jzoj3170-[GDOI2013模拟4]挑选玩具【容斥,状态压缩,分治】
正題
題目大意
有nnn個(gè)箱子放了若干個(gè)玩具,要求選擇一些箱子使得mmm種玩具都有,求方案總數(shù)。
解題思路
設(shè)fSf_SfS?表示選擇只有在集合為SSS的方案數(shù)。
然后答案考慮容斥,那么答案就是∑S(2(f(~S))?1)?(?1)∣S∣\sum_S (2^{(f_{(\sim S)})}-1)*(-1)^{|S|}S∑?(2(f(~S)?)?1)?(?1)∣S∣
我們將集合的表示狀壓起來。
現(xiàn)在考慮如何快速求fff數(shù)組,首先fS=cSf_S=c_SfS?=cS?(cSc_ScS?表示集合是SSS的箱子個(gè)數(shù))。
然后分治,每次分治時(shí)rrr肯定是若干個(gè)111
比如當(dāng)l=0,r=11111l=0,r=11111l=0,r=11111時(shí)左邊邊都是0XXXX0XXXX0XXXX而右邊是1XXXX1XXXX1XXXX。也就是右邊是左邊第一位變成一。那么對(duì)于每個(gè)區(qū)間就有
fi=∑mfi?m+l?1(i>m)f_i=\sum_mf_{i-m+l-1}(i> m)fi?=m∑?fi?m+l?1?(i>m)
時(shí)間復(fù)雜度O(2mlog2m)O(2^m\ log\ 2^m)O(2m?log?2m)
codecodecode
#include<cstdio> using namespace std; const int M=(1<<20)+10,XJQ=1e9+7; int n,m,f[M],w[M],p[M],ans,v[M],MS; void apart(int l,int r) {if(l==r){f[l]=v[l];return; } int m=(l+r)>>1;apart(l,m);apart(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(int i=1;i<=n;i++){int z=0,k;scanf("%d",&k);while(k--){int x;scanf("%d",&x);z|=(1<<x-1);}v[z]++;}MS=1<<m;for(int i=0;i<MS;i++)w[i]=w[i>>1]^(i&1);p[0]=1;for(int i=1;i<=n;i++)p[i]=(p[i-1]<<1)%XJQ;apart(0,MS-1);for(int i=0;i<MS;i++)(ans+=((w[i]?-1:1)*(p[f[MS-i-1]]-1)))%=XJQ;printf("%d",(ans+XJQ)%XJQ); }總結(jié)
以上是生活随笔為你收集整理的jzoj3170-[GDOI2013模拟4]挑选玩具【容斥,状态压缩,分治】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jzoj3169-[GDOI2013模拟
- 下一篇: jzoj3171-[GDOI2013模拟