题目链接: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

题解:主要使用了容斥原理,但是在实现容斥原理代码中需要特殊考虑数值类型范围,处理爆范围情况。
 #include <cstdio>

 #define ll long long
using namespace std;
long long p[];
int k; ////容斥原理, solve 函数解出 [1,r] 中不包含 p 中所有因子的个数
long long solve(unsigned long long r) {
long long sum = ;
//共有 2^k 方钟组合
for (int i = ; i < ( << k); ++i) {
long long mult = , bits = ;
for (int j = ; j < k; ++j)
if (i&( << j)) {//与i的二进制的第j位比较,看是否为1,是则选中
bits++;//计算i中1的个数,也就是质因数的个数
mult *= p[j];
//注意 Mult 会爆 long long ,
//超出范围最高为可能为0,也可能为1,在截断为 long long 型后,必须处理才能保证正确定
if (mult > r || mult < ) mult = ;
}
if (mult &&(bits & ))//若1的个数是奇数则进行加法,否则进行减法
sum += r / mult;
else if(mult) sum -= r / mult;
}
return r - sum;//用总的数目-与n不互素的个数
} //这种解法不需要处理爆 long long 的情况
//long long solve(long long t) {
// int g = 1, i;
// long long temp1 = t;
// int count;
// while (g<(1<<k)) {
// count = 0;
// long long temp = temp1;
// for (i = 0; i < k; i++) {
// if (g&(1 << i)) {
// temp /= p[i];
// count++;
// }
// }
// if (count % 2 == 0) t += temp;
// else t -= temp;
// g++;
// }
// return t;
//} int main()
{
long long l, r;
int c = ;
scanf("%lld %lld %d", &l, &r, &k);
for (int i = ; i < k; i++)
{
scanf("%lld", &p[i]);
} long long flag = ;
for (int i = ; i < k; i++) {
if (l%p[i] == ) flag = ;
}
printf("%lld", solve(r) - solve(l) + flag);
return ;
}
05-22 00:39