Hihocoder1388 2016年北京网络赛 FFT

来源:互联网 发布:手机怎么成为网络歌手 编辑:程序博客网 时间:2024/06/11 18:56

题目链接
题目不难看懂,首先把公式变形:

i=0n1Ai+B(i+k)modn2=i=0n1A2i+i=0n1B2(i+k)modn2i=0n1AiB(i+k)modn

问题转化成求n1i=0AiB(i+k)modn的最大值
很明显这是一个循环卷积求和的问题,利用FFT可以确定最大值k,之后我们再重新带入原始进行计算即可。
WA点1.不能利用FFT直接求结果,有较大的精度误差,只能用其判断k的值
WA点2.一定要熟悉convert的过程,跑FFT把两个卷积的数组构造好,并且知道我们需要那一部分的卷积结果

AC代码:FFT用bin神的模版:

最后,网络赛时候我们是暴力+XJBG做出来的,丑陋

#include <bits/stdc++.h>const int maxn=200000+10;const double PI=acos(-1);typedef long long ll;using namespace std;int n,str1[maxn],str2[maxn],len;struct Complex{    double r,i;    Complex(double _r = 0.0,double _i = 0.0){        r = _r; i = _i;    }    Complex operator +(const Complex &b){        return Complex(r+b.r,i+b.i);    }    Complex operator -(const Complex &b){        return Complex(r-b.r,i-b.i);    }    Complex operator *(const Complex &b){        return Complex(r*b.r-i*b.i,r*b.i+i*b.r);    }};void rader(Complex y[],int len){    int i,j,k;    for(i=1,j=len/2;i<len-1;i++){        if(i<j)            swap(y[i],y[j]);        k=len/2;        while(j>=k){            j-=k;            k/=2;        }        if(j<k)            j+=k;    }}void fft(Complex y[],int len,int on){    rader(y,len);    for(int h=2; h<=len;h=h<<1){        Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));        for(int j=0;j<len;j+=h){            Complex w(1,0);            for(int k = j;k<j+h/2;k++){                Complex u = y[k];                Complex t = w*y[k+h/2];                y[k]=u+t;                y[k+h/2]=u-t;                w=w*wn;            }        }    }    if(on==-1)        for(int i=0;i<len;i++)            y[i].r/=len;}void convert(Complex a[],Complex b[],int len){    fft(a,len,1);  //DFT    fft(b,len,1);    for(int i=0;i<len;i++)    //时域卷积=频域相乘        a[i]=a[i]*b[i];    fft(a,len,-1);//IDFT}Complex x1[maxn],x2[maxn];void init(){    len=1;    while(len<n*2)        len=len<<1;    for(int i=0;i<n;i++)        x1[i]=Complex(str1[n-i-1],0);  //注意此处取反,理解convert的性质    for(int i=n;i<len;i++)        x1[i]=Complex(0,0);    for(int i=0;i<n;i++)        x2[i]=Complex(str2[i],0);    for(int i=n;i<2*n;i++)        x2[i]=Complex(str2[i-n],0);    for(int i=2*n;i<len;i++)        x2[i]=Complex(0,0);}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        for(int i=0;i<n;i++)            scanf("%d",&str1[i]);        for(int i=0;i<n;i++)            scanf("%d",&str2[i]);        init();        convert(x1,x2,len);        ll max=-1,k=0;        for(int i=0;i<len;i++){            if(max<x1[i].r){                max=x1[i].r;                k=i-n+1;            }        }        ll ans=0;        for(int i=0;i<n;i++)            ans+=1ll*(str1[i]-str2[(i+k)%n])*(str1[i]-str2[(i+k)%n]);        printf("%lld\n",ans);    }    return 0;}
0 0
原创粉丝点击