bzoj4827: [Hnoi2017]礼物
这个m的范围很有欺骗性啊。。。以为是要枚举C的
不管C的话其实就是要一个min{sigema (Y(i)-X(i+k))^2 }
把Y翻转过来,这样旋转k步的圈就是第n+k位
把它拆开的话其实只要算一个X*Y,就是fft的事儿了
再看看C怎么处理,我们带着C拆开,那么会多一个这个东西:sigema (x+C-y)*C == (sumx-sumy+C)*C
C取(sumx-sumy)/n就可以了,保险起见多算几次。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL sqr(LL x){return x*x;} const double pi=acos(-1.0); struct complex { double r,i; complex(){} complex(double R,double I){r=R,i=I;} friend complex operator +(complex x,complex y){return complex(x.r+y.r,x.i+y.i);} friend complex operator -(complex x,complex y){return complex(x.r-y.r,x.i-y.i);} friend complex operator *(complex x,complex y){return complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);} }A[410000],B[410000],C[410000]; int Re[410000]; void fft(complex *a,int n,int op) { for(int i=0;i<n;i++) if(i<Re[i])swap(a[i],a[Re[i]]); for(int i=1;i<n;i<<=1) { complex wn(cos(pi/i),sin(op*pi/i)); for(int j=0;j<n;j+=(i<<1)) { complex w(1,0); for(int k=0;k<i;k++,w=w*wn) { complex t1=a[j+k],t2=a[j+k+i]*w; a[j+k]=t1+t2;a[j+k+i]=t1-t2; } } } } int len,n,aa[51000],bb[51000]; LL solve(int CC) { memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); LL sum=0; for(int i=0;i<len;i++) { A[i].r=A[len+i].r=aa[i]+CC, B[i].r=bb[len-1-i]; sum+=sqr(aa[i]+CC)+sqr(bb[len-1-i]); } fft(A,n,1),fft(B,n,1); for(int i=0;i<n;i++)C[i]=A[i]*B[i]; fft(C,n,-1); LL ret=(1LL<<62); for(int i=len-1;i<=2*(len-1);i++) ret=min(ret,sum-2*LL(C[i].r/n+0.5)); return ret; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int M; LL sum=0; scanf("%d%d",&len,&M); for(int i=0;i<len;i++)scanf("%d",&aa[i]),sum+=aa[i]; for(int i=0;i<len;i++)scanf("%d",&bb[i]),sum-=bb[i]; sum/=len; int m=len*3,L=0; for(n=1;n<=m;n*=2)L++; for(int i=1;i<=n;i++)Re[i]=(Re[i>>1]>>1)|((i&1)<<(L-1)); LL mmin=(1LL<<62); for(int C=sum-1;C<=sum+1;C++) mmin=min(mmin,solve(C)); printf("%lld\n",mmin); return 0; }
pain and happy in the cruel world.