bzoj2839 集合计数

2839: 集合计数

Time Limit: 10 Sec  Memory Limit: 128 MB

Submit: 243  Solved: 129

[Submit][Status][Discuss]

Description

一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得

它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

Input

一行两个整数N,K

Output

一行为答案。

Sample Input

3 2

Sample Output

6

HINT

【样例说明】

假设原集合为{A,B,C}

则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB},{AC},{BC}

【数据说明】

对于100%的数据,1≤N≤1000000;0≤K≤N;

容斥原理

类似bzoj3198的思路,f[i]表示交集的个数至少是i个的方案数,最终答案ans=∑f[i]*C(i,k)*(-1)^(i-k),k≤i≤n。

于是问题转化为如何求f[i]。

加入限制了交集必须有i个数,等于将可选的集合范围缩小到了2^(n-i)个。而每一个集合都是可选可不选的,但是不能全部不选,所以f[i]=2^[2^(n-i)]-1。

可以发现随着i递减,2^[2^(n-i)]每一次都是上一次的平方,然后倒着算就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 1000005
#define mod 1000000007
using namespace std;
int n,k;
ll ans,fac[maxn],inv[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline ll getpow(ll x,ll y)
{
	ll ret=1;
	for(;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;
	return ret;
}
int main()
{
	n=read();k=read();
	fac[0]=1;
	F(i,1,n) fac[i]=fac[i-1]*i%mod;
	inv[0]=1;inv[1]=1;
	F(i,2,n) inv[i]=inv[i-mod%i]*(mod/i+1)%mod;
	F(i,2,n) inv[i]=inv[i]*inv[i-1]%mod;
	ll x=2;
	D(i,n,k)
	{
		if (i!=n) x=x*x%mod;
		ll tmp=fac[n]*inv[n-i]%mod*inv[k]%mod*inv[i-k]%mod;
		ans=(ans+tmp*(x+mod-1)%mod*((i-k)&1?mod-1:1)%mod)%mod;
	}
	printf("%lld\n",ans);
	return 0;
}
时间: 2024-10-25 21:07:39

bzoj2839 集合计数的相关文章

bzoj2839 集合计数(容斥)

2839: 集合计数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 883  Solved: 490[Submit][Status][Discuss] Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得 它们的交集的元素个数为K,求取法的方案数,答案模1000000007.(是质数喔~) Input 一行两个整数N,K Output 一行为答案. Sample Inp

【BZOJ2839】集合计数 组合数+容斥

[BZOJ2839]集合计数 Description 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007.(是质数喔~) Input 一行两个整数N,K Output 一行为答案. Sample Input 3 2 Sample Output 6 HINT [样例说明]假设原集合为{A,B,C}则满足条件的方案为:{AB,ABC},{AC,ABC},{BC,ABC},{AB

51nod 1352:集合计数

1352 集合计数 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 给出N个固定集合{1,N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数. 提示: 对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个. Input 第1行:1

hdu 6092 Rikka with Subset (集合计数,01背包)

Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them: Yuta has n positive A1?An and their sum is m. Then for each subset S of A, Yuta calcula

51nod 1352 集合计数(扩展欧几里得)

题目链接:传送门 题意:略 分析: 非常easy能够得到一个方程 A*x + B*y = N + 1 这式子能够用扩展GCD求出gcd,x和y,然后我们求出大于0的最小x,A*x第一个满足条件的集合firstSet,剩下的N-firstSet个集合能够直接除LCM(A,B)(A和B的最小公倍数)统计出数量. 代码例如以下: #include <stdio.h> #include <string.h> #include <iostream> #define LL long

BZOJ 2839 集合计数 容斥原理

题目大意:给定n个元素,求交集大小为k的集合的集合共有多少种 考虑容斥原理 计算交集大小至少为i的集合有多少种 首先需要选出i个元素 方案为C(n,i) 其它2^(n-i)个集合每个可选可不选 一共2^[2^(n-i)]种 故答案为Σ[k<=i<=n]C(n,i)C(i,k)*2^[2^(n-i)] #include <cstdio> #include <cstring> #include <iostream> #include <algorithm&

51nod 1352 集合计数

给出N个固定集合{1,N},{2,N-1},{3,N-2},...,{N-1,2},{N,1}.求出有多少个集合满足:第一个元素是A的倍数且第二个元素是B的倍数. 提示: 对于第二组测试数据,集合分别是:{1,10},{2,9},{3,8},{4,7},{5,6},{6,5},{7,4},{8,3},{9,2},{10,1}.满足条件的是第2个和第8个. Input 第1行:1个整数T(1<=T<=50000),表示有多少组测试数据. 第2 - T+1行:每行三个整数N,A,B(1<=N

51 Nod 1352 集合计数(中国剩余定理+扩展欧几里得)

题目链接:点我点我 题意:中文题 题解:由题意我们可以构造出方程:Ax+By=N+1,用扩展欧几里得算出最小的非负整数解x(x确定,y也就确定了),然后再把剩余的数分配掉(以它们的最小公倍数去分). 1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 using namespace std; 5 6 typedef long long LL; 7 8 LL e_gcd(LL a,LL b,

51nod_1352_集合计数 (exgcd)

题意:ax+by=n+1,x>0,y>0的解的个数 先判断(a,b)是否整除n+1,不整除无解,有解后用exgcd算出一解(x1,y1), 然后在草稿纸上写下x1+d*(b/gcd(a,b))>0,  y1-d*(b/gcd(a,b))>0,算出d的范围,大于号一侧向下取整(若本身为整数,还要-1,因为取不到等号),小于相反. 注意 : 负数时,取整是变大,正数是变小. #include<algorithm> #include<cstdlib> #inclu