题目传送门:点击打开链接
题目大意:给一个整数n,再给出m个整数,求1-n中不能被这m个整数整除的个数。
首先我们要知道 设 a为整数且a<=n,那么1-n 能被a整数的个数 为 n/a;
然后我们再利用集合的公式:
不知道 看点击打开链接百度百科
上面这两个式子都一样,接下来我们用dfs或二进制枚举A∩B∩C.......等就可以了 注:设A,B,C的公倍数c,那么A∩B∩C 其实就等于 n/c。
我把dfs枚举和二进制枚举 写在一个代码里啦。
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll n,m;
ll mi[20];ll nn;
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
void init()
{
cin>>m;
for(int i=0;i<m;++i)
{
cin>>mi[i];
for(int j=0;j<i;++j)
{
ll c=gcd(mi[j],mi[i]);
if(c==mi[j]||c==mi[i])
{
mi[j]=c;
--m;
--i;
}
}
}
/* cout<<m<<endl;
for(int i=0;i<m;++i)
cout<<mi[i]<<" ";
cout<<endl;*/
}
void dfs(int num,int tol,ll sum,int i)
{
if(sum>n)
return;
if(num==tol)
{
nn+=n/sum;
// cout<<nn<<" "<<sum<<" "<<num<<endl;
return;
}
if(i>=m)
return;
dfs(num,tol,sum,i+1);
dfs(num+1,tol,sum/gcd(sum,mi[i])*mi[i],i+1);
}
/*void solve() //dfs枚举
{
ll ans=0;
for(int i=1;i<=m;++i)
{
nn=0;
dfs(0,i,ll(1),0);
// cout<<i<<" "<<nn<<endl;
if(i&1)
ans+=nn;
else
ans-=nn;
}
cout<<n-ans<<endl;
}*/
void solve() //二进制枚举
{
int s=1<<m;ll tol=0;
for(int i=1;i<s;++i)
{
ll sum=1,cnt=0;
for(int j=0;j<m;++j)
{
if(i&(1<<j))
{
++cnt;
sum=sum/(gcd(sum,mi[j]))*mi[j];
if(sum>n)
break;
}
else if((1<<j)>i)
break;
}
if(cnt&1)
tol+=n/sum;
else
tol-=n/sum;
}
cout<<n-tol<<endl;
}
int main(int argc, const char * argv[])
{
while(cin>>n)
{
init();
solve();
}
return 0;
}