Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2769 | Accepted: 718 |
Description
Let {x} = 0.a1a2a3... be the binary representation of the fractional part of a rational number z. Suppose that {x} is periodic then, we can write
{x} = 0.a1a2...ar(ar+1ar+2...ar+s)w
for some integers r and s with r ≥ 0 and s > 0. Also, (ar+1ar+2...ar+s)wdenotes a nonterminating and repeating binary subsequence of {x}.
The subsequence x1 = a1a2 ... aris called the preperiod of {x} and x2 = ar+1ar+2 ... ar+s is the period of {x}.
Suppose that |x1| and |x2| are chosen as small as possible then x1 is called the least preperiod and x2 is called the least period of {x}.
For example, x = 1/10 = 0.0001100110011(00110011)w and 0001100110011 is a preperiod and 00110011 is a period of 1/10.
However, we can write 1/10 also as 1/10 = 0.0(0011)w and 0 is the least preperiod and 0011 is the least period of 1/10.
The least period of 1/10 starts at the 2nd bit to the right of the binary point and the the length of the least period is 4.
Write a program that finds the position of the first bit of the least period and the length of the least period where the preperiod is also the minimum of a positive rational number less than 1.
Input
Each line is test case. It represents a rational number p/q where p and q are integers, p ≥ 0 and q > 0.
Output
Each line corresponds to a single test case. It represents a pair where the first number is the position of the first bit of the least period and the the second number is the length of the least period of the rational number.
Sample Input
1/10 1/5 101/120 121/1472
Sample Output
Case #1: 2,4 Case #2: 1,4 Case #3: 4,4 Case #4: 7,11
题意:给出小数p/q的十进制表示,求当p/q的结果化为二进制的小数时,使p/q的循环节和非循环节都最短时,循环节开始的位置和循环节的长度。
思路:以下的discuss的做法:
我们可以观察一下1/10这组数据,按照二进制转换法(乘二法),我们可以得到:
1/10 2/10 4/10 8/10 16/10 32/10 ...
然后都分子都尽可能减去10,得到:
1/10 2/10 4/10 8/10 6/10 2/10 ...
这时候,发现出现了重复,那么这个重复就是我们要求的最小循环。
抽象出模型如下:对p/q首先p'=p/gcd(p,q)q'=q/gcd(p,q) (即化为最简);
然后我们就是求p'*2^i == p'*2^j (mod q') (“==”表示同余,i<j)
经过变换得到: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'')
而根据欧拉定理,,φ(n)为n的欧拉函数,那么我们要求出的x即为φ(n)的满足2^x%q''=1的最小因子。
AC代码:
#include <iostream> #include <cmath> #include <cstdlib> #include <cstring> #include <cstdio> #include <queue> #include <ctime> #include <algorithm> #define ll __int64 using namespace std; int fac[100005]; int cnt; int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } int euler(int n) { int ret = n; for(int i = 2; i * i <= n; i++) if(n % i == 0) { ret = ret / i * (i - 1); while(n % i == 0) n /= i; } if(n > 1) ret = ret / n * (n - 1); return ret; } void get_factor(int n) { cnt = 0; for(int i = 1; i * i <= n; i++) if(n % i == 0) { fac[cnt++] = i; fac[cnt++] = n / i; } } int Montgomery(int a, int b, int m) { int r = 1; a %= m; while(b) { if(b & 1) r = (long long) r * a % m; a = (long long) a * a % m; b >>= 1; } return r; } int main() { int p, q, c = 0; int ans1, ans2; while(~scanf("%d/%d", &p, &q)) { int GCD = gcd(p, q); p /= GCD; q /= GCD; ans1 = 0; while(q % 2 == 0) { ans1++; q /= 2; } int phi = euler(q); get_factor(phi); sort(fac, fac + cnt); for(int i = 0; i <cnt; i++) if(Montgomery(2, fac[i], q) == 1) { ans2 = fac[i]; break; } printf("Case #%d: %d,%d\n", ++c, ans1 + 1, ans2); } return 0; }