链接:https://ac.nowcoder.com/acm/problem/16513
来源:牛客网
无关(relationship)
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
若一个集合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
复习一波容斥,容斥的公式就是
那么,只要这个数不是所有因子的整数倍,就是我们想要的答案。
不过一个个找肯定不行,因为保证所有数都是素数,所以一个区间内素数的倍数个数为N/Ai,那枚举子集,求得乘积,即可得到答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int maxn=22;
ll a[maxn];
ll l,r,k;
ll solve(ll R){
ll ans=0;
for(int i=1;i<(1<<k);i++){
ll mult=1,bits=0;
for(int j=0;j<k;j++){
if(i&(1<<j)){
bits++;
mult*=a[j];
}
if(mult>R||mult<0)mult=0;//即时剪枝
}
if(mult&&(bits&1)){//奇数为+
ans+=R/mult;
}
else if(mult){
ans-=R/mult;
}
}
return R-ans;//[1,R]内与A无关的数的个数
}
int main(){
while(scanf("%lld%lld%lld",&l,&r,&k)!=EOF){
for(int i=0;i<k;i++){
scanf("%lld",&a[i]);
}
ll flag=1;
for(int i=0;i<k;i++){
if(l%a[i]==0){
flag=0;
}
}
printf("%lld\n",solve(r)-solve(l)+flag);
}
return 0;
}