hihocoder 1388 Periodic Signal

来源:互联网 发布:java什么是构造方法 编辑:程序博客网 时间:2024/05/04 13:56

ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛 1006 Periodic Signal

传送门

题目大意

给你两个序列,求一个差值平方和最小具体求法就是min{(a1-b1)²+...+(an-bn)²,(a1-b2)²+...+(an-b1)²,...,(a1-bn)²+...+(an-b1)²}

知道题意后化简的
ni=1a2i+ni=1b2i2(aibj)(iϵn,jϵn)
现在问题就变成了怎么快速求出aibj 的最大值
普通方法的时间复杂度O(n2),肯定要超时。
考虑下面的循环矩阵

a1anan1.a2a2a1an.a3a3a2a1.a4...............anan1an2.a1b1b2b3.bn=c1c2c3.cn

只需要求cn 的最大值即可。
可以参考下面一个链接
http://www.zybang.com/question/dd8b336ad690b3e2f9aa4dc0b596e1ea.html
将循环矩阵*向量转换为求卷积
所以用快速傅里叶变换将时间复杂度降为了O(nlog2n)
具体做法是
a=(a1,a2...,an)
b=(bn,bn1,...b2,b1,bn,bn1...b2)
之后对ac=DFT(a)
bd= DFT(b)
时间复杂度为O(nlog2n)
然后求S=cd
时间复杂度为O(n)
再对Sans=IDFT(S)
时间复杂度为O(nlog2n)
最后求ans 中最大的元素即可
不过这道题的坑点在于精度问题
WA了若干次
发现精度怎么都够不了
于是发现在ans 中答案的位置就是移动的位置
于是先求出移动的位置
然后暴力跑一边就求出答案了
代码如下(缩进懒得改了套的模板,将就看)

#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define N 150005#define pi acos(-1.0)using namespace std;int l,T,n,num,wz;long long ans,tot,sum[N],A[N],B[N];struct complex{      double r,i;      complex(double real=0.0,double image=0.0){r=real;i=image;}    complex operator + (const complex o)    {        return complex(r+o.r,i+o.i);    }    complex operator - (const complex o)    {        return complex(r-o.r,i-o.i);    }    complex operator * (const complex o)    {        return complex(r*o.r-i*o.i,r*o.i+i*o.r);    }  }x1[N],x2[N];void brc(complex *y,int l){      register int i,j,k;    for(i=1,j=l/2;i<l-1;i++)      {        if(i<j)swap(y[i],y[j]);        k=l/2;        while(j>=k)j-=k,k/=2;        if(j<k)j+=k;    }}void fft(complex *y,int l,double on){    register int h,i,j,k;    complex u,t;    brc(y,l);    for(h=2;h<=l;h<<=1)    {          complex wn(cos(on*2*pi/h),sin(on*2*pi/h));        for(j=0;j<l;j+=h)        {            complex w(1,0);            for(k=j;k<j+h/2;k++)            {                u=y[k];                t=w*y[k+h/2];                y[k]=u+t;                y[k+h/2]=u-t;                w=w*wn;            }        }    }    if(on==-1)for(i=0;i<l;i++)y[i].r/=l;}long long Getans(int k){    ans=0;    for(int i=0;i<n;i++)ans+=(A[i]-B[(i+k)%n])*(A[i]-B[(i+k)%n]);    return ans;}int main()  {    register int i,j;    scanf("%d",&T);    while(T--)    {        l=1;        tot=0;        scanf("%d",&n);        while(l<n*2)l<<=1;        for(i=n-1;i>=0;i--)        {            scanf("%d",&num);            x1[i].r=num;            x1[i].i=0.0;            tot+=num*num;            A[n-i-1]=num;        }        for(i=n;i<2*n-1;i++)x1[i]=x1[i-n];        for(i=2*n-1;i<l;i++)x1[i].r=x1[i].i=0.0;        for(i=0;i<n;i++)        {            scanf("%d",&num);            x2[i].r=num;            x2[i].i=0.0;            tot+=num*num;            B[i]=num;        }        for(i=n;i<l;i++)x2[i].r=x2[i].i=0.0;          fft(x1,l,1);//DFT        fft(x2,l,1);//DFT        for(i=0;i<l;i++)x1[i]=x1[i]*x2[i];        fft(x1,l,-1);//IDFT        double m=-1;        for(i=n-1;i<2*n;i++)if(m<x1[i].r)m=x1[i].r,wz=i;//求位置        printf("%lld\n",Getans((wz+1)%n));    }    return 0;}
0 0
原创粉丝点击