HDU
来源:互联网 发布:java 同步互斥 编辑:程序博客网 时间:2024/06/05 12:43
题意:
让你求出一个数的全部原根,如果没有,输出-1;
题解“:
首先先判断该数有无原根,
一个数x若有原根 则必然满足 n=1,2,4,2p,p^r
若有原根,再暴力枚举找到最小的原根,分解质因数phi(n);
则从2~n-1 中有a 满足 a^phi(n)mod n=1 则a 不是n的原根。
找到最小原根后
如果g为n的原根,则gd为m的原根的充要条件是gcd(d,φ(n))=1;
然后递推出所有结果。
1.有原根的数只有2,4,p^n,2p^n(p为质数,n为正整数)。
2.一个数的最小原根的大小是O(n0.25)的。
3.如果g为n的原根,则gd为m的原根的充要条件是(d,φ(n))=1;
4.如果n有原根,它的原根个数为φ(φ(n))。
5.一个数n的全体原根乘积模n余16.一个数n的全体原根总和模n余μ(n-1)(莫比乌斯函数)
#include<iostream>#include<cstdio>#include<vector>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define ll long longconst int maxn=1e6+5;int a[10000];bool p[maxn];int ans[maxn];int cnt;ll gcd(ll a,ll b){ ll t; while(b){ t=a;a=b;b=t%b; } if(a>=0) return a; else return -a;}int phi(int x){ if(p[x]) return x-1; int ret=x; for(int i=2;i<=x;++i){ if(x%i==0){ while(x%i==0) x/=i; ret=ret-ret/i; } } if(x>1) ret=ret-ret/x; return ret;}bool check(int x){ if(x%2==0) x/=2; if(p[x]) return true; for(int i=3;i*i<=x;i+=2){ if(x%i==0){ while(x%i==0) x/=i; return x==1; } } return 0;}void get_x(int x){ cnt=0; if(p[x]) return ; for(int i=2;i*i<=x;++i){ if(x%i==0) a[++cnt]=i; if(i*i!=x) a[++cnt]=x/i; //while(x%i==0) x/=i; }}int kru(int a,int b,int mod){ ll ret=1; ll t=a; while(b){ if(b&1) ret=(ret*t)%mod; t=t*t%mod; b>>=1; } return (int)ret;}void init(){ memset(p,1,sizeof(p)); p[0]=p[1]=false; for(int i=2;i<maxn;++i) if(p[i]){ for(int j=i+i;j<maxn;j+=i) p[j]=false; }}int main(){ init(); int n; while(~scanf("%d",&n)){ if(n==2){ puts("1");continue; } if(n==4){ puts("3");continue; } if(check(n)==0) { puts("-1");continue; } int t=phi(n); //printf("phi(%d)=%d\n",n,t); get_x(t); int x=-1; for(int i=2;i<n;++i){ int f=1; if(kru(i,t,n)!=1) continue; for(int j=1;j<=cnt;++j){ if(kru(i,a[j],n)==1){ f=0;break; } } if(f){ x=i; ans[0]=i; break; } } if(x==-1){ puts("-1");continue; } cnt=0; for(int i=2;i<t;++i){ if(gcd(i,t)==1) ans[++cnt]=kru(x,i,n); } sort(ans,ans+cnt+1); printf("%d",ans[0]); for(int i=1;i<=cnt;++i) printf(" %d",ans[i]); puts(""); } return 0;}
阅读全文
0 0