題目: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;}