zoukankan      html  css  js  c++  java
  • 【题解】yyy loves Maths VII

    yyy loves Maths VII

    ( ext{Solution:})

    一个显然的状压 (dp) 是,设 (f[S]) 表示状态 (S) 中的数已经被选后的所有胜利方案数,那么最终的结果就是 (f[2^n-1])

    那么对于转移,我们直接枚举它的二进制下 (1) 的位置,它从 (i-2^j,2^j) 两个地方转移。

    关于厄运数字,我们直接判断当前位置的 (sum) 是不是厄运数字。为了卡常数, (sum) 的维护要在转移中进行,这样可以少一个 (2) 的常数。

    那么复杂度就是 (O(ncdot 2^n)) 了。但是很难卡过去。

    观察到我们每次只是取出一个二进制位下的 (1,)lowbit(i) 这个函数的功能就是直接取出该数二进制下的第一个 (1) 的位置。

    于是,我们可以用 lowbit 来优化转移。这样就可以轻松卡过去了。

    主要收获:卡常数技巧以及 lowbit 的灵活运用。

    #include<bits/stdc++.h>
    #include<assert.h>
    using namespace std;
    const int mod=1e9+7;
    const int dyx=(1<<30);
    int n;
    int m;
    inline int lowbit(int x){return x&(-x);}
    int u[2],f[1<<25],sum[1<<25];
    int main(){
    	freopen("111.txt","r",stdin);
    	scanf("%d",&n);u[0]=-1;u[1]=-1;
    	for(int i=1;i<=n;++i)scanf("%d",&sum[1<<(i-1)]);
    	scanf("%d",&m);
    	for(int i=0;i<m;++i)scanf("%d",&u[i]);
    	f[0]=1;
    	for(int i=1;i<(1<<n);++i){
    		sum[i]=sum[i^lowbit(i)]+sum[lowbit(i)];
    		if(sum[i]==u[0]||sum[i]==u[1]){
    			continue;
    		}
    		for(int j=i;j;j-=lowbit(j)){
    			int pos=i-lowbit(j);
    			f[i]+=f[pos];
    			if(f[i]>=mod)f[i]-=mod;
    		}
    	}
    	printf("%d
    ",f[(1<<n)-1]);
    	return 0;
    }
    
  • 相关阅读:
    上下界网络流——概念解析与快速入门(待修改)
    maomao的现在与未来
    exgcd证明和最基础应用
    快速入门Splay
    luogu 2515
    bzoj 1996
    *51nod 1409
    51nod 1412
    51nod 1503
    51nod 1020
  • 原文地址:https://www.cnblogs.com/h-lka/p/15003706.html
Copyright © 2011-2022 走看看