首页 > 其他分享 >NTT(快速数论变换)

NTT(快速数论变换)

时间:2022-09-01 21:37:00浏览次数:69  
标签:数论 rev NTT 表示法 变换 int type

NTT(快速数论变换)

在取模的情况下,解决多项式乘法.

n,m表示多项式的次数,从低到高读入

const int NR = 1 << 22, g = 3, gi = 332748118, mod = 998244353;
//998244353的一个原根为3且998244353-1=2^23*119,3在模998244353意义下的逆元为332748118
int n, m, rev[NR]; //rev[i]为i的二进制翻转
long long a[NR], b[NR];
ll fast_power(ll a, ll k) //快速幂,a为底数,k为指数
{
    ll res = 1;
    while (k)
    {
        if (k & 1)
            res = res * a % mod;
        a = a * a % mod;
        k >>= 1;
    }
    return res;
}
void NTT(ll* a, int n, int type) //NTT,type=1时系数表示法转点值表示法,否则点值表示法转系数表示法
{
    for (int i = 0; i < n; ++i) //先将a变成最后的样子
        if (i < rev[i])
            swap(a[i], a[rev[i]]);
    for (int i = 1; i < n; i <<= 1)
    {                                                            //在这之前NTT与FFT无异
        ll gn = fast_power(type ? g : gi, (mod - 1) / (i << 1)); //单位原根g_n
        for (int j = 0; j < n; j += (i << 1))                    //枚举具体区间,j也就是区间右端点
        {
            ll g0 = 1;
            for (int k = 0; k < i; ++k, g0 = g0 * gn % mod) //合并,记得要取模
            {
                ll x = a[j + k], y = g0 * a[i + j + k] % mod;
                a[j + k] = (x + y) % mod;
                a[i + j + k] = (x - y + mod) % mod;
            }
        }
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i <= n; ++i) //输入第一个多项式
        scanf("%lld", a + i);
    for (int i = 0; i <= m; ++i) //输入第二个多项式
        scanf("%lld", b + i);
    int len = 1 << max((int)ceil(log2(n + m)), 1); //由于NTT需要项数为2的整数次方倍,所以多项式次数len为第一个大于n+m的二的正整数次方
    for (int i = 0; i < len; ++i)                  //求rev
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (max((int)ceil(log2(n + m)), 1) - 1));
    NTT(a, len, 1); //系数表示法转点值表示法
    NTT(b, len, 1);
    for (int i = 0; i <= len; ++i)
        a[i] = a[i] * b[i] % mod;          //O(n)乘法
    NTT(a, len, 0);                        //点值表示法转系数表示法
    ll inv = fast_power(len, mod - 2);     //inv为len的逆元(费马小定理求逆元)
    for (int i = 0; i <= n + m; ++i)       //输出
        printf("%lld ", a[i] * inv % mod); //除以len在模mod意义下即为乘以inv
    return 0;
}

标签:数论,rev,NTT,表示法,变换,int,type
From: https://www.cnblogs.com/wz021001/p/16647874.html

相关文章

  • 归档 220901 | 梅开四度:初等数论 - 整除,同余,排列组合
    致敬经典:数↗学,能够使我的灵↗魂↗得到升↗华↘。证明:任意奇数的平方减\(1\)是\(8\)的倍数。设该奇数为\(2n+1\),则:\[\begin{aligned}(2n+1)^2-1&=......
  • 【瞎口胡】快速数论变换 NTT
    在FFT中,因为是浮点数计算因此会掉精度。如果你不知道FFT是什么,请阅读这里。如果在模意义下,我们可以选择不使用复平面的单位根,而是模意义下的单位根。考虑单位根的性......
  • Mathematical Circus-数论-分类讨论
    codeforces MathematicalCircus-div2-B题意:给定n,k。是否能把(1--n)的数分成符合条件的(a,b)对。条件:(a+k)*b%4==0解:因为:原式=(a+k)*b≡0(mod4)ab+b*k≡0(mod4)若k>=4,b......
  • React报错之Property 'value' does not exist on type EventTarget
    正文从这开始~总览当event参数的类型不正确时,会产生"Property'value'doesnotexistontypeEventTarget"错误。为了解决该错误,将event的类型声明为React.ChangeEvent......
  • 数论笔记(Full Version)
    数论笔记(FullVersion)一、数论基础:1、整除:重新定义除法:对于计算式:\(a\divb\)来说,其结果可以变化为以下的式子:$$a=\lfloor\frac{a}{b}\rfloor+a\bmodb$$其......
  • 从零开始游戏开发——3.2 投影变换
    在3.1节中的程序中,我们在RendererApplication::OnInitialize()中看到有下面一段代码,这段代码创建了一个转换到摄像机空间的矩阵和转换到投影空间的矩阵,并将他们传递给......
  • Python图像处理丨图像的灰度线性变换
    摘要:本文主要讲解灰度线性变换。本文分享自华为云社区《[Python图像处理]十五.图像的灰度线性变换》,作者:eastmount。一.图像灰度线性变换原理图像的灰度线性变换是通过......
  • 【AGC】AGC鉴权认证模式获取clientToken的方法
    ​近期有开发者在使用API方式接入Indexing服务时提出疑问,如何获取clientToken。其实AGC认证模式是基于clientToken鉴权方式,由云侧网关与AGC微服务实现的一套OAuth2标准鉴权......
  • 时隔多年,再次复习 CRT(数论全家桶)
    1.CRT中国剩余定理,用来求解同余方程组\begin{cases}x\equiva_1\pmod{m_1}\\x\equiva_2\pmod{m_2}\\x\equiva_3\pmod{m_3}\\…………\\x\equiva_n\pmod{m......
  • 数论做题记录
    P3811【模板】乘法逆元数据范围是只能\(\mathcal{O}(n)\)过的。考虑递推逆元。设\(t=p/i,k=p%i\)。\(t*i+k\equiv0(\bmodp)\).\(k\equiv-t*......