zoukankan      html  css  js  c++  java
  • P6091 【模板】原根

    题解

    定义 (delta_m(a))(a)(m) 的阶)为满足 (a^nequiv 1pmod m) 的最小的正整数 (n)

    原根 (g) 就是满足 (delta_m(g)=varphi(m)) 的正整数。

    一个数 (a) 是原根的充要条件是对于 (varphi(m)) 的任意素因子 (p),都有 (a^{varphi(m)/p} otequiv1 pmod m),且 (a^{varphi(m)}equiv 1 pmod m)

    一个关于原根的性质是,假如我们知道了模 (m) 意义下的最小原根 (g),那么其它所有原根都形如 (g^{alpha}),其中 (alphaperp varphi(m))。由此也可以得出一个数 (m) 如果有原根,那么其原根个数为 (varphi(varphi(m)))

    另一方面我们也有原根存在定理:如果正整数 (m) 等于 (2,4,p^{alpha},2p^{alpha})(p) 是奇质数),那么 (m) 有原根。

    又有一个定理:如果一个数 (m) 有原根,那么其最小原根的大小不会超过 (m^{0.25})

    于是我们可以在 (O(m^{0.25}omega(m)log m)) 的时间复杂度内找到 (m) 的最小原根,并在 (O(varphi(m) log m)) 的时间复杂度内找到所有原根。

    (omega(m))(m) 的不同质因子个数。

    代码
    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <vector>
    #include <algorithm>
    using namespace std;
    #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
    #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
    template<typename T> void Read(T &x){
    	x=0;int _f=1;
    	char ch=getchar();
    	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
    	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    	x=x*_f;
    }
    template<typename T,typename... Args> void Read(T &x,Args& ...others){
    	Read(x);Read(others...);
    }
    typedef long long ll;
    const int N=1e6+5;
    int T;
    int vis[N],prime[N],prCnt=0,phi[N],rt[N];
    void Sieve(int mx){
    	phi[1]=vis[1]=1;
    	For(i,2,mx){
    		if(!vis[i]) prime[++prCnt]=i,phi[i]=i-1,rt[i]=1;
    		for(int j=1;j<=prCnt&&1LL*i*prime[j]<=mx;++j){
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
    			phi[i*prime[j]]=phi[i]*(prime[j]-1);
    		}
    	}
    	rt[2]=rt[4]=1;
    	for(int j=2;j<=prCnt;++j){
    		for(ll cur=prime[j];cur<=mx;cur*=prime[j]){
    			rt[cur]=1;
    			if(2*cur<=mx) rt[2*cur]=1;
    		}
    	}
    }
    ll Pow(ll a,ll b,ll p){
    	ll res=1;
    	while(b){
    		if(b&1) res=res*a%p;
    		b>>=1,a=a*a%p;
    	}return res;
    }
    bool Check(ll g,ll n,vector<int> &pfac){
    	for(int p:pfac){
    		if(Pow(g,phi[n]/p,n)==1) return 0;
    	}return Pow(g,phi[n],n)==1;
    }
    int main(){
    	Sieve(N-5);
    	Read(T);
    	int n,d;
    	while(T--){
    		Read(n,d);
    		if(!rt[n]){puts("0
    ");continue;}
    		vector<int> pfac;
    		for(int j=1,n_=phi[n];prime[j]<=n_;++j){
    			if(n_%prime[j]==0){
    				pfac.push_back(prime[j]);
    				while(n_%prime[j]==0) n_/=prime[j];
    			}
    		}
    		int g;
    		for(g=1;g<=n;++g){
    			if(Check(g,n,pfac)) break;
    		}
    		vector<int> ans;
    		For(k,1,n) if(__gcd(k,phi[n])==1) ans.push_back(Pow(g,k,n));
    		sort(ans.begin(),ans.end());
    		auto it=unique(ans.begin(),ans.end());
    		ans.erase(it,ans.end());
    		printf("%d
    ",static_cast<int>(ans.size()));
    		for(auto it=ans.begin();it!=ans.end();++it){
    			if((distance(ans.begin(),it)+1)%d==0)
    				printf("%d ",*it);
    		}
    //		for(auto x:ans) printf("%d ",x);
    		puts("");
    	}
    	return 0;
    }
    
    Written by Alan_Zhao
  • 相关阅读:
    004_列表list操作
    003_字符串str的操作
    002_python基础语录
    求哈夫曼树的编码
    Python笔记(一)——打印输出
    python基础一 day33 验证客户端的合法性
    python基础一 day32 复习
    python基础一 day30 网络编程
    python基础一 day29 logging
    python基础一 day29 学习方法(课前谈心)
  • 原文地址:https://www.cnblogs.com/alan-zhao-2007/p/p6091-sol.html
Copyright © 2011-2022 走看看