2019.4.13 提高A组 T2 JZOJ 3170 挑选玩具

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89281858

D e s c r i p t i o n Description

给定 n n 个子,要求选出若干个箱子,这些箱子中的玩具必须齐全( m m 件),求方案数,答案对 1 0 9 + 7 10^9+7 取模

数据范围: n 1 0 6 , m 20 n\leq 10^6,m\leq 20


S o l u t i o n Solution

首先很容易想到状压 m m ,这样做状压 d p dp 就有50分了

这样子的复杂度显然还是不够优秀,由于求全部齐全的比较麻烦,但我们可以用容斥求出至少少一个的方案数,再用 2 n 2^n 一减去即为答案了


C o d e Code

 	#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define N (1<<m)
#define mod 1000000007
using namespace std;
int c[1<<20],w[1<<20],f[1<<20],p[1<<20]={1},n,m,ans=0,s,k;
inline long long read()
{
    char c;int f=0,d=1;
    while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
void cdq(int l,int r)
{
	if(l==r)
	{
		f[l]=c[l];
		return;
	}
	int m=l+r>>1;
	cdq(l,m);cdq(m+1,r);
	for(int i=l;i<=m;++i) f[i+m-l+1]+=f[i];
}
int main()
{
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=n;i++)
	{
		k=read();s=0;
		for(register int j=1;j<=k;j++) s|=1<<(read()-1);
		c[s]++;
	}
	for(register int i=1;i<N;i++) w[i]=w[i>>1]^(i&1);
	for(register int i=1;i<=n;i++) p[i]=(p[i-1]<<1)%mod;
	cdq(0,N-1);
	for(register int i=0;i<N;++i) ans=w[i]?(ans-p[f[N-i-1]]+1)%mod:(ans+p[f[N-i-1]]-1)%mod;
	printf("%d",(ans+mod)%mod);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/89281858
今日推荐