【GDSOI2017第三轮模拟】Gift

来源:互联网 发布:黄帝大战蚩尤电影知乎 编辑:程序博客网 时间:2024/05/17 09:12

Description

这里写图片描述
n<=50000

Solution

刚刚考完体育中考,整个人都颓废了_ (:з」∠) _
于是决定写一个FFT冷静一下~
我们可以强制把加的数都放到y上面,这样c的非负整数限制也没有了。
那么我们把式子化一下:

i=1n(xi(yi+c))2=i=1nx2i+i=1n(yi+c)22i=1nxi(yi+c)

=i=1nx2i+i=1ny2i+nc2+2ci=1n(yixi)2i=1nxiyi

发现前两项为定值,扔掉。
把和c有关的项提出来,发现是一个形如ac^2+bc的二次函数,要求最小值。
这样就可以把c求出来了,也就是我们只需要求旋转过后的ni=1xiyi的最大值。
考虑FFT,把y翻转,那么就是形如ni=1xiyni+1,也就是卷积的形式。
将x串倍长,那么对于每一个x串的结尾,往前长度为n的串和y串的卷积就是这一段串的答案。
于是直接上FFT,最后对每个答案求个最大值就好了。
听说循环卷积跑得快?我不会啊QwQ

Code

#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define pi acos(-1)using namespace std;typedef double db;const int N=4*1e5+5;struct complex{    db r,i;    complex(db _r=0,db _i=0) {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[N],B[N],C[N],t[N];int n,m,ans,sumx,sumy,len,lg;db x[N],y[N],z[N];void DFT(complex *a,int flag) {    for(int i=0;i<len;i++) {        int p=0;        for(int j=i,k=0;k<lg;k++,j/=2) p=p*2+(j&1);        t[p]=a[i];    }    for(int m=2;m<=len;m*=2) {        int half=m/2;        for(int i=0;i<half;i++) {            complex w=complex(cos(i*flag*pi/half),sin(i*flag*pi/half));            for(int j=i;j<len;j+=m) {                complex u=t[j],v=t[j+half]*w;                t[j]=u+v;t[j+half]=u-v;            }        }    }    for(int i=0;i<len;i++) a[i]=t[i];    if (flag==-1) for(int i=0;i<len;i++) a[i].r/=len;}void FFT(db *a,db *b,db *c) {    for(int i=0;i<len;i++) {        A[i]=complex(a[i],0);        B[i]=complex(b[i],0);    }    DFT(A,1);DFT(B,1);    for(int i=0;i<len;i++) C[i]=A[i]*B[i];    DFT(C,-1);    for(int i=0;i<len;i++) c[i]=C[i].r;}int main() {    freopen("gift.in","r",stdin);    freopen("gift.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,0,n-1) scanf("%lf",&x[i]),sumx+=x[i],ans+=x[i]*x[i];    fo(i,0,n-1) scanf("%lf",&y[i]),sumy+=y[i],ans+=y[i]*y[i];    db a=n,b=2*(sumy-sumx);    db c=-b/2.0/a;    int c1=floor(c),c2=ceil(c);    if (c-c1<c2-c) c=c1;else c=c2;    ans+=a*c*c+b*c;    fo(i,n,2*n-1) x[i]=x[i-n];    fo(i,1,n/2) swap(y[i-1],y[n-i]);    int nn=n,sum=0;n*=2;    for(len=1;len<2*n;len*=2) lg++;    FFT(x,y,z);    fo(i,nn,n-1) sum=max(sum,(int)z[i]);    printf("%d\n",ans-2*sum);}
0 0