1、hihocoder1388(2016 acm 北京网络赛e题)
给出等长的A,B序列,求
input:
2
9
3 0 1 4 1 5 9 2 6
5 3 5 8 9 7 9 3 2
5
1 2 3 4 5
2 3 4 5 1
output:
80
0
解题思路:这题其实也是2个一维卷积的应用。公式可以化简为
此时我们可以把一个串变长一倍,再用另一个串反转求他们的卷积,如
1 2 3 4 5 1 2 3 4 5与2 3 4 5 1的卷积,然后就能看出有一串连续位置的fft值即为结果,求出其中最小值即可,又因为fft的精度问题,直接fft很可能WA,所以需要在
- for(int i = 0;i < len;i++)
- sum[i]= (int)(x1[i].r+0.5);
这种地方直接比较x1[i].r的大小,然后得出什么位置最小,重新按数组计算即可。
代码:
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- #include <algorithm>
- #include <cmath>
- using namespace std;
- typedef long long ll;
- const double PI = acos(-1.0);
- //复数结构体
- 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);
- }
- };
- /*
- * 进行FFT和IFFT前的反转变换。
- * 位置i和 (i二进制反转后位置)互换
- * len必须去2的幂
- */
- void change(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]);
- //交换互为小标反转的元素,i<j保证交换一次
- //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
- k = len/2;
- while( j >= k)
- {
- j -= k;
- k /= 2;
- }
- if(j < k) j += k;
- }
- }
- /*
- * 做FFT
- * len必须为2^k形式,
- * on==1时是DFT,on==-1时是IDFT
- */
- void fft(complex y[],int len,int on)
- {
- change(y,len);
- for(int h = 2; h <= len; 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;
- }
- const int maxn = 400010;
- complex x1[maxn],x2[maxn];
- ll a[maxn],b[maxn],num[maxn],sum;
- int main()
- {
- int T,i,j,len,n,len1,len2;
- scanf("%d",&T);
- while (T--)
- {
- scanf("%d",&n);
- sum=0;
- len1=2*n;
- len2=n;
- for (i=0;i<n;i++)
- {
- scanf("%lld",&a[n-i-1]);
- a[2*n-i-1]=a[n-i-1];
- sum+=a[n-i-1]*a[n-i-1];
- }
- for (i=0;i<n;i++)
- {
- scanf("%lld",&b[n-i-1]);
- sum+=b[n-i-1]*b[n-i-1];
- }
- len=1;
- while (len<len1*2) len<<=1;
- for (i=0;i<len1;i++)
- {
- x1[i]=complex(a[i],0);
- }
- for (i=len1;i<len;i++)
- {
- x1[i]=complex(0,0);
- }
- for (i=0;i<len2;i++)
- {
- x2[i]=complex(b[len2-i-1],0);
- }
- for (i=len2;i<len;i++)
- {
- x2[i]=complex(0,0);
- }
- fft(x1,len,1);
- fft(x2,len,1);
- for(int i = 0;i < len;i++)
- x1[i] = x1[i]*x2[i];
- fft(x1,len,-1);
- ll ans=0;
- double temp=-1;
- int pos;
- for(i = n-1;i < 2*n;i++)
- {
- if (temp<x1[i].r)
- {
- temp=x1[i].r;
- pos=i;
- }
- }
- int t=0;
- for (i=pos;i>pos-n;i--)
- {
- ans+=a[i]*b[--len2];
- }
- printf("%lld\n",sum-2*ans);
- }
- return 0;
- }