##原根求解算法: 獲取一個數$N$的原根$root$的算法c++
#include<bits/stdc++.h> #define ll long long #define IL inline #define RG register using namespace std; ll prm[1000],tot,N,root; ll Power(ll bs,ll js,ll MOD){ ll S = 1,T = bs; while(js){ if(js&1)S = S*T%MOD; T = T*T%MOD; js >>= 1; } return S; } IL ll GetRoot(RG ll n){ RG ll tmp = n - 1 , tot = 0; for(RG ll i = 2; i <= sqrt(tmp); i ++){ if(tmp%i==0){ prm[++tot] = i; while(tmp%i==0)tmp /= i; } } if(tmp != 1)prm[++tot] = tmp; //質因數分解 for(RG ll g = 2; g <= n-1; g ++){ bool flag = 1; for(RG int i = 1; i <= tot; i ++){ //檢測是否符合條件 if(Power(g,(n-1)/prm[i],n) == 1) { flag = 0; break; } } if(flag)return g; }return 0; //無解 } int main(){ cin >> N; root = GetRoot(N); cout<<root<<endl; return 0; }
##快速數論變換算法: 計算多項式$f_1*f_2$在模$P$ ($P$爲質數) 意義下的卷積。 講真的,只要把$FFT$的單位複數根換成原根就好了。 注意要提早用上面的算法把模數的原根算出來。算法
#define mod 998244353 //使用NTT須要保證模數mod 爲質數 const ll pr = 3; //3是998244353的原根,在比賽中請用上面那個算法提早算出.... ll f1[_],f2[_],U,V; ll wn[50],R[_],N,M,n,m,l,ans[_]; IL ll Power(RG ll bs,RG ll js){ RG ll S = 1 , T = bs; while(js){if(js&1)S=S*T%mod; T=T*T%mod; js>>=1;} return S; } IL void GetWn(){ //須要計算floor(log n)個原根 for(RG int i = 0; i <= 25; i ++){ RG ll tt = 1<<i; wn[i] = Power(pr,(mod-1)/tt); }return; } IL void NTT(RG ll P[],RG int opt){ for(RG int i = 0; i < n; i ++) if(i < R[i]) swap(P[R[i]],P[i]); for(RG int i = 1,id = 0; i < n; i<<=1){ id ++; for(RG int j = 0,p = i<<1; j < n; j += p){ RG ll w = 1; for(RG int k = 0; k < i; k ++,w = w*wn[id]%mod){ U = P[j+k]; V = w*P[j+k+i]; P[j+k] = (U+V)%mod; P[j+k+i] = ((U-V)%mod+mod)%mod; } } } if(opt == -1){ //caution:反轉時是從1開始 for !!!!! for(RG int i = 1; i < n/2; i ++)swap(P[i],P[n-i]); RG ll inv = Power(n,mod-2); for(RG int i = 0; i < n; i ++)P[i] = P[i]%mod*inv%mod; }return; } int main(){ //讀入數據: cin >> N >> M; for(RG int i = 0; i <= N; i ++)cin >> f1[i]; for(RG int i = 0; i <= M; i ++)cin >> f2[i]; //NTT計算: m = N+M; l = 0; for(n = 1; n <= m; n<<=1) ++ l; for(RG int i = 0; i < n; i ++) R[i] = (R[i>>1]>>1) | ((i&1)<<(l-1)); GetWn(); NTT(f1,1); NTT(f2,1); for(RG int i = 0; i < n; i ++)f1[i] = f1[i]*f2[i]%mod; NTT(f1,-1); //轉移答案: for(RG int i = 0; i <= m; i ++)ans[i] = f1[i]; for(RG int i = 0; i <= m; i ++)cout<<ans[i]<<" "; return 0; }