NTT学习笔记

NTT

好吧,本质上就是FFT,把单位根换成了原根(不是很理解但是就是记住就行)

优点

能取模,FFT的复数你给我来取个模

没有精度差,FFT浮点数的精度怎么也会出一点问题

由于均为整数操作(虽然取模多),NTT常数小,通常比一大堆浮点运算的FFT要快

缺点

多项式的系数都必须是整数

模数有限制,NTT题的模数通常都是相同的998244353

其实这些模数的原根通常都是3

嗯,不太会原根,就不说了

#include<bits/stdc++.h> //NNT 
#define Fu(i,a,b) for(register int i=(a);i<=(b);i++)
#define ll long long
#define mod 998244353
using namespace std;
int n,m,len=1,x,rev[8000005],bit,g=3,gi;//g就是所谓原根
ll a[8000005],b[8000005];
int ksm(ll a,int k){
	ll ans=1;
	while(k){
		if(k&1) ans=ans*a%mod;
		a=a*a%mod,k>>=1;
	}
	return ans;
}
void ntt(int n,ll *a,int inv){
	Fu(i,0,n) if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int mid=1;mid<n;mid<<=1){
		ll wn=ksm(inv==1?g:gi,(mod-1)/(mid<<1));
		for(int i=0;i<n;i+=mid<<1){
			ll w0=1;
			Fu(j,0,mid-1){
				ll x=a[i+j],y=w0*a[i+j+mid]%mod;
				a[i+j]=(x+y)%mod,a[i+j+mid]=(x-y+mod)%mod,w0=w0*wn%mod;
			}
		}
	}
}
int main(){
	gi=ksm(g,mod-2);
	scanf("%d%d",&n,&m);
	Fu(i,0,n) scanf("%lld",&a[i]);
	Fu(i,0,m) scanf("%lld",&b[i]);
	while(len<=n+m) len<<=1,bit++;
	Fu(i,0,len) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
	ntt(len,a,1),ntt(len,b,1);
	Fu(i,0,len) a[i]=1ll*a[i]*b[i]%mod;
	ntt(len,a,-1);
	Fu(i,0,n+m) printf("%lld ",a[i]*ksm(len,mod-2)%mod);
	return 0;
}
posted @ 2024-02-22 20:47  zhy_learn  阅读(5)  评论(0编辑  收藏  举报