牛客小白月赛5 A 无关(relationship) 【容斥原理】【数据范围处理】

题目链接:https://www.nowcoder.com/acm/contest/135/A

题目描述 

  若一个集合A内所有的元素都不是正整数N的因数,则称N与集合A无关。

  给出一个含有k个元素的集合A={a1,a2,a3,...,ak},求区间[L,R]内与A无关的正整数的个数。
  保证A内的元素都是素数。

输入描述:

输入数据共两行:

第一行三个正整数L,R,k,意义如“题目描述”。

第二行k个正整数,描述集合A,保证k个正整数两两不相同。

输出描述:

输出数据共一行:

第一行一个正整数表示区间[L,R]内与集合A无关的正整数的个数
示例1

输入

复制
1 10 4
2 3 5 7

输出

复制
1
示例2

输入

复制
2 10 4
2 3 5 7

输出

复制
0

说明

对于30%的数据:1<=L<=R<=10^6

对于100%的数据:1<=L<=R<=10^18,1<=k<=20,2<=ai<=100


题解:主要使用了容斥原理,但是在实现容斥原理代码中需要特殊考虑数值类型范围,处理爆范围情况。
 1 #include <cstdio>
 2 
 3 #define ll long long
 4 using namespace std;
 5 long long p[20];
 6 int k;
 7 
 8 ////容斥原理, solve 函数解出 [1,r] 中不包含 p 中所有因子的个数 
 9  long long  solve(unsigned long long r) {
10     long long sum = 0;
11     //共有 2^k 方钟组合
12     for (int i = 1; i < (1 << k); ++i) {
13          long long  mult = 1, bits = 0;
14         for (int j = 0; j < k; ++j)
15             if (i&(1 << j)) {//与i的二进制的第j位比较,看是否为1,是则选中
16                 bits++;//计算i中1的个数,也就是质因数的个数
17                 mult *= p[j];
18                 //注意 Mult 会爆 long long ,
19                 //超出范围最高为可能为0,也可能为1,在截断为 long long 型后,必须处理才能保证正确定
20                 if (mult > r || mult < 0) mult = 0;
21             }
22         if (mult &&(bits & 1))//若1的个数是奇数则进行加法,否则进行减法
23             sum += r / mult;
24         else if(mult) sum -= r / mult;
25     }
26     return r - sum;//用总的数目-与n不互素的个数
27 }
28 
29 
30  //这种解法不需要处理爆 long long 的情况
31 //long long solve(long long t) {
32 //    int g = 1, i;
33 //    long long temp1 = t;
34 //    int count;
35 //    while (g<(1<<k)) {
36 //        count = 0;
37 //        long long temp = temp1;
38 //        for (i = 0; i < k; i++) {
39 //            if (g&(1 << i)) {
40 //                temp /= p[i];
41 //                count++;
42 //            }
43 //        }
44 //        if (count % 2 == 0) t += temp;
45 //        else t -= temp;
46 //        g++;
47 //    }
48 //    return t;
49 //}
50 
51 int main()
52 {
53     long long l, r;
54     int c = 0;
55     scanf("%lld %lld %d", &l, &r, &k);
56     for (int i = 0; i < k; i++)
57     {
58         scanf("%lld", &p[i]);
59     }
60 
61     long long  flag = 1;
62     for (int i = 0; i < k; i++) {
63         if (l%p[i] == 0) flag = 0;
64     }
65     printf("%lld", solve(r) - solve(l) + flag);
66     return 0;
67 }

 

posted @ 2018-07-23 00:51  佰大于  阅读(404)  评论(0编辑  收藏  举报