随笔 - 73  文章 - 0 评论 - 0 阅读 - 6643
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

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, L = 0;
    while (len <= n + m)
        len <<= 1, L++;
    for (int i = 0; i < len; ++i)                  //求rev
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 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;
}
posted on   naiji  阅读(225)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示