【[AH2017/HNOI2017]礼物】一道FFT题
最近学了FFT,真是恶心 开心极了
我们假设增加的亮度为r,那么
ANS == segma ( xi - yi + r )^2 == segma( xi ^2 + yi^2 + r^2 ) + 2 * r * segma( xi - yi ) - 2 * segma( xi*yi )
我们可以发现xi*yi可以用FFT来处理,而M的范围很小可以直接枚举r来搞定其他,r可以用二次函数最值处理(比较懒,直接暴力枚举)
发现除了xiyi并不会因为旋转而影响,用fft搞xiyi。xiyi处理方法---》将b翻转,之后每个匹配位置的和,一一匹配xiyi就为a,b相乘之后所得的c,c的c[i]+c[i+n],可以在纸上稍推一下就可以发现这是系数的匹配。
于是就这么搞出来啦!
code:
/* ans=segma( xi - yi + r )^2 ==segma(x^2+y^2+r^2) + 2*r*segma(xi-yi) - 2*segma(xi*yi) */ #include<complex> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int maxn = 200000; const double pi = 3.1415926535; typedef complex<double> cd; char s1[maxn],s2[maxn]; cd aa[maxn],bb[maxn]; int out[maxn],rev[maxn]; void getrev(int n) { for(int i=0,j=0;i<n;i++) { rev[i]=j; for(int k=n>>1;(j^=k)<k;k>>=1); } } void fft(cd *a,int n,int dft) { for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]); for(int st=1;st<n;st<<=1) { cd dwfg=exp(cd(0,dft*pi/st)); for(int i=0;i<n;i+=(st<<1)) { cd nfg=1; for(int j=i;j<i+st;j++) { cd x=a[j],y=a[j+st]*nfg; nfg*=dwfg; a[j]=x+y; a[j+st]=x-y; } } } if(dft==-1) for(int i=0;i<n;i++) a[i]/=n; } int n,m; int ans=0x3f3f3f3f; int ma,sum1,sum2; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lf",&aa[i].real()); for(int i=1;i<=n;i++) scanf("%lf",&bb[i].real() ); for(int i=1;i<=n;i++) { sum1+=aa[i].real()*aa[i].real()+bb[i].real()*bb[i].real(); sum2+=aa[i].real()-bb[i].real(); } int s; reverse(bb+1,bb+1+n); for(s=2;s<=2*n;s<<=1); getrev(s); fft(aa,s,1); fft(bb,s,1); for(int i=0;i<s;i++) aa[i]*=bb[i]; fft(aa,s,-1); for(int i=0;i<s;i++) out[i]=(int)(aa[i].real() +0.5); for(int i=0;i<=n;i++) ma=max(out[i]+out[i+n],ma); for(int r=-m;r<=m;r++) { ans=min(ans,-ma*2+sum1+n*r*r+2*r*sum2); } printf("%d",ans); }