• 学习笔记———NTT


    基本原理和FFT是一样的,那么我们参考FFT,他是把单位根代入了进去,但是这样就会产生精度问题,那么NTT如何避免这个问题呢??

    我们可以用原根来代替单位根

    什么是原根呢??

    其实我也不知道,但是给出一个结论:一个质数P的原根为(g),那么(g^1,g^2dots g^{p-1})他们模P后的结果各不相同

    为什么可代替呢??

    考虑在FFT中我们应用了单位根哪几个性子:

    1. 对于任意的(1leq w leq n)(W_n^k)都各不相同

    2. (W_n^k = W_{2n}^{2k})

    3. (W_{n}^{k+frac{n}{2}} = -W_{n}^{k})

    根据之前给出的结论,可以证明性质1成立,然后通过一些平方运算也可以证明剩下两条性质成立,那么我们就证明了他是可替代的

    剩下的就和FFT一样了,代码如下:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #define ll long long
    #define B cout<<"Breakpoint"<<endl;
    #define O(x) cout<<#x<<" "<<x<<endl;
    #define o(x) cout<<#x<<" "<<x<<" ";
    using namespace std;
    int read(){
    	int x = 1,a = 0;char ch = getchar();
    	while (ch < '0'||ch > '9'){if (ch == '-') x = -1;ch = getchar();} 
    	while (ch >= '0'&&ch <= '9'){a = a*10+ch-'0';ch = getchar();}
    	return x*a; 
    }
    const int maxn = 3e6+10,G = 3,Gi = 332748118,P = 998244353;
    int dp[maxn];
    ll qpow(ll a,ll k){
    	ll res = 1;a = a % P;
    	while (k){
    		if (k&1) res = res*a % P;
    		a = a*a % P;
    		k >>= 1;
    	} 
    	return res % P;
    }
    int n,m,len,num;
    inline void NTT(ll *a,int op){
    	for (int i = 0;i < len;i++){
    		if (i < dp[i]) swap(a[i],a[dp[i]]);
    	}
    	for (int l = 1;l < len;l <<= 1){
    		ll wn = qpow(op == 1 ? G : Gi,(P-1)/(l << 1));
    		for (int i = 0;i < len;i += (l <<1)){
    			ll w0 = 1;
    			for (int j = 0;j < l;j++,w0 = w0*wn % P){
    				int x = a[i+j],y = w0*a[i+j+l] % P;
    				a[i+j] = (x+y) % P,a[i+j+l] = (x-y + P) % P; 
    			}
    		}
    	}
    }
    ll a[maxn],b[maxn];
    int main(){
    	n = read(),m = read();
    	for (int i = 0;i <= n;i++) a[i] = read();
    	for (int i = 0;i <= m;i++) b[i] = read();
    	len = 1,num = 0;
    	while (len <= n+m) len <<= 1,num++;
    	for (int i = 0;i < len;i++) dp[i] = (dp[i >> 1] >> 1) | ((i & 1) << (num-1));
    	NTT(a,1),NTT(b,1); 
    	for (int i = 0;i < len;i++) a[i] = a[i]*b[i] % P;
    	NTT(a,-1);
    	ll inv = qpow(len,P-2);
    	for (int i = 0;i <= n+m;i++) printf("%d ",a[i]*inv % P);
    	return 0;
    }
    
  • 相关阅读:
    Java并发基础-并发模型、基础接口以及Thread
    Java基础-IO
    大数据平台搭建-hbase集群的搭建
    大数据平台搭建-zookeeper集群的搭建
    大数据平台搭建-基础环境安装
    kafka知识体系-消费者编程实践
    kafka知识体系-生产者编程实践
    editplus打造java运行环境(安装、配置、操作)
    实验2 安装Atlas实现读写分离
    实验1 配置MySQL主从同步
  • 原文地址:https://www.cnblogs.com/little-uu/p/14940959.html
Copyright © 2020-2023  润新知