原根求解算法 && NTT算法

##原根求解算法: 獲取一個數$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;
}
相關文章
相關標籤/搜索