1. 程式人生 > >bzoj4827 [hnoi2017]禮物

bzoj4827 [hnoi2017]禮物

CA close 整數 its pla AI clas swa sum

題意:給你兩串珠子,求將其中一串珠子進行加一個整數c和旋轉操作後,最小的$\sum_{i=1}^{n}(x[i]-y[i+k]+c)^2$。

標程:

技術分享圖片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int mod=998244353;
 5 const int rt=31;
 6 const int N=500006;
 7 int l,_n,w[N],pos[N],n,k,wn,inv_n;
 8 ll sum1,sum2,ans,a[N],b[N];
 9 void
up(int &x,int y) {x=((ll)x+y)%mod;} 10 int ksm(int x,int y) 11 { 12 int res=1; 13 while (y) {if (y&1) res=(ll)res*x%mod; x=(ll)x*x%mod; y>>=1;} 14 return res; 15 } 16 void init(int n) 17 { 18 l=0; 19 while ((1<<l)<=n) l++; 20 _n=1<<l;wn=ksm(rt,1<<23
-l); 21 w[0]=1;inv_n=ksm(_n,mod-2); 22 for (int i=1;i<_n;i++) 23 w[i]=(ll)w[i-1]*wn%mod,pos[i]=(i&1)?pos[i-1]|(1<<(l-1)):pos[i>>1]>>1; 24 } 25 void fft(ll *a,int op) 26 { 27 for (int i=0;i<_n;i++) if (i<pos[i]) swap(a[i],a[pos[i]]); 28 int len=1,id=_n;
29 for (int i=0;i<l;i++) 30 { 31 int wn=w[id>>=1]; 32 for (int j=0;j<_n;j+=len*2) 33 for (int k=j,w=1;k<j+len;k++) 34 { 35 int l=a[k],r=(ll)a[k+len]*w%mod; 36 a[k]=((ll)l+r)%mod;a[k+len]=((ll)l-r+mod)%mod; 37 w=(ll)w*wn%mod; 38 } 39 len<<=1; 40 } 41 if (op==-1) { 42 reverse(a+1,a+_n); 43 for (int i=0;i<_n;i++) a[i]=(ll)a[i]*inv_n%mod; 44 } 45 } 46 47 int main() 48 { 49 scanf("%d%d",&n,&k);init(2*n+1); 50 for (int i=1;i<=n;i++) scanf("%lld",&a[i]),sum1+=a[i]*a[i],sum2+=a[i]; 51 for (int i=1;i<=n;i++) scanf("%lld",&b[n-i+1]),sum1+=b[n-i+1]*b[n-i+1],sum2-=b[n-i+1]; 52 fft(a,1);fft(b,1); 53 for (int i=0;i<_n;i++) a[i]=(ll)a[i]*b[i]%mod; 54 fft(a,-1); 55 for (int i=2;i<=n+1;i++) ans=max(ans,(ll)a[i]+a[n+i]);//取max的時候別取模 56 double c=round((double)-sum2/n);//註意要加double! 57 ll cc=c; 58 ans=(ll)cc*cc*n+2*sum2*cc+sum1-2*ans; 59 printf("%lld\n",ans); 60 return 0; 61 }
View Code

題解:fft

平方展開原式:

$\sum_{i=1}^{n}(x[i]-y[i+k]+c)^2$

$=n*c^2+2*(sumx-sumy)*c+sum^2(x)+sum^2(y)-2*max(x[i]*y[i+k])$

c可以直接求得,取對稱軸值c=(sumy-sumx)/n。求max(x[i]*y[i+k])直接多項式平移+fft。

bzoj4827 [hnoi2017]禮物