转载请注明出处,谢谢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;
}