bzoj2800

这题好难,翻了一下波兰文的题解……这好像是当年唯一没人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的规模不大会证,但跑得很快是了)

  1 type node=record
  2        loc:longint;
  3        num:int64;
  4      end;
  5 
  6 var h:array[0..1000010] of node;
  7     x,y:array[0..1000010] of int64;
  8     d:array[0..1000010] of longint;
  9     g,i,j,a,b,n,x0,y0:longint;
 10     ans,l,m,r,s:int64;
 11 
 12 procedure swap(var a,b:int64);
 13   var c:int64;
 14   begin
 15     c:=a;
 16     a:=b;
 17     b:=c;
 18   end;
 19 
 20 function gcd(a,b:longint):longint;
 21   begin
 22     if b=0 then exit(a)
 23     else exit(gcd(b,a mod b));
 24   end;
 25 
 26 function cal(x,y,k:int64):int64;
 27   begin
 28     exit(abs(x+k*int64(b))+abs(y-k*int64(a)));
 29   end;
 30 
 31 procedure exgcd(a,b:longint; var x,y:longint);
 32   var xx,yy:longint;
 33   begin
 34     if b=0 then
 35     begin
 36       x:=1;
 37       y:=0;
 38     end
 39     else begin
 40       exgcd(b,a mod b,x,y);
 41       xx:=x;
 42       yy:=y;
 43       x:=yy;
 44       y:=xx-a div b*yy;
 45     end;
 46   end;
 47 
 48 procedure sift(i:longint);
 49   var j:longint;
 50       x:node;
 51   begin
 52     j:=i shl 1;
 53     while j<=n do
 54     begin
 55       if (j<n) and (h[j].num>h[j+1].num) then inc(j);
 56       if h[i].num>h[j].num then
 57       begin
 58         x:=h[i]; h[i]:=h[j]; h[j]:=x;
 59         i:=j;
 60         j:=j shl 1;
 61       end
 62       else break;
 63     end;
 64   end;
 65 
 66 begin
 67   readln(n,a,b);
 68   g:=gcd(a,b);
 69   for i:=1 to n do
 70   begin
 71     read(d[i]);
 72     if d[i] mod g<>0 then
 73     begin
 74       writeln(-1);
 75       halt;
 76     end;
 77     d[i]:=d[i] div g;
 78   end;
 79   a:=a div g; b:=b div g;
 80   d[n+1]:=-d[n];
 81   for i:=n downto 2 do
 82     d[i]:=d[i]-d[i-1];
 83   inc(n);
 84   if a=b then
 85   begin
 86     for i:=1 to n do
 87       ans:=ans+abs(d[i]);
 88     writeln(ans div 2);
 89     halt;
 90   end;
 91   exgcd(a,b,x0,y0);
 92   for i:=1 to n do
 93   begin
 94     x[i]:=int64(x0)*int64(d[i]);
 95     y[i]:=int64(y0)*int64(d[i]);
 96   //  writeln(x[i],' ',y[i],' ',d[i],':');
 97     l:=-d[i];
 98     r:=d[i];
 99     if l>r then swap(l,r);
100     while l+1<r do
101     begin
102       m:=(r-l+1) div 3;
103       if cal(x[i],y[i],l+m)>cal(x[i],y[i],l+2*m) then l:=l+m+1
104       else r:=l+2*m-1;
105     end;
106     if cal(x[i],y[i],l)>cal(x[i],y[i],r) then
107     begin
108       x[i]:=x[i]+r*int64(b);
109       y[i]:=y[i]-r*int64(a);
110       s:=s+r;
111     end
112     else begin
113       x[i]:=x[i]+l*int64(b);
114       y[i]:=y[i]-l*int64(a);
115       s:=s+l;
116     end;
117   //  writeln(x[i],' ',y[i],' ',i,' ',d[i]);
118   end;
119   if s<0 then
120   begin
121     for i:=1 to n do
122       swap(x[i],y[i]);
123     g:=a; a:=b; b:=g;
124     s:=abs(s);
125   end;
126   for i:=1 to n do
127   begin
128     h[i].loc:=i;
129     h[i].num:=abs(x[i]-b)+abs(y[i]+a)-abs(x[i])-abs(y[i]);
130   end;
131   for i:=n div 2 downto 1 do
132     sift(i);
133 
134   for i:=1 to s do
135   begin
136     j:=h[1].loc;
137     x[j]:=x[j]-b;
138     y[j]:=y[j]+a;
139     h[1].num:=abs(x[j]-b)+abs(y[j]+a)-abs(x[j])-abs(y[j]);
140     sift(1);
141   end;
142   for i:=1 to n do
143     ans:=ans+abs(x[i])+abs(y[i]);
144   writeln(ans div 2);
145 end.
View Code
原文地址:https://www.cnblogs.com/phile/p/4555777.html