HDU - 1402,A * B Problem Plus
https://vjudge.net/problem/HDU-1402/origin
Calculate A * B.
思路:FFT板题,贴个常数很小的板子
#include<bits/stdc++.h>
#define ll long long
#define ri register int
#define MAXN 50005
using namespace std;
const double pi=acos(-1.0);
struct cpx
{
double r, i;
inline void operator +=(const cpx &b){ r+=b.r, i+=b.i;}
inline cpx operator +(const cpx &b)const{ return (cpx){r+b.r, i+b.i};}
inline cpx operator -(const cpx &b)const{ return (cpx){r-b.r, i-b.i};}
inline cpx operator *(const cpx &b)const{ return (cpx){r*b.r-i*b.i, r*b.i+i*b.r};}
inline cpx operator *(const double b)const{ return (cpx){r*b, i*b};}
inline cpx operator ~()const{return (cpx){r, -i};}
}a[MAXN<<2], b[MAXN<<2], w[MAXN<<2];
inline void DFT_(cpx *f, int n)
{
for(ri i=0, j=0; i<n; ++i)
{
if(i>j) swap(f[i], f[j]);
for(ri k=n>>1; (j^=k)<k; k>>=1);
}
for(ri i=1; i<n; i<<=1) for(ri j=0; j<n; j+=i<<1)
for(ri k=j; k<j+i; ++k)
{
cpx t=w[i+k-j]*f[k+i];
f[k+i]=f[k]-t, f[k]+=t;
}
}
inline void DFT(cpx *f, int n)
{
if(n==1) return;
n>>=1;
static cpx a[MAXN<<1];
for(ri i=0; i<n; ++i) a[i]=(cpx){f[i<<1].r, f[i<<1|1].r};
DFT_(a, n);
for(ri i=0; i<n; ++i)
{
cpx q=~a[(n-i)&(n-1)], x=(a[i]+q)*0.5, y=(a[i]-q)*(cpx){0, -0.5}, t=y*w[n+i];
f[i]=x+t, f[n+i]=x-t;
}
}
inline void IDFT(cpx *f, int n)
{
if(n==1) return;
reverse(f+1, f+n), n>>=1;
static cpx a[MAXN<<1];
for(ri i=0; i<n; ++i)
a[i]=(f[i]+f[i+n])*0.5 + (f[i]-f[i+n])*(cpx){0, 0.5}*w[n+i];
DFT_(a, n);
double k=1.0/n;
for(ri i=0; i<n; ++i) f[i<<1]=(cpx){a[i].r*k, 0}, f[i<<1|1]=(cpx){a[i].i*k, 0};
}
void transfer(int a[], int n)//因为是求大整数,需进位
{
int t = 0;
for(int i = 0; i < n; i++)
{
a[i] += t;
if(a[i] > 9)
{
t = a[i] / 10;
a[i] %= 10;
}
else t = 0;
}
}
char s1[MAXN],s2[MAXN];
int len1,len2,len,sum[MAXN<<2];
inline void conv(cpx a[], cpx b[], int n)//将多项式相乘并把系数放入sum
{
DFT(a, len), DFT(b, len);
for(ri i=0; i<n; ++i)
a[i]=a[i]*b[i];
IDFT(a, len);
for(int i = 0;i < len;i++)//提取出系数
sum[i] = (int)(a[i].r+0.5);
}
inline void init()//将多项式的项数扩充至2^n
{
len1 = strlen(s1);
len2 = strlen(s2);
len = 1;
while(len < len1+len2)len<<=1;
for(int i = 0;i < len1;i++)
a[i] = (cpx){(double)(s1[len1-1-i]-'0'),0};
for(int i = len1;i < len;i++)
a[i] = (cpx){0,0};
for(int i = 0;i < len2;i++)
b[i] = (cpx){(double)(s2[len2-1-i]-'0'),0};
for(int i = len2;i < len;i++)
b[i] = (cpx){0,0};
for(ri i=1; i<len; i<<=1)
{
w[i]=(cpx){1, 0};
for(ri j=1; j<i; ++j)
w[i+j]=((j&31)==1?(cpx){cos(pi*j/i), sin(pi*j/i)}:w[i+j-1]*w[i+1]);
}
}
int main()
{
while(~scanf("%s%s",s1,s2))//输入两个多项式的长度及模数,注意这里的长度比实际长度小1
{
init();
conv(a,b,len);
transfer(sum,len);
len = len1+len2-1;
while(sum[len] <= 0 && len > 0)len--;//舍去前导0
for(int i = len;i >= 0;i--)
printf("%c",sum[i]+'0');
printf("\n");
}
return 0;
}