zz: http://www.strongczq.com/2012/04/srm540-div2-3-fractionindifferentbases.html
题目原文:http://community.topcoder.com/stat?c=problem_statement&pm=11135&rd=14732
题目原文:http://community.topcoder.com/stat?c=problem_statement&pm=11135&rd=14732
题目大意:
在正整数区间[A,B]内有多少个满足一下条件的的正整数X:给定正整数P和Q,P/Q所表示的有理数用X进制表示是一个无限循环小数。
数据规模:P为[0,10^12], Q为 [1, 10^12], A和B均为[2,10^18], A<=B
思路:
该问题的解题关键是观察到以下数学性质:如果P和Q互质,那么有理数P/Q在X进制下可以表示成有限小数的充要条件是X拥有Q的所有质因子。
根据该性质,我们首先需要令Q=Q/gcd(Q,P),使得有理数的分数形式最简化。然后计算Q的所有质因子,X拥有Q所有质因子等价于X是这些质因子乘积的倍数。令所有质因子的乘积为product,那么A,B之间为product倍数的X都会使得P/Q表示成有限小数,相反的其他所有数都使得P/Q为无限循环小数。整个算法的计算瓶颈在于计算Q的质因子上,下面例程中该部分的计算复杂度为O(sqrt(Q)),在题目给定的数据规模下没有问题。
证明:如果P和Q互质,那么有理数P/Q在X进制下可以表示成有限小数的充要条件是X拥有Q的所有质因子。
充分性:
假设P/Q所表示成的有限小数的小数部分为:
d1/X + d2/X^2 + d2/X^3 + ... + dk/X^k
则P/Q乘以X^k之后将变成整数,即P*(X^k)/Q为整数。由于P和Q互质,那么X^k为Q的倍数,X显然必须拥有Q的所有质因子。
必要性:
假设存在一个拥有Q所有质因子的X使得P/Q不是有限小数(显然Q>=2),那么必然是无限循环小数,假设小数部分为:
d1 ... di d(i+1) ... d(i+k)
d
(i+1)
... d
(i+k)
d
(i+1)
... d
(i+k)
...
即i+1到i+k之间是循环体,那么当n为非负整数时所有有理数(X^(i+k*n))*P/Q都具有相同的小数部分(循环体部分)。分别取n为0和足够大的整数N,则(X^(i+k*N))×P/Q-(X^i)*P/Q为整数,即(X^i)*(X^(k*N)-1)*P/Q为整数。显然(X^i)不会是Q的倍数,那么另Q'=Q/gcd(Q,
X^i
),则得到以下结论:
X^(k*N)-1是Q'的倍数
由于X也拥有Q'的所有质因子,当N足够大时有以下结论:
X^(k*N)是Q'的倍数
根据以上两个结论有1是Q'的倍数,显然这是不可能的。所以假设不成立,原命题成立。
Java代码:
public class FractionInDifferentBases {
private long getFactorProduct(long Q) {
long product = 1;
for (long i = 2; i * i <= Q; ++i) {
boolean ok = false ;
while (Q % i == 0) {
Q /= i;
ok = true;
}
if(ok){
product *= i;
}
}
if(Q != 1){
product *= Q;
}
return product;
}
private long gcd(long a, long b){
return b == 0 ? a : gcd(b, a % b);
}
public long getNumberOfGoodBases(long P, long Q, long A, long B) {
Q /= gcd(P, Q);
if (Q == 1) {
return 0;
}
long product = getFactorProduct(Q);
long total = B - A + 1;
if(A % product != 0){
A = A + product - A % product;
}
long bad = B >= A ? (B - A) / product + 1 : 0;
return total - bad;
}
}