[HDOJ4135]Co-prime
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4135
题意:给一个区间[a,b],再给你一个数n,求在这个区间[a,b]中与n互质的数的个数。
思路:这是一道数学题,如果数据范围不大的话可以直接套用欧拉函数,但是数据范围给得很大。所以用容斥原理来做。
具体思路就是计算[1,a]中与n非互质的数的个数以及[1,b]中与n非互质的数的个数,然后用上限减掉非互质的数的个数,之后作差即可。首先分解n的质因数,接着用一个变量的二进制表示质因数中1的数量,当这个变量是偶数的时候就加,奇数的话就减,因为重复计算了(详解见书《挑战程序设计竞赛P297》)。代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cmath> 5 6 using namespace std; 7 typedef long long LL; 8 9 vector<LL> v; 10 LL a, b; 11 LL n; 12 13 void init() { 14 v.clear(); 15 scanf("%I64d %I64d %I64d", &a, &b, &n); 16 LL nn = (LL)sqrt(n) + 1; 17 for(int i = 2; i < nn; i++) { 18 if(n % i == 0) { 19 v.push_back(i); 20 while(n % i == 0) { 21 n /= i; 22 } 23 } 24 } 25 if(n > 1) { 26 v.push_back(n); 27 } 28 } 29 30 LL solve(LL x, LL y) { 31 LL ans; 32 LL m ,cnt; 33 LL s = 1 << v.size(); 34 for(int i = 1; i < s; i++) { 35 m = 1; 36 cnt = 0; 37 for(int j = 0; j < v.size(); j++) { 38 if(i & (1 << j)) { 39 m *= v[j]; 40 cnt++; 41 } 42 } 43 if(cnt & 1) { 44 ans += x / m; 45 } 46 else { 47 ans -= x / m; 48 } 49 } 50 return x - ans; 51 } 52 int main() { 53 int t; 54 int kase = 1; 55 scanf("%d", &t); 56 while(t--) { 57 init(); 58 LL l, r; 59 l = solve(a-1, n); 60 r = solve(b, n); 61 cout << "Case #" << kase++ << ": " << r - l << endl; 62 } 63 }