您的位置:首页 > 其它

UVA 10325 lottery 容斥原理

2012-11-18 15:50 513 查看
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=15&problem=1266&mosmsg=Submission+received+with+ID+9619336

题意: 给定 n,m 和 m 个数 ,求 1~n 中 不能 能被 m个数中的任意 一个数整除 的个数

题解:

首先明白对于集合[1,n]内能被a整除的数的个数为n/a,既能被a整除又能被b整除的数的个数为n/lcm(a,b)(a,b的最小公倍数);

容斥原理地简单应用。先找出1...n - 1内能被集合M中任意一个元素整除的个数,再减去能被集合中任意两个整除的个数,即能被它们俩的最小公倍数整除的个数,因为这部分被计算了两次,然后又加上三个时候的个数,然后又减去四个时候的倍数...直接枚举状态0...(1<<m),然后判断状态内涵几个集合元素,然后计算lcm和能被整除的个数,最后判断下集合元素的个数为奇还是偶,奇加偶减。这里回溯搜索M元素的组合也行

1 #include<cstdio>
2 #include<cstring>
3 #include<cmath>
4 #include<iostream>
5 #include<algorithm>
6 #include<set>
7 #include<map>
8 #include<queue>
9 #include<vector>
#include<string>
#define inf 0x7fffffff
#define maxn 60000
#define CL(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
ll n , m ;
ll a[20] ;
ll gcd(ll a,ll b)
{

if(b == 0) return a;

return gcd(b,a%b) ;

}
ll lcm(ll a,ll b)
{
ll d = gcd(a,b) ;

return a*b/d ;
}
int main()
{
int i ;
while(scanf("%lld%lld",&n,&m)!=EOF)
{
ll ans= 0 ;
for(i = 0 ;i < m;i++ )
{
scanf("%lld",&a[i]) ;

}

ll sum = 0 ;
for(ll msk = 1 ; msk < (1<< m); msk++)// 所有的情况
{

ll mul = 1;

ll bits = 0 ;

for(int j = 0 ; j < m;j++)
{

if(msk & (1 << j))
{

bits ++ ;
mul = lcm(mul, a[j]) ;
if(mul > n)break ;

}

}

if(mul > n) continue ;

ll cur = n/mul ;

if(bits & 1 )
{
sum += cur ;
}
else sum -= cur ;

}

printf("%lld\n",n - sum ) ;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: