容斥原理
对于两个集合,
对于三个集合,
以此类推即可,上式很好理解的
对于容斥原理,可以用二进制枚举,当然dfs也行,这两个复杂度差不多
二进制枚举
对于一个二进制数,每一位只有1和0两种情况,对应着取与不取
举个例子,一共有5件物品,那么最大值就选择(1<<5)-1 = 11111 = 31,如果从00001枚举到11111,也就是1---31,就能把所有情况都枚举出来了
题目
小明做题(一)
Time Limit: 4000/2000ms (Java/Others)
Problem Description:
小明刚上大学,报的是计算机专业,听说acm协会是一个玩思维,玩数学等等的好地方,一向数学成绩优秀的他果断参加了acm笔试,而且最终成绩还不错,便正式成为了一名acmer。有一天晚上,时不时出题人就出了这样一道题:给定一个区间(L,R)(L、R均为正整数)和一个正整数N,求该区间与N互质的数的个数。小明绞尽脑子还是想不出怎么快速解决这道题.请问你能帮助小明解决这道题吗
Input:
输入包含若干组数据。每组数据第一行包含一个T(1 <= T <= 100),表示T个测试样例,接下来的T行中每行包含三个正整数 L 、R 和 N(1 <= L < R <= 10^16,1 <= N <= 10^13)。
Output:
对于每个测试用例,打印L和R之间满足条件的整数个数。注意:每组数据内每个输出之间空一行。请遵循下面的输出格式。
Sample Input:
2
1 10 2
2 12 5
2
10 18 3
12 15 4
Sample Output:
Case #1: 4
Case #2: 7
Case #1: 5
Case #2: 1
找出与n互质的数的个数并相减即可
附上DFS代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <stack>
#include <queue>
using namespace std;
#define ll long long
ll prime[100];
int sum = 0;
ll ans = 0,l,r;
void dfs(int now,ll mul,int num)
{
if(now == sum)
{
if(num %2 == 0 && mul != 1)
ans+=l/mul,ans-=r/mul;
else if(mul != 1)
ans-=l/mul,ans+=r/mul;
return;
}
//cout << ans << endl;
dfs(now+1,mul*prime[now],num+1);
dfs(now+1,mul,num);
}
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
for(int cas = 1;cas <= t;cas++)
{
ll n;
sum = 0;
ans = 0;
scanf("%lld%lld%lld",&l,&r,&n);
r--;
for(ll j = 2;j*j<=n;j++){
if(n%j==0){
prime[sum++]=j;
while(n%j==0) n/=j;
}
}
if(n > 1) prime[sum++] = n;
dfs(0,1,0);
printf("Case #%d: %lld\n", cas,r-l-ans);
if(cas != t)
printf("\n");
}
}
//cout << "AC" <<endl;
return 0;
}
附上二进制枚举代码:
#include <stdio.h>
#define ll long long
ll prime[25];
ll l,r;
int sum;
ll solve()
{
ll ans = 0;
for(int i = 1;i < (1<<sum);i++){
ll tp = 1;
int temp = 0;
for(int j = 0;j < sum;j++)
if((1<<j)&i){
temp++;
tp*=prime[j];
}
if(temp&1) ans-=l/tp,ans+=r/tp;
else ans+=l/tp,ans-=r/tp;
}
return ans;
}
int main(){
int t;
while(scanf("%d",&t) !=EOF){
for(int cas = 1;cas<=t;cas++){
sum = 0;
ll n;
scanf("%lld%lld%lld",&l,&r,&n);
r--;
for(ll j = 2;j*j<=n;j++){
if(n%j==0){
prime[sum++]=j;
while(n%j==0) n/=j;
}
}
if(n > 1) prime[sum++] = n;
printf("Case #%d: %lld\n", cas,r-l-solve());
if(cas != t) printf("\n");
}
}
//cout << "AC" <<endl;
return 0;
}

本文介绍了容斥原理在解决集合问题中的应用,探讨了如何使用二进制枚举和深度优先搜索(DFS)方法,并结合实例展示了这两种方法在解决实际问题时的等效性。同时,提供了一个关于寻找与特定数互质的数的题目,附带了DFS和二进制枚举的代码实现。
13万+

被折叠的 条评论
为什么被折叠?



