• 【JZOJ3170】挑选玩具【分治】


    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/3170
    nn个箱子装着mm个玩具(一个玩具可以在多个箱子内),求有多少种选择箱子的方案使得每种玩具至少有一个。


    思路:

    f[i]f[i]表示S1(S&i=S)sum^{}_{S}1(S&i=S),也就是选择其中一些箱子,会得到一个玩具集合SS(状压后),如果ii完全包含SSf[i]f[i]就加一。
    那么f[MAXN1i]f[MAXN-1-i]就是没有一个玩具在集合ii中的方案数。
    显然答案就是
    S1S×(2f[MAXN1i]1)sum _S -1^{|S|} imes (2^{f[MAXN-1-i]}-1)
    对于求ff,可以考虑使用分治。
    显然f[i]&f[i+mid]=f[i]f[i]&f[i+mid]=f[i],因为若f[i]f[i]abcdabcd,则f[i+mid]f[i+mid]1abcd1abcd
    这样时间复杂度就降到了O(2mlog2m)O(2^mlog 2^m)


    代码:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010,MOD=1e9+7,M=(1<<20)+10;
    int n,m,ans,MAXN,cnt[M],f[M],power[N];
    
    void work(int l,int r)
    {
    	if (l==r)
    	{
    		f[l]=cnt[l];
    		return;
    	}
    	int mid=(l+r)/2;
    	work(l,mid);
    	work(mid+1,r);
    	for (int i=l;i<=mid;i++)
    		f[i-l+mid+1]+=f[i]; 
    }
    
    int main()
    {
    	freopen("data","r",stdin);
    	scanf("%d%d",&n,&m);
    	MAXN=(1<<m);
    	for (int i=1;i<=n;i++)
    	{	
    		int sum,x,S=0;
    		scanf("%d",&sum);
    		while (sum--)
    		{
    			scanf("%d",&x);
    			S|=(1<<x-1);
    		}
    		cnt[S]++;
    	}
    	work(0,MAXN-1);
    	power[0]=1;
    	for (int i=1;i<=n;i++) power[i]=power[i-1]*2%MOD;
    	cnt[0]=1;
    	for (int i=0;i<MAXN;i++)
    	{
    		if (i&1) cnt[i]=-cnt[i>>1];
    			else cnt[i]=cnt[i>>1];
    		ans=(ans+cnt[i]*(power[f[MAXN-1-i]]-1)%MOD)%MOD;
    	} 
    	printf("%d
    ",(ans%MOD+MOD)%MOD);
    	return 0;
    }
    
  • 相关阅读:
    元素设置float属性后,其后面的元素的位置问题
    Vue.js经典开源项目汇总
    ES6-模块导入导出
    JavaScript内存泄漏
    父元素高度比子元素高度多几个像素的解决方法
    jasmine —— Spies(转)
    用npm-run自动化任务(转)
    AngularJS中页面传参方法
    Path模块部分常用函数解析——NodeJS
    html特殊字符表
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998239.html
Copyright © 2020-2023  润新知