题目链接: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无关的正整数的个数
示例2
说明
对于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 }