P1919 【模板】A*B Problem升级版(FFT快速傅里叶)

FFT 板子题

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define MAXN 3000100
using namespace std;
char s1[MAXN],s2[MAXN];
int lim=1,r[MAXN],res[MAXN],cnt1,cnt2,k;
const double Pi=acos(-1.0);
struct Node{
    double x,y;
    Node(double _x=0,double _y=0):x(_x),y(_y){}
    Node operator*(Node b){
        return Node(x*b.x-y*b.y,x*b.y+y*b.x);
    }
    Node operator+(Node b){
        return Node(x+b.x,y+b.y);
    }
    Node operator-(Node b){
        return Node(x-b.x,y-b.y);
    }
}a[MAXN],b[MAXN];
void fft(Node *a,double d){ // d=1:系数转点值,d=-1:点值转系数
    for(int i=0;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]); // butterfly 换位
    for(int i=1;i<lim;i<<=1){ // fft 的迭代写法
        Node T(cos(Pi/i),d*sin(Pi/i));
        for(int j=0;j<lim;j+=(i<<1)){
            Node t(1,0);
            for(int k=0;k<i;k++,t=t*T){
                Node nx=a[j+k],ny=t*a[i+j+k];
                a[j+k]=nx+ny;a[i+j+k]=nx-ny;
            }
        }
    }
}
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf(" %s %s ",s1,s2);
    int len1=strlen(s1),len2=strlen(s2);
    for(int i=len1-1;i>=0;i--)a[cnt1++].x=s1[i]-'0'; // 从低位到高位存储系数表达式
    for(int i=len2-1;i>=0;i--)b[cnt2++].x=s2[i]-'0';
    while(lim<len1+len2)lim<<=1,k++; // 通过补零使总长成为2的幂, lim=2^k
    for(int i=0;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(k-1)); // r[i] 是 i 的反序二进制, 此处写法用了个递推
    fft(a,1);fft(b,1); // 系数=>点值
    for(int i=0;i<=lim;i++)a[i]=a[i]*b[i]; // 点乘法
    fft(a,-1);
    int tot=0;
    for(int i=0;i<=lim;i++){
        res[i]+=(int)(a[i].x/lim+0.5);
        if(res[i]>=10)res[i+1]+=res[i]/10,res[i]%=10,lim+=(i==lim);
    }
    while(!res[lim]&&lim>=1)lim--;lim++;
    while(--lim>=0)printf("%d",res[lim]);
    return 0;
}

posted @ 2020-07-11 17:07  winechord  阅读(104)  评论(0编辑  收藏  举报