您的位置:首页 > 其它

hdu 1796 How many integers can you find 容斥原理

2016-08-03 10:48 507 查看
传送门:hdu 1796 How many integers can you find

题目大意

在M个集合中,找到能被N整除(不包含N)的个数

解题思路

首先要解决这个题目要知道什么容斥定理!

我们先假设N=100,然后M=3其中M集合中的元素为{1,2,3}

如果我们直接计算N/a1 = 100,N/a2=50,N/a3 = 33,在计算前两个的时候,N/a2这么多个元素就是多余的,在计算后面两个的时候我们会发现lcm(a2,a3)中也是公共部分需要减去的!

例子的展示图如下:



假设Ai(1<=i<=M)是X的一些子集,我们要求|⋃ Ai|,例如在上面的问题中,就可以看为Ai = {N|N可以整除ai},然后就能的到容斥原理的一般公式



容斥原理简单来说就是奇加偶减!

偶减是减去任意偶数个集合的交集!

奇加是加上任意奇数个集合的交集!

上面的两句话就解释了容斥原理那个公式!

我们把M个元素变为1~((1<

long long solve()
{
long long res = 0;
for(int i=1; i<(1<<M); i++)
{
int num = 0;
for(int j=i; j!=0; j>>=1) num += j&1;//判断有几个集合
long long lcm = 1;
/*求num个集合的最小公倍数*/
for(int j=0; j<M; j++)
if(i>>j&1)
{
lcm = lcm/gcd(lcm,a[j])*a[j];
if(lcm>N) break;
}
//奇加偶减
if(num%2 == 0)res -= (N/lcm);
else res+=(N/lcm);
}
return res;
}


AC代码

#include<cstdio>
#include<cstring>
int N,M,a[28];
long long gcd(long long a,long long b) //求最大公约数函数
{
if (a%b==0) return b;
else return gcd(b,a%b); //辗转相除法
}

long long solve() { long long res = 0; for(int i=1; i<(1<<M); i++) { int num = 0; for(int j=i; j!=0; j>>=1) num += j&1;//判断有几个集合 long long lcm = 1; /*求num个集合的最小公倍数*/ for(int j=0; j<M; j++) if(i>>j&1) { lcm = lcm/gcd(lcm,a[j])*a[j]; if(lcm>N) break; } //奇加偶减 if(num%2 == 0)res -= (N/lcm); else res+=(N/lcm); } return res; }

int main()
{

while(scanf("%d%d",&N,&M))
{
for(int i=0; i<M; i++)
{
scanf("%d",&a[i]);
if(!a[i])
{
i--;
M--;
}
}
if(N<=2)
{
puts("0");
continue;
}
N--;
printf("%lld\n",solve());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: