poj 3358
好题,好解。
//这道题就是求一个分数的2进制小数的循环节长度和起始位置。 // 首先,先对该分数 n/m 化简。 // n = n / gcd(n, m) // m = m / gcd(n, m) // n = n mod m // 接下来就是需要知道一个分数化成k进制小数的方法: // for i = 0 to 需要的位数 // n = n * k; // bit[i] = n / m; // n = n mod m; // 可以知道对于某一位的n,设为ni,当到了某一位nj,有ni mod m== nj mod m 时,此时循环节就出现了,长度L = j - i。 // 而aj = (ai * 2 ^ L) mod m 可得 2 ^ L mod m == 1 mod m 。 // 当m与2互质时,由于2 ^ 0 == 1 mod m,2 ^ phi(m) == 1 mod m,循环节的起始点一定为0,即答案的1。 // .而这里m与2不一定互质,可以通过两边同时消去2的t次幂来达到这个条件,即2 ^ (L - t) == 1 mod (m / 2 ^ t)。 // 可见此时循环节起始点为t,即答案为t + 1。 // 剩下的就是求2 ^ L' = 1 mod m' 了,由于若2 ^ k == 1 mod m',则k整除phi(m'),所以我们可以从小到大枚举phi(m')的因子,即可得到答案。
//============================================================================ // Name : 3358.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ //这道题就是求一个分数的2进制小数的循环节长度和起始位置。 // 首先,先对该分数 n/m 化简。 // n = n / gcd(n, m) // m = m / gcd(n, m) // n = n mod m // 接下来就是需要知道一个分数化成k进制小数的方法: // for i = 0 to 需要的位数 // n = n * k; // bit[i] = n / m; // n = n mod m; // 可以知道对于某一位的n,设为ni,当到了某一位nj,有ni mod m== nj mod m 时,此时循环节就出现了,长度L = j - i。 // 而aj = (ai * 2 ^ L) mod m 可得 2 ^ L mod m == 1 mod m 。 // 当m与2互质时,由于2 ^ 0 == 1 mod m,2 ^ phi(m) == 1 mod m,循环节的起始点一定为0,即答案的1。 // .而这里m与2不一定互质,可以通过两边同时消去2的t次幂来达到这个条件,即2 ^ (L - t) == 1 mod (m / 2 ^ t)。 // 可见此时循环节起始点为t,即答案为t + 1。 // 剩下的就是求2 ^ L' = 1 mod m' 了,由于若2 ^ k == 1 mod m',则k整除phi(m'),所以我们可以从小到大枚举phi(m')的因子,即可得到答案。 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; int t, n, m, GCD, phi, ans1, ans2; int temp, num; int fac[1000000]; int gcd(int x, int y){ int r; if(x < y){ swap(x, y); } while(x%y){ r = x%y; x = y; y = r; } return y; } int euler(int x){ int y = (int)sqrt(x+0.5); int curans = x; for(int i = 2;i <= y;i++){ if(x%i == 0){ curans = curans/i*(i-1); while(x%i == 0){ x /= i; } } } if(x > 1){ curans = curans/x*(x-1); } return curans; } int quickpow(int m, int n, int k){ int b = 1; while(n > 0){ if(n&1){ b = (long long)b*m%k; } n >>= 1; m = (long long)m*m%k; } return b; } int main(){ // printf("%d\n", euler(5)); freopen("a.txt", "r", stdin); int T = 0; while(scanf("%d/%d", &n, &m)!=EOF){ T++; GCD = gcd(n, m); // printf("%d\n", GCD); n /= GCD; m /= GCD; // printf("%d %d\n", n, m); t = 0; while(m%2 == 0){ t++; m /= 2; } ans1 = t+1; phi = euler(m); if(phi == 1){ ans2 == 1; } else{ num = 0; for(int i = 1;i*i <= phi;i++){ if(phi%i == 0) { fac[num++] = i; fac[num++] = phi/i; } } sort(fac, fac+num); // printf("%d\n", num); for(int i = 0;i < num;i++){ // printf("%d\n", fac[i]); temp = quickpow(2, fac[i], m); // printf("i: %d phi: %d %d\n", i, phi, temp); if(temp == 1){ // printf("%d\n\n", ans2); ans2 = fac[i]; break; } } } printf("Case #%d: ", T); printf("%d,%d\n", ans1, ans2); } return 0; }