[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 }

 

posted @ 2015-08-17 15:08  Kirai  阅读(334)  评论(0编辑  收藏  举报