bzoj2800
2015-06-05 23:17
316 查看
这题好难,翻了一下波兰文的题解……这好像是当年唯一没人A的题目
首先区间修改不难想到差分,我们令d1=x1,dn+1=-xn,di=xi-xi-1
注意Σdi=0,这样对于[l,r]的修改(比如+a) 就是d[l]+a d[r+1]-a
首先不难想到,对于每个di,ax+by=di一定要有解(gcd(a,b)|di)
这样我们知道这个方程的解为xi=x0+kb yi=y0-ka (x0,y0为这个方程一组解,可以由扩展欧几里德得到)
现在我们考虑最终的答案要求是Σxi=0 Σyi=0且(|Σxi|+|Σyi|)/2最小
我们有这样一个思路,先求出每个f(i)=|xi|+|yi|的最小值,最后总体贪心,调整成Σxi=0 Σyi=0
f(i)=|x0+kb|+|y0-ka|这显然是凸函数,我们可以用三分来解决
注意ax0+by0=di Σdi=0,所以我们只要Σki=0就满足Σxi=0 Σyi=0
设当前s=|Σki|,我们只要用堆调整s次即可得到满足条件的最优值
(关于s的规模不大会证,但跑得很快是了)
View Code
首先区间修改不难想到差分,我们令d1=x1,dn+1=-xn,di=xi-xi-1
注意Σdi=0,这样对于[l,r]的修改(比如+a) 就是d[l]+a d[r+1]-a
首先不难想到,对于每个di,ax+by=di一定要有解(gcd(a,b)|di)
这样我们知道这个方程的解为xi=x0+kb yi=y0-ka (x0,y0为这个方程一组解,可以由扩展欧几里德得到)
现在我们考虑最终的答案要求是Σxi=0 Σyi=0且(|Σxi|+|Σyi|)/2最小
我们有这样一个思路,先求出每个f(i)=|xi|+|yi|的最小值,最后总体贪心,调整成Σxi=0 Σyi=0
f(i)=|x0+kb|+|y0-ka|这显然是凸函数,我们可以用三分来解决
注意ax0+by0=di Σdi=0,所以我们只要Σki=0就满足Σxi=0 Σyi=0
设当前s=|Σki|,我们只要用堆调整s次即可得到满足条件的最优值
(关于s的规模不大会证,但跑得很快是了)
type node=record loc:longint; num:int64; end; var h:array[0..1000010] of node; x,y:array[0..1000010] of int64; d:array[0..1000010] of longint; g,i,j,a,b,n,x0,y0:longint; ans,l,m,r,s:int64; procedure swap(var a,b:int64); var c:int64; begin c:=a; a:=b; b:=c; end; function gcd(a,b:longint):longint; begin if b=0 then exit(a) else exit(gcd(b,a mod b)); end; function cal(x,y,k:int64):int64; begin exit(abs(x+k*int64(b))+abs(y-k*int64(a))); end; procedure exgcd(a,b:longint; var x,y:longint); var xx,yy:longint; begin if b=0 then begin x:=1; y:=0; end else begin exgcd(b,a mod b,x,y); xx:=x; yy:=y; x:=yy; y:=xx-a div b*yy; end; end; procedure sift(i:longint); var j:longint; x:node; begin j:=i shl 1; while j<=n do begin if (j<n) and (h[j].num>h[j+1].num) then inc(j); if h[i].num>h[j].num then begin x:=h[i]; h[i]:=h[j]; h[j]:=x; i:=j; j:=j shl 1; end else break; end; end; begin readln(n,a,b); g:=gcd(a,b); for i:=1 to n do begin read(d[i]); if d[i] mod g<>0 then begin writeln(-1); halt; end; d[i]:=d[i] div g; end; a:=a div g; b:=b div g; d[n+1]:=-d ; for i:=n downto 2 do d[i]:=d[i]-d[i-1]; inc(n); if a=b then begin for i:=1 to n do ans:=ans+abs(d[i]); writeln(ans div 2); halt; end; exgcd(a,b,x0,y0); for i:=1 to n do begin x[i]:=int64(x0)*int64(d[i]); y[i]:=int64(y0)*int64(d[i]); // writeln(x[i],' ',y[i],' ',d[i],':'); l:=-d[i]; r:=d[i]; if l>r then swap(l,r); while l+1<r do begin m:=(r-l+1) div 3; if cal(x[i],y[i],l+m)>cal(x[i],y[i],l+2*m) then l:=l+m+1 else r:=l+2*m-1; end; if cal(x[i],y[i],l)>cal(x[i],y[i],r) then begin x[i]:=x[i]+r*int64(b); y[i]:=y[i]-r*int64(a); s:=s+r; end else begin x[i]:=x[i]+l*int64(b); y[i]:=y[i]-l*int64(a); s:=s+l; end; // writeln(x[i],' ',y[i],' ',i,' ',d[i]); end; if s<0 then begin for i:=1 to n do swap(x[i],y[i]); g:=a; a:=b; b:=g; s:=abs(s); end; for i:=1 to n do begin h[i].loc:=i; h[i].num:=abs(x[i]-b)+abs(y[i]+a)-abs(x[i])-abs(y[i]); end; for i:=n div 2 downto 1 do sift(i); for i:=1 to s do begin j:=h[1].loc; x[j]:=x[j]-b; y[j]:=y[j]+a; h[1].num:=abs(x[j]-b)+abs(y[j]+a)-abs(x[j])-abs(y[j]); sift(1); end; for i:=1 to n do ans:=ans+abs(x[i])+abs(y[i]); writeln(ans div 2); end.
View Code
相关文章推荐
- 黑马程序员——Java基础---面向对象<二>
- 如何做好网站开发项目需求分析(转)
- OpenCSP开源程序解析之OPENCSP_Keyset.cpp
- Unable to load R3 module
- Java学习篇之---Collection接口
- Spinner的OnItemSelectedListener事件(在布局文件中通过Spinner的android:entries属性加载列表)
- [UnityShader]使用Unity Render Textures实现画面特效——建立画面特效脚本系统
- OpenCSP开源程序解析之OPENCSP_Key.cpp
- 支付宝SDK IOS
- SQL 性能调优日常积累
- Codeforecs 550D - Regular Bridge (构造)
- 黑马程序员——Java基础---面向对象<一>
- 三重门,论企业权力争夺战
- 用keytool工具生成签名文件与获取摘要信息
- Bash内置命令
- mysql 并行数据库与分区(Partition)
- Ubuntu14.04 Caffe安装
- Cut Ribbon
- 设计模式之六:原型模式(Prototype)
- 晚餐队列安排