bzoj 2179 FFT快速傅立叶(NTT)

来源:互联网 发布:知乎发帖注意事项 编辑:程序博客网 时间:2024/06/05 13:23

2179: FFT快速傅立叶
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 3468 Solved: 1820
[Submit][Status][Discuss]
Description

给出两个n位10进制整数x和y,你需要计算x*y。

Input

第一行一个正整数n。 第二行描述一个位数为n的正整数x。 第三行描述一个位数为n的正整数y。

Output

输出一行,即x*y的结果。

Sample Input

1

3

4

Sample Output

12

数据范围:

n<=60000


【分析】

NTT解法



【代码】

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mod=479*(1<<21)+1; const int mxn=400005;char s[mxn];int n,m,L;int a[mxn],b[mxn],R[mxn];inline int ksm(int a,int k){    int res=1;    while(k)    {        if(k&1) res=((ll)res*a)%mod;         a=((ll)a*a)%mod;        k>>=1;    }    return res; }inline void NTT(int *a,int f){    int i,j,k;    fo(i,0,n-1) if(i<R[i]) swap(a[i],a[R[i]]);    for(i=1;i<n;i<<=1)    {        int wn=ksm(3,(mod-1)/(i<<1));        for(j=0;j<n;j+=(i<<1))        {            int w=1;            for(k=0;k<i;k++,w=((ll)w*wn)%mod)            {                int x=a[j+k],y=((ll)w*a[j+k+i])%mod;                a[j+k]=(x+y)%mod,a[j+k+i]=(x-y+mod)%mod;            }        }    }    if(f==-1)    {        reverse(a+1,a+n);        int rev=ksm(n,mod-2);        fo(i,0,n-1) a[i]=((ll)a[i]*rev)%mod;    }}int main(){    int i,j,k;    scanf("%d",&n);    n--;    scanf("%s",s);    fo(i,0,n) a[i]=s[n-i]-'0';    scanf("%s",s);    fo(i,0,n) b[i]=s[n-i]-'0';    m=2*n;for(n=1;n<=m;n<<=1) L++;    fo(i,0,n-1) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);    NTT(a,1),NTT(b,1);    fo(i,0,n) a[i]=((ll)a[i]*b[i]%mod);    NTT(a,-1);    fo(i,0,m) if(a[i]>=10)    {        a[i+1]+=a[i]/10,a[i]%=10;        if(i==m) m++;    }    while(!a[m]) m--;    for(i=m;i>=0;i--) printf("%d",a[i]);    return 0;}