快速傅立叶之二

一、题目

Description
请计算C[k]=sigma(a[i]*b[i-k]) 其中 k < = i < n ,并且有 n < = 10 ^ 5。 a,b中的元素均为小于等于100的非负整数。
Input
第一行一个整数N,接下来N行,第i+2…i+N-1行,每行两个数,依次表示a[i],b[i] (0 < = i < N)。
Output
输出N行,每行一个整数,第i行输出C[i-1]。

二、解法

可以把原式变化成卷积的形式,我们翻转 b b b数组,得到 d [ n − i + k − 1 ] = b [ i − k ] d[n-i+k-1]=b[i-k] d[ni+k1]=b[ik],这样就可以把 a , d a,d a,d数组理解为多项式,它们相乘的次数是固定的也就是 n + k − 1 n+k-1 n+k1,我们输出是就从 n − 1 n-1 n1,输出到 2 n − 2 2n-2 2n2就行了。

#include <cstdio>
#include <cmath>
const int MAXN = 300005;
const double pi = acos(-1.0);
int read()
{
    int num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
    return num*flag;
}
int n,len;
struct complex
{
	double x,y;
	complex() {}
	complex(double X,double Y) : x(X) , y(Y) {}
	complex operator + (const complex &R) const {return complex(x+R.x,y+R.y);}
	complex operator - (const complex &R) const {return complex(x-R.x,y-R.y);}
	complex operator * (const complex &R) const {return complex(x*R.x-y*R.y,x*R.y+y*R.x);} 
}a[MAXN],b[MAXN];
void FFT(int len,complex *a,int flg)
{
	if(len==1) return ;
	complex a1[len>>1],a2[len>>1];
	for(int i=0;i<len;i+=2) a1[i>>1]=a[i],a2[i>>1]=a[i+1];
	FFT(len>>1,a1,flg);FFT(len>>1,a2,flg);
	const complex w=complex(cos(pi*2.0/len),sin(pi*2.0/len)*flg);
	complex k=complex(1,0);len>>=1;
	for(int i=0;i<len;i++,k=k*w)
	{
		a[i]=a1[i]+k*a2[i];
		a[i+len]=a1[i]-k*a2[i];
	}
}
int main()
{
	n=read();
	for(int i=0;i<n;i++) a[i].x=read(),b[n-i-1].x=read();
	len=1;while(len<=2*n) len<<=1;
	FFT(len,a,1);FFT(len,b,1);
	for(int i=0;i<=len;i++) a[i]=a[i]*b[i];
	FFT(len,a,-1);
	for(int i=n-1;i<2*n-1;i++)
		printf("%d\n",(int)(a[i].x/len+0.5));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值