题意:求一个区间[a,b]中有多少个与n互素的数。
思路:
这道题是容斥原理的模板题之一,容斥原理请参考容斥原理详述,很好的一篇文章。
[a,b]中与n互素的数目可转化为[1,b]-[1,a-1]的数目。
给出整数n和r。求区间[1;r]中与n互素的数的个数的方法:
解决它的逆问题,求不与n互素的数的个数。
考虑n的所有素因子pi(i=1…k)
在[1;r]中有多少数能被pi整除呢?它就是:
然而,如果我们单纯将所有结果相加,会得到错误答案。有些数可能被统计多次(被好几个素因子整除)。所以,我们要运用容斥原理来解决。
我们可以用o(2^k)的算法求出所有的pi组合,然后计算每种组合的pi乘积,通过容斥原理来对结果进行加减处理。
code:
/*
*Author : Flint_x
*Created Time : 2015-07-20 13:22:56
*File name : whust1_H.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define cls(a) memset(a,0,sizeof(a))
#define rise(i,a,b) for(int i = a ; i <= b ; i++)
#define fall(i,a,b) for(int i = a ; i >= b ; i--)
vector<lint> p;
lint solve (lint n, lint r) {
p.clear();
for (lint i=2; i*i<=n; ++i)
if (n % i == 0) {
p.push_back (i);
while (n % i == 0)
n /= i;
}
if (n > 1)
p.push_back (n);
lint sum = 0;
for (lint msk=1; msk<(1<<p.size()); ++msk) {
lint mult = 1,bits = 0;
for (lint i=0; i<(lint)p.size(); ++i)
if (msk & (1<<i)) {
mult *= p[i];
bits++;
}
lint cur = r / mult;
// cout << cur << endl;
if (bits % 2 == 1)
sum += cur;
else
sum -= cur;
}
return r - sum;
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
int T;
cin >> T;
rise(kase,1,T){
lint a,b,n;
cin >> a >> b >> n;
lint ans = solve(n,b) - solve(n,a-1);
cout << "Case #" << kase << ": " << ans << endl;
}
return 0;
}