洛谷P1919--A*B Problem升级版(NTT优化高精度乘法)

题目链接:https://www.luogu.com.cn/problem/P1919

题目背景

本题数据已加强,请使用 FFT/NTT,不要再交 Python 代码浪费评测资源。

题目描述

给你两个正整数 a,b,求$ a imes b$.

输入格式

第一行一个正整数,表示 a;
第二行一个正整数,表示 b。

输出格式

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

输入输出样例

输入 
114514 
1919810
输出 
219845122340

说明/提示

【数据范围】
$1le a,b le 10^{1000000}$

可能需要一定程度的常数优化。

emmmm,刚开始学FFT/NTT的可能一下子没有反应过来,我们设输入$s$,那么这个数必然能被表示成$s=a_0*10^0+a_1*10^1+a_2*10^2+cdots $。。。然后就是个愉快的卷积了^_^,只不过要稍微注意一下顺序的问题和边界的处理

以下是AC代码:

/*
    实质上就是将一个数变成a_0*10^0+a_1*10+a_2*10^2...然后就可以快乐地卷积了
*/
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <string>
using namespace std;

#define IOS ios::sync_with_stdio(false);
typedef long long ll;
const int mac=3e6+10;
const int mod=998244353;

ll a[mac],b[mac],rt[5][30];
int r[mac];
string s1,s2;

ll qpow(ll a,ll b)
{
    ll ans=1;
    a%=mod;
    while (b){
        if (b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans%mod;
}

void NTT(int len,ll *a,int type)
{
    for (int i=0; i<len; i++)
        if (i<r[i]) swap(a[i],a[r[i]]);
    int nb=1;
    for (int mid=1; mid<len; mid<<=1){
        //ll wn=qpow(G,(mod-1)/(mid<<1));//原根代替单位根
        //if (type==-1) wn=qpow(wn,mod-2);//逆变换要乘上逆元
        ll wn=rt[type+1][nb++];
        for (int j=0; j<len; j+=(mid<<1)){
            ll w=1;
            for (int k=0; k<mid; k++,w=(w*wn)%mod){
                ll x=a[j+k],y=w*a[j+k+mid]%mod;
                a[j+k]=(x+y)%mod;
                a[j+k+mid]=(x-y+mod)%mod;
            }
        }
    }
}

int main(int argc, char const *argv[])
{
    for (int i=0; i<=25; i++){//预处理出每个长度下的逆元
        int len=1<<i;
        rt[2][i]=qpow(3,(mod-1)/len);//正变换
        rt[0][i]=qpow(rt[2][i],mod-2);//逆变换
    }
    IOS;
    cin.tie(0); cout.tie(0);
    cin>>s1>>s2;
    int len1=s1.length(),len2=s2.length();
    for (int i=0; i<len1; i++)
        a[i]=s1[len1-i-1]-'0';
    for (int i=0; i<len2; i++)
        b[i]=s2[len2-i-1]-'0';
    int len=1,l=0;
    while (len<=len1+len2) len<<=1,l++;
    for (int i=0; i<len; i++)
        r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    NTT(len,a,1); NTT(len,b,1);
    for (int i=0; i<len; i++)
        a[i]=(a[i]*b[i])%mod;
    NTT(len,a,-1);
    ll inv=qpow(len,mod-2);
    for (int i=0; i<=len1+len2; i++)
        a[i]=a[i]*inv%mod;
    for (int i=0; i<len1+len2; i++){
        if (a[i]>=10) {a[i+1]+=a[i]/10; a[i]%=10;}
    }
    int tail=len1+len2;
    while (a[tail]==0 && tail>0) tail--;
    while (a[tail]>=10) {a[tail+1]+=a[tail]/10; a[tail++]%=10;}
    for (int i=tail; i>=0; i--)
        printf("%d",a[i]);
    printf("
");
    return 0;
}
路漫漫兮
原文地址:https://www.cnblogs.com/lonely-wind-/p/13334058.html