您的位置:首页 > 其它

poj 3358 Period of an Infinite Binary Expansion——欧拉函数+费马小定理

2011-09-06 19:12 423 查看
题目意思是给定m,n问你 m/n的二进制表示的最大循环节开始位置和长度。

找了一些题解,发现没有满意的,discuss里面的分析已经很好了。。

我们可以观察一下1/10这组数据,按照二进制转换法(乘二法),我们可以得到:

1/10 2/10 4/10 8/10 16/10 32/10 ...

然后都分子都尽可能减去10,得到:

1/10 2/10 4/10 8/10 6/10 2/10 ...

这时候,发现出现了重复,那么这个重复就是我们要求的最小循环。

抽象出模型如下:对p/q

首先p'=p/gcd(p,q)

q'=q/gcd(p,q);

然后我们就是求p'*2^i == p'*2^j (mod q') (“==”表示同余,i<j;

经过变换得到:

p'*2^i*(2^(j-i)-1) ==0 (mod q')

也就是 q' | p'*2^i*(2^(j-i)-1)

由于gcd(p',q')=1,

得到: q' | 2^i*(2^(j-i)-1)

因为2^(j-i)-1为奇数,所以q'有多少个2的幂,i就是多少,而且i就是循环开始位置的前一位。

那么令q''为q'除去2的幂之后的数

此时 q'' | 2^(j-i)-1

也就是求出x,使得 2^x ==1 (mod q'')

因此我们还要枚举phi(q)的因子,判断有 2 ^ x == 1(mod q) ,取最小的x(PS:先开始这个地方写搓了,很容易错的呀。。)

a274003358Accepted400K0MSG++1258B2011-09-06 18:57:36
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>

typedef long long LL;

LL gcd(LL a,LL b)
{
if(b==0)
return a;
else return gcd(b,a%b);
}

LL euler(LL n)
{
LL i;
LL total=n;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
total=total/i*(i-1);
while(n%i==0)    n/=i;
}
}
if(n!=1)
total=total/n*(n-1);
return total;
}

LL quickmod(LL a,LL n,LL p)
{
if(n==0)
return 1%p;
if(n==1)
return a%p;
a%=p;
LL ans=quickmod(a,n/2,p)%p;
ans=ans*ans%p;
if(n&1)
ans=ans*a%p;
return ans;
}

int main(void)
{
LL p,q;
LL cas=0;
char ch;
while(scanf("%lld%c%lld",&p,&ch,&q)==3)
{
LL temp=gcd(p,q);
p=p/temp;
q=q/temp;
LL i=1,j=-1;
while(q%2==0)
{
q/=2;
i++;
}
LL phi=euler(q);
LL k;
for(k=2;k*k<=phi;k++)
{
if(phi%k==0)
{
if(quickmod(2,k,q)==1)
{
if(j==-1)
j=k;
else if(j>k)
j=k;
break;
}
else
{
LL temp=phi/k;//先开始忘记写else这块了。。。
if(quickmod(2,temp,q)==1)
{
if(j==-1)
j=temp;
else if(j>temp)
j=temp;
}
}
}
}
if(j==-1)
j=phi;
printf("Case #%lld: %lld,%lld\n",++cas,i,j);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: