题目:
http://poj.org/problem?id=3358
这一题很经典。
题解:源于http://www.cnblogs.com/ACKOKO/articles/2119216.html
这里讲一下2^i*(2^(j-i)-1)%q==0,为什么将q中的2的个数是i,因为2^i中的i要尽量小(i是循环的前一位,题目要求i要小),并且要满足去除q中所有的2,所以i要等于q中的2的个数。
源代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
int cnt;
int m,n,d;
int factor[1000000];
int gcd(int a,int b)
{
if(b==0) return a;
return gcd(b,a%b);
}
int euler(int m)
{
int s=m;
for(int i=2;i*i<=m;i++)
{
if(m%i==0)
{
while(m%i==0) {m=m/i;}
s=s/i*(i-1);
}
}
if(m>1)
s=s/m*(m-1);
return s;
}
ll quickPow(int b,int m)
{
ll s=1,a=2;
while(b>0)
{
if(b%2==1) s=s*a%m;
a=a*a%m;
b=b/2;
}
return s;
}
int solve(int m)
{
int flag=0,y,k=0;
int sum,x=euler(m);
if(x==1) return 1;
for(int i=2;i*i<=x;i++)
if(x%i==0)
{
factor[k++]=i;
factor[k++]=x/i;
}
sort(factor,factor+k);
for(int i=0;i<k;i++)
{
sum=quickPow(factor[i],m);
if(sum==1)
{
y=factor[i];
flag=1;
break;
}
}
if(!flag) y=x;
return y;
}
int main(){
int cas=1;
while(scanf("%d/%d",&n,&m)!=EOF)
{
cnt=1;
d=gcd(n,m);
n=n/d; m=m/d;
while(m%2==0)
{
m=m/2;
cnt++;
}
printf("Case #%d: %d,%d\n",cas++,cnt,solve(m));
}
return 0;
}