LUOGU P3723 [AH2017/HNOI2017]禮物 (fft)
阿新 • • 發佈:2018-11-24
解題思路
首先我們設變化量為\(r\),那麼最終的答案就可以寫成 :
\[ ans=min(\sum\limits_{i=1}^n(a_i-b_i+r)^2) \]
\[ ans=min(\sum\limits_{i=1}^n(a_i-b_i)^2-2*r*\sum\limits_{i=1}^{n}(a_i-b_i)+n*r^2) \]
繼續化簡:
\[ ans=min(\sum\limits_{i=1}^n a_i^2+\sum\limits_{i=1}^n b_i^2-2*\sum\limits_{i=1}^na_i*b_i-2*r*\sum\limits_{i=1}^{n}(a_i-b_i)+n*r^2) \]
\[ ans=min((\sum\limits_{i=1}^n a_i^2+\sum\limits_{i=1}^n b_i^2)-(2*r*\sum\limits_{i=1}^{n}(a_i-b_i)+n*r^2)-(2*\sum\limits_{i=1}^na_i*b_i)) \]
這樣我們就可以發現,第一部分是一個定值,第二部分只需要從\(-m\)到\(m\)列舉一下\(r\)就能算出,現在問題就是算第三部分。發現第三部分形式特別像卷積,就直接將\(a\)陣列翻一下倍,表示旋轉,\(b\)數字翻轉一下。然後\(fft\)後算一個最大值即可。
程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int MAXN = 50005<<3; const double Pi=acos(-1); typedef long long LL; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,m,limit=1,rev[MAXN]; LL ans,sqA,sqB,A,B,Sum=1e18; struct Complex{ double x,y; Complex(double xx=0,double yy=0) {x=xx;y=yy;} }a[MAXN],b[MAXN]; Complex operator +(const Complex A,const Complex B) {return Complex(A.x+B.x,A.y+B.y);} Complex operator -(const Complex A,const Complex B) {return Complex(A.x-B.x,A.y-B.y);} Complex operator *(const Complex A,const Complex B) {return Complex(A.x*B.x-A.y*B.y,A.x*B.y+A.y*B.x);} inline void fft(Complex *f,int type){ for(int i=0;i<limit;i++) if(i<rev[i]) swap(f[i],f[rev[i]]); int len;Complex Wn,w,tmp; for(int p=2;p<=limit;p<<=1){ len=p>>1;Wn=Complex(cos(Pi/len),type*sin(Pi/len)); for(int k=0;k<limit;k+=p){ w=Complex(1,0); for(int l=k;l<k+len;l++){ tmp=f[l+len]*w; f[l+len]=f[l]-tmp;f[l]=f[l]+tmp; w=w*Wn; } } } } int main(){ n=rd(),m=rd();int x; for(int i=1;i<=n;i++) { x=rd();sqA+=x*x;A+=x;a[i].x=(double)x; } for(int i=1;i<=n;i++) { x=rd();sqB+=x*x;B+=x;b[n-i+1].x=(double)x; } for(int i=1;i<=n;i++) a[i+n].x=a[i].x; while(limit<=3*n) limit<<=1; for(int i=0;i<limit;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?limit>>1:0); fft(a,1);fft(b,1);for(int i=0;i<limit;i++) a[i]=a[i]*b[i];fft(a,-1); for(int i=n+1;i<=n*2;i++) ans=max(ans,(LL)(a[i].x/limit+0.5)); ans<<=1;ans=-ans; for(int i=-m;i<=m;i++) Sum=min(Sum,(LL)(A-B)*2*i+(LL)n*i*i); ans+=Sum+sqA+sqB;cout<<ans<<endl; return 0; }