这道题目感觉好难,根本就是无从下手的感觉,尝试了以前的所有方法,都没有思路,毫无进展,参考了一下别人的思路,感觉学到了新的知识
接下来开始分析
观察1/10这组数据,按照二进制转化法可以得到: 1/10 2/104/108/1016/1032/10.……
对于每一个分子进行模10处理 可以相应的得到: 1/102/104/108/106/102/10……
出现了重复,这个重复就是要求的最小循环
对于p/q,首先p'=p/gcd(p,q),q'=q-gcd(p,q),然后求p'*2^i ≡ p'*2^j (mod q'),然后开始变换,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'');因为q''与2是互诉的,所以肯定有解,令 n=q'', 2^φ(n) ≡ 1 (mod n ),由于题目要求的是 最小的x,看似 φ(n) 是最终解,所以不妨 像poj3696那样大胆假设 x其实是 φ(n)的一个因子,推导符合题目要求,再反过来假设x不是φ(n)的因子, 令r=φ(n),mod x,r大于0,同时r<x,注意 2^φ(n) ≡ 1(mod n),且 2^x≡ 1(mod n),所以2^r %n=1,那么就存在一个比x更小的正整数 是的 2^r ≡ 1(mod n),所以 第二个假设失败,所以 x为 φ(n)的因子, 不断的寻找φ(n)的因子 然后判断是否符合题目要求即可
#include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #include<string> #include<queue> #include<stack> #include<map> #include<vector> #include<cmath> #include<memory.h> #include<set> #define ll long long #define eps 1e-8 #define inf 0xfffffff const ll INF = 1ll<<61; using namespace std; //vector<pair<int,int> > G; //typedef pair<int,int > P; //vector<pair<int,int> > ::iterator iter; // //map<ll,int >mp; //map<ll,int >::iterator p; // int a,b,r[112]; int Gcd(int a,int b) { return b==0?a:Gcd(b,a%b); } void detal(int x,int m) { r[0]=x%m; for(int i=1;i<32;i++) r[i]=(ll)r[i-1]*r[i-1]%m; } int quick(int x,int y,int m) { int i=0,ans,j; int d[50]; while(y) { d[i++]=y%2; y>>=1; } for(j=0,ans=1;j<i;++j) if(d[j]) ans=(ll)ans*r[j]%m; return ans; } int main() { int Case=0; char s[102]; while(~scanf("%s",s)) { a=0,b=0; bool flag=false; for(int i=0;i<strlen(s);i++) { if(s[i] != '/' && !flag) a=a*10+s[i]-'0'; else flag=true; if(flag && s[i] != '/') b=b*10+s[i]-'0'; } if(a == 0) { printf("Case #%d: %d,%d\n",++Case,1,1); continue; } int gcd=Gcd(a,b); b/=gcd; int x=0; while(!(b&1)) { b>>=1; x++; } x++; int c[112][2],k=0,a=b,ans=b; for(int i=2;i*i<=a;i++) { if(a%i == 0) { ans-=ans/i; a/=i; while(a%i == 0) a/=i; } } if(a > 1) ans-=ans/a;; a=ans; for(int i=2;i*i<=a;i++) { if(a%i == 0) { c[k][0]=i; c[k][1]=0; c[k][1]++; while(a%i == 0) { c[k][1]++; a/=i; } k++; } } if(a > 1) { c[k][0]=a; c[k][1]=1; k++; } detal(2,b); for(int i=0;i<k;i++) { for(int j=0;j<c[i][1];j++) { if(quick(2,ans/c[i][0],b) != 1) break; ans/=c[i][0]; } } printf("Case #%d: %d,%d\n",++Case,x,ans); } return EXIT_SUCCESS; }