Hihocoder1388 2016年北京网络赛 FFT

Posted legend_PawN

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hihocoder1388 2016年北京网络赛 FFT相关的知识,希望对你有一定的参考价值。

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

i=0n1Ai+B(i+k)modn2=i=0n1A2i+i=0n1B2(i+k)modn2i=0n1AiB(i+k)modn
问题转化成求 n1i=0AiB(i+k)modn 的最大值
很明显这是一个循环卷积求和的问题,利用FFT可以确定最大值 k <script type="math/tex" id="MathJax-Element-312">k</script>,之后我们再重新带入原始进行计算即可。
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;

以上是关于Hihocoder1388 2016年北京网络赛 FFT的主要内容,如果未能解决你的问题,请参考以下文章

(每日一题)2016 北京ICPC网络赛G hihocoder 1388 (中国剩余定理 + NTT)

hihoCoder1388 Periodic Signal(2016北京网赛F:NTT)

hihocoder#1384/北京网络赛2016 Genius ACM 归并排序+倍增

hihoCoder 1389 Sewage Treatment 二分+网络流+优化 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)

hihoCoder 1392 War Chess 模拟 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)

hihoCoder 1391 Countries 预处理+排序+堆 (ACM-ICPC国际大学生程序设计竞赛北京赛区(2016)网络赛)