1. 程式人生 > >3520. 【NOIP2013模擬11.7B組】原根

3520. 【NOIP2013模擬11.7B組】原根

Description

Input

有且只有一個正整數m。

Output

以遞增序依次輸出模m的所有原根,每行輸出一個原根。 如果不存在模m的原根,輸出-1。

Sample Input

7

Sample Output

3

5

Data Constraint

50%的資料,m≤ 200。 100%的資料,m ≤ 10000。

Hint

樣例解釋:

 Solution 

題目是簡單的,完全按照題目描述的方式模擬就可以了。 主要是考察選手會不會對數學題頭昏,以及gcd函式怎麼寫

意思就是暴力。時間複雜度O(m^2);

有人(某大佬)認為這樣的時間複雜度過不了極限資料(其實我也是這麼認為,但是不知為何偏偏就過了),於是想出了一種O(m*根號m*long m)的時間複雜度,這裡來講一下:首先我們知道如果1到fai(m)中可能有很多個

d使得a^d=1(mod m)的,並且每兩個相鄰的d的間隔是一樣的!也就是說d有“迴圈節”因為當a的d次方模完m後又會從1開始再乘a,當a再乘以d次方後又變回了1,即a^2d=1(mod m),如:2^3%7=1,2^6%7=1。總而言之,d是一直迴圈直到fai(m)為止的,就是說a^d=1(mod m)a^2^d=1(mod m)a^3^d=1(mod m),......a^x^d=1(mod m)a^f^a^i^(^m^)=1(mod m)那麼我們又會得出一個結論:d一定是fai(d)的因數!所以我們可以先暴力求出fai函式,然後再根號fai(m)求出fai(m)的所有約數,再將每個約數用快速冪乘起來得出一個答案,再用這個答案mod m看看是否等於1,如果是,那麼當前這個a就不是原根了。

Code1

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
int n,p,x,s,ans=0;
bool bz;
int fai(int x){
	int q=x;
	for(int i=2;i<=x;i++){
		if(x%i==0){
			q=q*(i-1)/i;
			while(x%i==0) x/=i;
		}
	}
	if(x>1) q=q*(x-1)/x;
	return q;
}
int gcd(int x,int y){
	if(x%y==0) return y;
	else return gcd(y,x%y);
}
int main(){
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	scanf("%d",&n);
	if(n==1){printf("1");return 0;}
	p=fai(n);
	for(int i=1;i<=n-1;i++){
		if(gcd(i,n)!=1) continue;
		x=s=i;bz=1;
		for(int j=1;j<=p-1;j++){
			if(s==1){bz=0;break;}
			s=(s*x)%n;
		}
		if(bz){ans++;printf("%d\n",i);}
	}
	if(!ans) printf("-1\n");
	return 0;
}

Code2 

#include<cstdio>
using namespace std;
int zh[10010],ys[10010];
int m,phi=0,tot=0,cnt=0;
bool bz[10010],check,all=0;

int ksm(int x,int y)
{
	int s=1;
	while (y)
	{
		if (y & 1) s=s*x%m;
		x=x*x%m;
		y>>=1;
	}
	return s;
}

int main()
{
	freopen("math.in","r",stdin);
	freopen("math.out","w",stdout);
	scanf("%d",&m);
	if (m==0) return 0&puts("-1");
	else if (m==1 || m==2) return 0&puts("1");
	for (int i=2;i<=m;i++)
		if (!bz[i])
		{
			zh[++tot]=i;
			if (m%i) continue;
			for (int j=1;j<=m/i;j++)
				bz[i*j]=true;
		}
	for (int i=1;i<=m;i++)
		if (!bz[i]) phi++;
	for (int i=1,x=phi;i<=tot && x>1;i++)
		if (x%zh[i]==0)
		{
			ys[++cnt]=zh[i];
			while (x%zh[i]==0) x/=zh[i];
		}
	for (int i=2;i<m;i++)
		if (!bz[i])
		{
			check=1;
			for (int j=1;j<=cnt;j++)
				if (ksm(i,phi/ys[j])==1) {check=0; break;}
			if (check) all=1,printf("%d\n",i);
		}
	if (!all) puts("-1");
	return 0;
}