您的位置:首页 > 其它

POJ-3358Period of an Infinite Binary Expansion

2015-08-18 20:21 417 查看

题目:

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

题意:

给出一个分数,求该分数的小数部分循环节起点与长度。

思路:

相当神奇的一道题,真真是毫无思路。

挣扎无果之后看网上的解题报告也是混乱,后来看到一个写得比较清楚的终于豁然开朗:

/article/7807290.html

简单地说就是利用欧拉定理

//欧拉定理:a与p互质,a^x==1(mod p)则x==euler[p];
具体解法是,首先取gcd(n,m)化为真分数,

当出现循环节时有:n*2^i==n*2^j(mod m),消去n,可以变换为:2^i*(2^(j-i)-1)==0(mod m).

因为(2^(j-i)-1)是奇数,所以取m对于2的幂就是i,也就求出了循环节起点。

之后再利用欧拉定理(j-i)==eulur[m],取eulur[m]所有因子枚举找出最小循环节就行了。

代码:

long long n,m;
long long flag,ave,ans,res,len,ans1,ans2;

long long modMul(long long a,long long b,long long n)
{
long long res = 0;
while(b)
{
if(b&1)    res = (res + a) % n;
a = (a + a) % n;
b >>= 1;
}
return res;
}
long long modExp(long long x,long long k,long long mod)
{
long long ans = 1;
while(k)
{
if(k & 1) ans = modMul(ans, x, mod);
x = modMul(x, x, mod);
k >>= 1;
}
return ans;
}
long long factor[1000];
int sum;

long long gcd(long long a,long long b)
{
if(a==0)return 1;
if(a<0) return gcd(-a,b);
while(b)
{
long long t=a%b;
a=b;
b=t;
}
return a;
}
void fact( long long x )
{
sum = 0;
for ( long long i = 2; i * i <= x; i++ )
if ( x % i == 0 )
factor[sum++] = i, factor[sum++] = x / i;
}
long long euler(long long n)
{
long long res=n,a=n;
for(long long i=2;i*i<=a;i++)
if(a%i==0)
{
res=res/i*(i-1);
while(a%i==0) a/=i;
}
if(a>1) res=res/a*(a-1);
return res;
}
int main()
{
long long i,j,k,kk,t,x,y,z;
kk=0;
while(scanf("%lld/%lld",&n,&m)!=EOF)
{
if(!n)
{
printf("Case #%lld: 1,1\n",++kk);
continue;
}
t=gcd(n,m);
n/=t;m/=t;
res=1;
while(m%2==0)m/=2,res++;

ans=euler(m);
fact(ans);
sort(factor,factor+sum);
factor[sum++]=ans;
for(i=0;i<sum;i++)
if(modExp(2,factor[i],m)==1)
break;
printf("Case #%lld: %lld,%lld\n",++kk,res,factor[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: