HDU 3358 Period of an Infinite Binary Expansion 推荐!!(欧拉函数,费马小定理)

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove

题目:http://poj.org/problem?id=3358

将一个分数化成小数,转化成二进制后寻找循环节

对于分数P/Q而言,首先化成最简,调整为P'=P/GCD(P,Q) Q'=Q/GCD(P,Q)

我们知道转化成二进制,其实就是不断乘2,如果大于1,则去掉1,当前位为1,否则为0.

表示成分数的时候便是P/Q,2*P/Q如果分子大于分母,则减掉,也相当于取余。

于是我们假设在第I位的时候开始循环,第J位出现重复。

而出现循环反正在分数上便是分母和分子都相同,由于在这里分母是不变的,只考虑分子

那么(P'*2^I)%Q'==(P'*2^J)%Q ;

一个同余式,作 些调整  P'*(2^J-2^I)==0(MOD Q')   P'*2^I*(2^(J-I)-1)==0(MOD Q')

变成P'*2^I*(2^(J-I)-1)|Q’

其中P'与Q'互质。那么2^I*(2^(J-I)-1)|Q’

(2^(J-I)-1是奇数,那么I的值便是Q'里面有多少个2^的幂,第一部分已经解决

假设Q'除掉2的幂之后为Q''

那么Q''|(2^(J-I)-1),由费马小定理或者欧拉定理可知

若A与P互质,则A^PHI(P) == 1 (MOD P)

所以2^X ==1 (mod Q'')   必定存在解。

我们要求的是最小的解,则枚举PHI(Q'')的因子,从小开始判断

2^X==1(MOD Q'')

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
#define N 1000000
using namespace std;
LL gcd(LL a,LL b){
	return b==0?a:gcd(b,a%b);
}
LL get_eular(LL n){
	LL ret=1;
	for(LL i=2;i*i<=n;i++)
		if(n%i==0){
			ret*=i-1;
			n/=i;
			while(n%i==0){
				n/=i;
				ret*=i;
			}
		}
	if(n>1)
		ret*=n-1;
	return ret;
}
LL PowMod(LL a,LL b,LL MOD){
	LL ret=1;
	while(b){
		if(b&1)
			ret=(ret*a)%MOD;
		a=(a*a)%MOD;
		b>>=1;
	}
	return ret;
}
LL fact[100000],cnt;
void get_fact(LL n){
	cnt=0;
	for(LL i=2;i*i<=n;i++)
		if(n%i==0){
			fact[cnt++]=i;
			fact[cnt++]=n/i;
		}
}
int main(){
	LL p,q;
	int cas=0;
	while(scanf("%lld/%lld",&p,&q)!=EOF){
		LL t=gcd(p,q);
		p/=t;
		q/=t;
		int c=1;
		while(!(q&1)){
			q/=2;
			c++;
		}
		LL phi=get_eular(q),ans;
		get_fact(phi);
		fact[cnt++]=phi;
		sort(fact,fact+cnt);
		for(int i=0;i<cnt;i++)
			if(PowMod(2,fact[i],q)==1){
				ans=fact[i];
				break;
			}
			printf("Case #%d: %d,%lld\n",++cas,c,ans);
	}
	return 0;
}
			








你可能感兴趣的:(HDU 3358 Period of an Infinite Binary Expansion 推荐!!(欧拉函数,费马小定理))