首先要明确分式的二进制表达方式:
1 //supposing the fraction is a / b, (a < b && (a, b)) 2 //its binary expression is denoted as : 0.bit[1]bit[2]... 3 seed[0] = a;
4 for(int i = 1; ; i++){ 5 bit[i] = (seed[i - 1] << 1) / b; 6 seed[i] = (seed[i - 1] << 1) % b;
7 }
不妨设其中一个循环节为bit[r]..bit[s],显然有seed[r - 1] = seed[s] 且bit[r] = bit[s + 1],其中循环节长度l = (s - r + 1)。
由seed[i] = 2i+1 % b, 则有 2r % b = 2s+1 % b, 即2r(2s-r+1-1) ≡ 0(modb),
记b = 2t*b1,其中 (b1,2),且令r = t,则 2l≡ 1(modb1)。
则l|φ(b1),由此枚举b1的约数即可得到周期l。
并且有初始位置p = t + 1 。
http://poj.org/problem?id=3358
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 typedef __int64 LL; 7 const int maxn = 1e2 + 10; 8 int prime[maxn], k; 9 int fac[maxn]; 10 int a, b, B; 11 12 int power(int a, int p){ 13 a %= B; 14 int ans = 1; 15 while(p){ 16 if(p & 1) ans = (LL)ans * a % B; 17 p >>= 1; 18 a = (LL)a * a % B; 19 } 20 return ans; 21 } 22 23 int gcd(int a, int b) { return !b ? a : gcd(b, a % b); } 24 25 void solve(){ 26 a %= b; 27 int d = gcd(a, b); 28 a /= d, b /= d; 29 int t = 0; 30 while(b % 2 == 0) b /= 2, ++t; 31 printf("%d,", ++t); 32 if(b == 1) { printf("%d ",1); return; } 33 k = 0; 34 B = b; 35 int phi = b; 36 int mid = (int)sqrt(b); 37 for(int i = 3; i <= mid; i += 2){ 38 if(b % i == 0){ 39 prime[k++] = i; 40 while(b % i == 0) b /= i; 41 } 42 } 43 if(b != 1) prime[k++] = b; 44 for(int i = 0; i < k; i++) phi /= prime[i]; 45 for(int i = 0; i < k; i++) phi *= (prime[i] - 1); 46 k = 0; 47 for(int i = 1; i * i <= phi; i++){ 48 if(phi % i == 0) fac[k++] = i, fac[k++] = phi / i; 49 } 50 sort(fac, fac + k); 51 for(int i = 0; i < k; i++) if(power(2, fac[i]) == 1){ 52 printf("%d ", fac[i]); 53 break; 54 } 55 } 56 57 int main(){ 58 //freopen("in.txt", "r", stdin); 59 int kase = 0; 60 while(~scanf("%d/%d", &a, &b)){ 61 printf("Case #%d: ", ++kase); 62 solve(); 63 } 64 return 0; 65 }