题目大意:
给你一个分数,就他二进制的循环节。求开始循环的点和循环长度。
思路:
已知t*2^phi(r)=t (mod r),先求出phi(r),然后求phi(r)的因子,求一个最小符合条件的。
这样就可以大大缩小了查找的范围。
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
#define LL long long
#define min(a,b) a<b?a:b
LL gcd(LL a,LL b)
{
if(b==0) return a;
return gcd(b,a%b);
}
LL phi(LL p)
{
LL ret=p;
for(LL i=2;i*i<=p;++i)
{
if(p%i==0)
{
ret=ret/i*(i-1);
p/=i;
while(p%i==0) p/=i;
}
}
if(p!=1)
ret=ret/p*(p-1);
return ret ;
}
LL pow2_mod(LL k,LL md)
{
if(k==0) return 1;
if(k==1)
return 2%md;
LL b=pow2_mod(k/2,md);
b=(b*b)%md;
if(k&1)
return 2*b%md;
return b;
}
int main()
{
LL p,q,i,cnt=0,period,j;
while(~scanf("%I64d/%I64d",&p,&q))
{
j=1<<29;
//if(!p){ printf("Case #%I64d: 1,1 \n",++cnt);continue; }
period=0;
LL g=gcd(p,q);
p/=g;
q/=g;
i=1;
while(q%2==0)
{
q/=2;
i++;
}
LL x=phi(q);
for(int k=2;k*k<=x;++k)
{
if(x%k==0)
{
if(k<j)
{
if(pow2_mod(k,q)==1)
j=k;
}
LL temp=x/k;
if(temp<j)
if(pow2_mod(temp,q)==1)
j=temp;
}
}
if(j>(1<<28))
period=x;
else period=j;
printf("Case #%I64d: %I64d,%I64d \n",++cnt,i,period);
}
}