• 原根求解算法 && NTT算法


    原根求解算法:

    获取一个数\(N\)的原根\(root\)的算法

    #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;
    }
    
    

  • 相关阅读:
    mongdb
    网络编程
    分布式锁与事务
    mongodb
    Angular4
    思考
    kafka
    Spark总结
    你不知道的javaScript笔记(1)
    vue2.0 配置 选项 属性 方法 事件 ——速查
  • 原文地址:https://www.cnblogs.com/Guess2/p/8362004.html
Copyright © 2020-2023  润新知