problem
Description
给出n个数a1,a2……an,求区间[L,R]中有多少个整数不能被其中任何一个数整除。
Input
第一行三个正整数,n,L,R。
第二行n个正整数a1,a2……an
Output
一个数,即区间[L,R]中有多少个整数不能被其中任何一个数整除。
Sample Input
2 1 1000
10 15
Sample Output
867
Data Constraint
对于30%的数据,1<=n<=10,1<=L,R<=1000
对于100%的数据,1<=n<=18,1<=L,R<=10^9
analysis
设ans(x)表示1~x中有多少个整数不能被a1,a2……an其中任何一个数整除的个数
这种题目的套路是一样的,都是求ans(r)−ans(l−1),于是考虑怎么求ans
通过容斥原理我们知道,1~n中能被x整除的数个数是⌊n/x⌋ ,能被y整除的数的个数是⌊n/y⌋,而能被(x,y)整除的数的个数是 ⌊n/(x,y)⌋
所以对于x和y两个数而言,ans(n)=n−(⌊n/x⌋+⌊n/y⌋−⌊n/(x,y)⌋)
如果再还有一个约数z呢?那么——
ans(n)=n−(⌊n/x⌋+⌊n/y⌋+⌊n/z⌋−⌊n/(x,y)⌋−⌊n/(x,z)⌋−⌊n/(y,z)⌋+⌊n/(x,y,z)⌋)
所以,我们使用dfs把所有约数组合的情况搞出来
若所有已选的约数个数为奇数ans就减所有数的lcm,否则ans就加上lcm
总体时间复杂度为O(2∗2n))(因为需要用两次递归)
code
#include<cstdio>
#include<algorithm>
using namespace std;
int a[20];
int n,l,r,ans;
int gcd(int x,int y)
{
return x%y==0?y:gcd(y,x%y);
}
inline void dfs(int m,int lcm,int v)
{
if (m>n)
{
ans+=v/lcm;
return;
}
dfs(m+1,lcm,v);
long long t=-1ll*a[m]/gcd(abs(lcm),a[m])*lcm;
if(abs(t)<=v)dfs(m+1,t,v);
}
int solve(int x)
{
ans=0;
dfs(1,1,x);
return ans;
}
int main()
{
scanf("%d%d%d",&n,&l,&r);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
printf("%d",solve(r)-solve(l-1));
return 0;
}