题意:求一个区间[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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/qq_15714857/article/details/46972865