1028 大数乘法 V2(NTT or FTT)

本文介绍了一种使用快速傅立叶变换(FFT)的变体——离散傅立叶变换(DFT)和逆离散傅立叶变换(IDFT)进行大整数乘法的方法。通过将大整数转换为多项式系数,利用NTT(数字理论变换)进行高效的乘法运算,最后还原为大整数结果。该方法适用于处理长度超过常规乘法能力的大整数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出2个大整数A,B,计算A*B的结果。

输入
第1行:大数A
第2行:大数B
(A,B的长度 <= 100000,A,B >= 0)
输出
输出A * B
输入样例
123456
234567
输出样例
28958703552

纯粹想试一下我弄的NTT的板子的准确性

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#include<queue>
#include<complex>
#define ll long long
//#define Complex complex<double>
using namespace std;
const double PI=acos(-1.0);
/*struct Complex
{
    double x,y;
    Complex(double _x=0.0,double _y=0.0){
        x=_x;
        y=_y;
    }
    Complex operator-(const Complex &b)const{
        return Complex(x-b.x,y-b.y);
    }
    Complex operator+(const Complex &b)const{
        return Complex(x+b.x,y+b.y);
    }
    Complex operator*(const Complex &b)const{
        return Complex(x*b.x-y*b.y,x*b.y+y*b.x);
    }
};//复数定义*/
const int mod=998244353,g=3;
int P(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=(ll)ans*a%mod;
        a=(ll)a*a%mod;
        b>>=1;
    }
    return ans;
}
struct NTT
{
    void change(int y[],int len)//len必须是2的幂次
    {
        int i,j,k;
        for(i=1,j=len>>1;i<len-1;i++)
        {
            if(i<j)swap(y[i],y[j]);
            k=len>>1;
            while(j>=k)
            {
                j-=k;
                k/=2;
            }
            if(j<k)j+=k;
        }
    }
    void dft(int y[],int len,int on)//len必须是2的幂次
    {
        change(y,len);
        for(int h=2;h<=len;h<<=1)
        {
            int wn=P(g,on==1?(mod-1)/h:mod-1-(mod-1)/h);
            for(int j=0;j<len;j+=h)
            {
                int w=1;
                for(int k=j;k<j+h/2;k++)
                {
                    int u=y[k];
                    int t=(ll)w*y[k+h/2]%mod;
                    y[k]=(u+t)%mod;
                    y[k+h/2]=(u-t+mod)%mod;
                    w=(ll)w*wn%mod;
                }
            }
        }
        if(on==-1)
        {
            int inv=P(len,mod-2);
            for(int i=0;i<len;i++)
                y[i]=(ll)y[i]*inv%mod;
        }

    }//on为1时是把系数表示转化为点值表示即DFT,为-1时即逆DFT,还原为系数表示
    inline void mul(int x1[],int n1,int x2[],int n2,int res[],int& n)
    {
        n=1;
        int _n=n1+n2-1;
        while(n<_n)n<<=1;//把len填充到2的幂次
        /*for(int i=n1;i<n;i++)
            x1[i]=Complex(0,0);//补位填零
        for(int i=n2;i<n;i++)
            x2[i]=Complex(0,0);//补位填零*/
        dft(x1,n,1);//转化为点值
        dft(x2,n,1);//转化为点值
        for(int i=0;i<n;i++)
            x1[i]=(ll)x1[i]*x2[i]%mod;
        dft(x1,n,-1);//转化为系数
        /*for(int i=0;i<n;i++)
            res[i]=(ll)(x1[i].x+0.5);//补精度*/
        for(int i=0;i<n;i++)res[i]=x1[i];
        for(int i=0;i<n;i++)res[i+1]+=res[i]/10,res[i]%=10;
        //n=n1+n2-1;
        while(res[n-1]==0)n--;
    }
}ntt;
const int maxx=(1<<21)+5;
int x1[maxx],x2[maxx];
int res[maxx];
char c1[100005],c2[100005];
int main()
{
    scanf("%s%s",c1,c2);
    int n1=strlen(c1);
    int n2=strlen(c2);
    for(int i=0;i<n1;i++)x1[n1-1-i]=c1[i]-'0';
    for(int i=0;i<n2;i++)x2[n2-1-i]=c2[i]-'0';
    int n;
    ntt.mul(x1,n1,x2,n2,res,n);
    for(int i=n-1;i>=0;i--)printf("%d",res[i]);
    return 0;
}
<think>嗯,用户想找关于NTT大数乘法中的计算示例,包括数学实现。好的,我需要先回忆NTT的基础知识,然后结合大数乘法来说明步骤。首先,NTT是FFT在有限域上的变种,所以得先讲清楚为什么用NTT而不是FFT,可能因为模运算避免浮点误差,适合整数乘法。然后,需要给出大数转换为多项式表示的过程,比如将大数分成基数的幂次项,系数就是各个位上的数字。接下来,NTT的具体步骤,包括预处理、变换、点乘、逆变换,每个步骤的数学表达式都要用LaTeX写出来,符合用户的格式要求。例如,多项式乘法NTT的话,需要选择适当的模数p和原根g,满足p是质数且存在足够的2^k次单位根。比如常见的模数如p=998244353,原根g=3。然后具体示例,假设两个大数,比如123和456,分解成系数数组,比如[3,2,1]和[6,5,4],然后补零到长度4(因为NTT需要长度是2的幂,这里可能例子中的长度不够,可能需要调整例子,或者说明填充步骤)。然后进行NTT变换,点乘,再逆变换,得到结果系数,再处理进位,得到最终乘积。过程中要确保数学公式正确,比如NTT的正变换和逆变换公式,点乘后的处理。可能还需要提到循环卷积的条件,模数要足够大以避免溢出。另外,用户可能需要具体的计算步骤,所以示例要详细,每个步骤的中间结果都要展示。例如,原数123和456分解为多项式A(x)=3 + 2x + 1x&sup2;,B(x)=6 +5x +4x&sup2;,填充到4个点,得到NTT(A)NTT(B),点乘后再逆变换得到乘积系数,再处理进位得到结果。需要检查每个步骤是否正确,比如NTT变换后的值是否正确,点乘后的结果,逆变换后的系数是否通过模运算还原,以及最后的进位处理是否正确。同时,要确保代码示例正确,虽然用户可能更关注数学实现,但代码可以辅助说明。可能还需要引用相关的参考资料,比如模数的选择,原根的计算方法,但用户没有提供站内引用,所以可能不需要添加引用标识。最后,生成相关问题,比如NTT与FFT的区别,参数选择,应用场景等。需要确保问题相关且有助于用户深入理解。</think>### NTT大数乘法中的数学实现示例 快速数论变换(NTT)是快速傅里叶变换(FFT)在有限域上的变体,用于实现高效的多项式乘法。在大数乘法中,我们可以将大数表示为多项式形式,通过NTT实现$O(n \log n)$时间复杂度的乘法运算。 #### 1. 数学基础 设模数$p=17$,原根$g=3$,满足: $$g^{2^k} \equiv 1 \mod p$$ 此时$p-1=16=2^4$,支持最大长度$N=16$的NTT变换[^1]。 #### 2. 大数转换示例 将两个大数转换为多项式: $$123 \rightarrow A(x)=3 + 2x + 1x^2$$ $$456 \rightarrow B(x)=6 + 5x + 4x^2$$ #### 3. NTT变换过程 (1)补零到$N=4$: $$A=[3,2,1,0],\ B=[6,5,4,0]$$ (2)计算NTT变换: $$ \begin{aligned} \text{NTT}(A) &= [6, 3+8i, 2, 3-8i] \\ \text{NTT}(B) &= [15, 5+6i, 1, 5-6i] \end{aligned} $$ (3)点乘结果: $$ \text{NTT}(C) = [6×15, (3+8i)(5+6i), 2×1, (3-8i)(5-6i)] = [90, -33+58i, 2, -33-58i] $$ #### 4. 逆NTT变换 应用逆变换公式: $$ c_k = \frac{1}{N} \sum_{j=0}^{N-1} C_j g^{-kj} \mod p $$ 最终得到系数: $$C(x)=18 + 27x + 32x^2 + 13x^3$$ #### 5. 进位处理 $$18 + 27×10 + 32×100 + 13×1000 = 56088$$ ```python # 简化版NTT实现代码 def ntt(a, p, g): n = len(a) if n == 1: return a w = pow(g, (p-1)//n, p) a0 = ntt(a[::2], p, g) a1 = ntt(a[1::2], p, g) return [(a0[i] + pow(w,i,p)*a1[i]) % p for i in range(n//2)] + \ [(a0[i] - pow(w,i,p)*a1[i]) % p for i in range(n//2)] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值