NTT注意事项

Posted linda-fcj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NTT注意事项相关的知识,希望对你有一定的参考价值。

记住几个常用的素数及原根:

998244353==>3

1004535809==>3

167772161==>3

参考这里:

https://www.cnblogs.com/Guess2/p/8422205.html

贴代码,看细节:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=3e6+10;
const long long mod=1004535809;//注意模数 
int n,m;
long long a[maxn],b[maxn];

inline long long Pow(long long x,long long b)
{
	long long res=1;
	for(;b;b>>=1)
	{
		if(b&1) res=res*x%mod;
		x=x*x%mod;		
	}
	return res;
}

namespace TNT
{
	long long p[maxn],w[21];
	int n,m;
	inline void init(int len)
	{
		for(n=1,m=0;n<=len;n<<=1,m++);//注意是n<=len等于号不能丢 
		for(int i=1;i<n;i++) p[i]=(p[i>>1]>>1)|((i&1)<<(m-1));
	}
	inline void ntt(long long a[],int flag)
	{
		for(int i=1;i<n;i++) if(i<p[i]) swap(a[i],a[p[i]]);
		w[0]=Pow(3*1ll,(mod-1)/n);
		if(flag) w[0]=Pow(w[0],mod-2);
		for(int i=1;i<m;i++) w[i]=w[i-1]*w[i-1]%mod;
		for(int i=1,x=m-1;i<n;x--,i<<=1)//后面这些全部不能加= 
			for(int j=0;j<n;j+=i<<1)//同上 
			{
				long long wi=1;
				for(int k=0;k<i;k++,wi=wi*w[x]%mod)
				{
					long long xx=a[j+k];
					long long yy=a[i+k+j]*wi%mod;
					a[j+k]=(xx+yy)%mod;//注意是j+k 
					a[j+k+i]=(xx-yy+mod)%mod;
				}
			}
		if(flag)
		{
			long long inv=Pow(n,mod-2);
			for(int i=0;i<n;i++) a[i]=a[i]*inv%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]);
	m+=n;
	TNT::init(m);
	TNT::ntt(a,0),TNT::ntt(b,0);
	for(int i=0;i<TNT::n;i++) a[i]=a[i]*b[i]%mod;//注意这里是TNT::n 
	TNT::ntt(a,1);
	for(int i=0;i<=m;i++) printf("%lld ",a[i]);
	return 0;
}

  

以上是关于NTT注意事项的主要内容,如果未能解决你的问题,请参考以下文章

模板 - 数学 - 多项式 - NTT

Luogu4238 模板多项式求逆(NTT)

XSY3306alpha - 线段树+分治NTT

NTT简介

任意模数NTT(MTT)模板

小程序各种功能代码片段整理---持续更新