这是一道模板题。
给你两个多项式,请输出乘起来后的多项式。
输入格式
第一行两个整数 nn 和 mm,分别表示两个多项式的次数。
第二行 n+1n+1 个整数,分别表示第一个多项式的 00 到 nn 次项前的系数。
第三行 m+1m+1 个整数,分别表示第一个多项式的 00 到 mm 次项前的系数。
输出格式
一行 n+m+1n+m+1 个整数,分别表示乘起来后的多项式的 00 到 n+mn+m 次项前的系数。
样例一
input
1 2
1 2
1 2 1
output
1 4 5 2
explanation
(1+2x)⋅(1+2x+x2)=1+4x+5x2+2x3(1+2x)⋅(1+2x+x2)=1+4x+5x2+2x3
限制与约定
0≤n,m≤1050≤n,m≤105,保证输入中的系数大于等于 00 且小于等于 99。
时间限制:1s
空间限制:256MB
分析:
如题所言,确实是一道FFT模板题,
寻求曲神帮助
虽然曲神神的有点不可思议,但人还是很亲切的
第一次写,代码极为丑陋
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
const int N=301000; //数组大小避免开成2的次方
const double pi=acos(-1.0);
struct node{
double a,b;
node (double aa=0,double bb=0)
{
a=aa;b=bb;
}
};
node a[N],b[N],omega[N],a_omega[N];
int n,m,k,l;
node operator +(const node &x,const node &y){return node(x.a+y.a,x.b+y.b);}
node operator -(const node &x,const node &y){return node(x.a-y.a,x.b-y.b);}
node operator *(const node &x,const node &y){return node(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);}
node operator *(const node &x,const double &y){return node(x.a*y,x.b*y);}
void init(int n)
{
for (int i=0;i<n;i++)
{
omega[i]=node(cos(2.0*pi*i/n),sin(2.0*pi*i/n));
a_omega[i]=node(cos(2.0*pi*i/n),-sin(2.0*pi*i/n));
}
}
void FFT(int n,node *a,node *w)
{
int i,j=0,k;
for (i=0;i<n;i++) //很显然这就是优美的rev操作
{
if (i>j) swap(a[i],a[j]);
for (int l=n>>1;(j^=l)<l;l>>=1);
}
for (int i=2;i<=n;i<<=1) //合并
{
int m=i>>1; //一半区间的长度
for (int j=0;j<n;j+=i)
for (k=0;k<m;k++)
{
node z=a[j+m+k]*w[n/i*k];
a[j+m+k]=a[j+k]-z;
a[j+k]=a[j+k]+z;
}
}
}
int main()
{
int fn;
scanf("%d%d",&n,&m);
for (int i=0;i<=n;i++) scanf("%lf",&a[i].a);
for (int i=0;i<=m;i++) scanf("%lf",&b[i].a);
fn=1;
while (fn<=n+m) fn<<=1; //找到大于n+m的最小2次幂
init(fn);
FFT(fn,a,omega);
FFT(fn,b,omega);
for (int i=0;i<=fn;i++)
a[i]=a[i]*b[i];
FFT(fn,a,a_omega);
for (int i=0;i<=n+m;i++) printf("%d ",(int)(a[i].a/fn+0.5)); //四舍五入
}