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

https://www.luogu.com.cn/problem/P1919
题目背景
本题数据已加强,请使用 FFT/NTT,不要再交 Python 代码浪费评测资源。

题目描述
给你两个正整数 a,ba,b,求 a \times ba×b。

输入格式
第一行一个正整数,表示 aa;
第二行一个正整数,表示 bb。

输出格式
输出一行一个整数表示答案。

输入输出样例
输入 #1复制
114514
1919810
输出 #1复制
219845122340
说明/提示
【数据范围】
1 ≤ a , b ≤ 1 0 1000000 1\le a,b \le 10^{1000000} 1a,b101000000
可能需要一定程度的常数优化。
数据由 NaCly_Fish 重造

#include<bits/stdc++.h>
#define MOD 1000000007
using namespace std;        //FFT模板
                            //位数不同的高精度乘法

const int maxn=1e6+5;

struct Complex //复数类
{
    double x,y;
    Complex(double dx=0,double dy=0)
    {
        x=dx;
        y=dy;
    }
};

Complex operator +(Complex a,Complex b)
{
    return Complex(a.x+b.x,a.y+b.y);
}
Complex operator -(Complex a,Complex b)
{
    return Complex(a.x-b.x,a.y-b.y);
}
Complex operator *(Complex a,Complex b)
{
    return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
}

const double pi=acos(-1.0); //PI
int limit=1,bit=0; //limit为最终扩充的长度 limit = 1<<bit
int wz[maxn<<2];
int re[maxn<<2]; //存储结果
Complex a[maxn<<2],b[maxn<<2];
char s1[maxn],s2[maxn];//存储两个整数

void FFT(Complex *A,int inv)
{
    for(int i=0;i<limit;i++)
        if(i<wz[i])
            swap(A[i],A[wz[i]]);
    for(int mid=1;mid<limit;mid<<=1)
    {
        Complex wn(cos(pi/mid),inv*sin(pi/mid));
        for(int i=0;i<limit;i+=mid<<1)
        {
            Complex w(1,0);
            for(int j=0;j<mid;j++,w=w*wn)
            {
                Complex t1=A[i+j];
                Complex t2=w*A[i+mid+j];
                A[i+j]=t1+t2;
                A[i+mid+j]=t1-t2;
            }
        }
    }
}

int main()
{
    while(~scanf("%s%s",s1,s2))
    {
        memset(wz,0,sizeof(wz));
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        limit=1,bit=0;
        int temp;
        int len1=strlen(s1),len2=strlen(s2);
        int len=len1+len2;
        while(limit<=len)
        {
            limit<<=1;
            bit++;
        }               //一个n位的十进制数 可以看做一个n-1次多项式
        for(int i=len1-1,j=0;i>=0;i--,j++)
        {
            a[j].x=s1[i]-48;
            a[j].y=0;
        }
        for(int i=len2-1,j=0;i>=0;i--,j++)
        {
            b[j].x=s2[i]-48;
            b[j].y=0;
        }
        for(int i=0;i<limit;i++)
            wz[i]=(wz[i>>1]>>1)|((i&1)<<(bit-1));
        FFT(a,1);
        FFT(b,1);
        for(int i=0;i<limit;i++)
            a[i]=a[i]*b[i];
        FFT(a,-1);
        memset(re,0,sizeof(re));
        for(int i=0;i<=limit;i++)
        {
            re[i]+=(int)(a[i].x/limit+0.5);
            if(re[i]>=10) //进位
            {
                re[i+1]+=re[i]/10;
                re[i]%=10;
                if(i==limit)
                    ++limit;
            }
        }
        while(!re[limit]&&limit>=1)//去除高位的0
            limit--;
        while(limit>=0)
            printf("%d",re[limit--]);
        printf("\n");
    }
    return 0;
}



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值