测试地址:Period of an Infinite Binary Expansion
题目大意:对于一个小于1的有理数
L
,将其写成二进制小数形式:
做法:可恶啊!明明方程都推出来了,可就是做不出来,好气啊,没办法只能看了题解……
首先我们可以将
p/q
约分,即令
p=p/gcd(p,q),q=q/gcd(p,q)
,简化计算而又不影响结果。分析题目,一个有理数小数部分的二进制表示可以用二进制转换法(乘二法)得到,那么我们可以得到下面这个序列:
2i×p/q(i≥0)
,将每一个数的分子模
q
,得到:
将式子转换一下变成:
(2j−1)×p×2i≡0(modq)
,也就是说
q|(2j−1)×p×2i
,因为
gcd(p,q)=1
,所以
q|(2j−1)×2i
,又由于
2j−1
是奇数,所以
i
就是
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll p,q,fac[30];
ll gcd(ll a,ll b)
{
return (b==0)?a:gcd(b,a%b);
}
ll mult(ll a,ll b,ll mod)
{
a%=mod,b%=mod;
ll s=a,sum=0;
while(b)
{
if (b&1)
{
sum+=s;
if (sum>=mod) sum-=mod;
}
b>>=1;s<<=1;
if (s>=mod) s-=mod;
}
return sum;
}
ll power(ll a,ll b,ll mod)
{
ll s=a,sum=1;
while(b)
{
if (b&1) sum=mult(sum,s,mod);
b>>=1;s=mult(s,s,mod);
}
return sum;
}
ll phi(ll x)
{
ll p=x;
for(int i=2;i*i<=x;i++)
if (!(x%i))
{
p=p/i*(i-1);
while(!(x%i)) x/=i;
}
if (x>1) p=p/x*(x-1);
return p;
}
void find_factor(ll x)
{
fac[0]=0;
for(int i=2;i*i<=x;i++)
if (!(x%i))
{
fac[++fac[0]]=i;
while(!(x%i)) x/=i;
}
if (x>1) fac[++fac[0]]=x;
}
int main()
{
int t=0;
while(scanf("%lld/%lld",&p,&q)!=EOF)
{
t++;
ll d=gcd(p,q),i=0,j;
p/=d,q/=d;
while(!(q%2)) {q>>=1;i++;}
i++;
j=phi(q);
find_factor(j);
for(int i=1;i<=fac[0];i++)
{
while(1)
{
j/=fac[i];
if (power(2,j,q)!=1)
{
j*=fac[i];
break;
}
else if (j%fac[i]) break;
}
}
printf("Case #%d: %lld,%lld\n",t,i,j);
}
return 0;
}