zoukankan      html  css  js  c++  java
  • 【luogu P3803】【模板】多项式乘法(NTT)

    【模板】多项式乘法(NTT)

    题目链接:luogu P3803

    题目大意

    给你两个多项式,要你求它们的卷积。

    思路

    这次我们写 NTT 的做法。
    它的优点就是它可以取模,而且不会有精度问题,而且会比 FFT 稍微快一点?

    然而它的确定就是它的模数比较死板,一般就 (998244353,1004535809,469762049) 这些。(它们的原根都是 (3)

    其实就是考虑用原根代替复数。
    因为它是跟单位根有着相同的性质。

    然后通过证明,我们可以得到 (omega_nequiv g^{frac{p-1}{n}}mod p)
    然后你就把 FFT 中的 (omega_i) 都换掉就是 NTT 了。
    然后这里我 (p) 取的是 (998244353),原根是 (3)

    代码

    #include<cstdio>
    #include<algorithm>
    #define ll long long
    #define mo 998244353
    #define G 3
    
    using namespace std;
    
    int n, m, an[4000001];
    int limit, ln;
    ll a[4000001], b[4000001], Gv;
    
    ll ksm(ll x, ll y) {
    	ll re = 1;
    	while (y) {
    		if (y & 1) re = (re * x) % mo;
    		x = (x * x) % mo;
    		y >>= 1;
    	}
    	return re;
    }
    
    void NTT(ll *now, int op) {
    	for (int i = 0; i < limit; i++)
    		if (i < an[i]) swap(now[i], now[an[i]]);
    	
    	for (int mid = 1; mid < limit; mid <<= 1) {
    		ll Wn = ksm(op == 1 ? G : Gv, (mo - 1) / (mid << 1));
    		//如果这里是负的那就是逆元的次方
    		for (int R = (mid << 1), j = 0; j < limit; j += R) {
    			ll w = 1;
    			for (int k = 0; k < mid; k++, w = (w * Wn) % mo) {
    				ll x = now[j + k], y = w * now[j + mid + k] % mo;
    				now[j + k] = (x + y) % mo;
    				now[j + mid + k] = (x - y + mo) % mo;
    			}
    		}
    	}
    }
    
    int main() {
    	scanf("%d %d", &n, &m);
    	for (int i = 0; i <= n; i++) {
    		scanf("%d", &a[i]);
    		a[i] = (a[i] % mo + mo) % mo;
    	}
    	for (int i = 0; i <= m; i++) {
    		scanf("%d", &b[i]);
    		b[i] = (b[i] % mo + mo) % mo;
    	}
    	
    	limit = 1;
    	while (limit <= n + m) {
    		limit <<= 1; ln++;
    	}
    	for (int i = 0; i < limit; i++)
    		an[i] = (an[i >> 1] >> 1) | ((i & 1) << (ln - 1));
    	Gv = ksm(G, mo - 2);
    	
    	NTT(a, 1);
    	NTT(b, 1);
    	for (int i = 0; i < limit; i++)
    		a[i] = (a[i] * b[i]) % mo;
    	NTT(a, -1);
    	
    	ll liv = ksm(limit, mo - 2);//除就变成逆元乘
    	for (int i = 0; i <= n + m; i++)
    		printf("%lld ", a[i] * liv % mo);
    	
    	return 0;
    }
    
  • 相关阅读:
    checkbox美化
    JS 之简单计算器
    python实现简单用户认证和角色制授权
    搭建高性能web服务
    纯JS实现fadeIn 和fadeOut
    纯CSS实现气泡框
    javascript之对象(二)&& 继承问题
    JavaScript之对象(一)
    Web发展史
    [LeetCode 256] Paint House
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_P3803_NTT.html
Copyright © 2011-2022 走看看