zoukankan      html  css  js  c++  java
  • arc093F Dark Horse

    我们可以假设1的位置在1,并且依次与右边的区间合并。答案最后乘上2^n即可。

    那么需要考虑1所在的区间与另一个区间合并时,另一个区间的最小值不能为特殊的。

    直接求解很难,考虑容斥,钦定在哪几个位置必定输,容斥出必胜的方案数。

    从大到小dp,设f(i,S)表示当前考虑到第i个特殊的数,必输的区间集合为S。

    考虑是否向集合S中加入i,若加入,枚举在哪个区间合并,用组合数算出能够选出的数的方案并乘上排列数。

    若不加入,则直接转移即可。

    f(i,S) <- f(i+1,S)

    f(i,S|(1<<k)) <- Σ f(i+1,S) * C((1<<n)-S-a[i],(1<<k)-1) * (1<<k)!

    最后f(i,S)对答案的贡献还要乘上没有钦定的位置数的排列。

    最后答案乘上2^n。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=17,mod=1e9+7;
    int n,m,a[N],f[N][1<<N],fac[1<<N],ifac[1<<N];
    int Pow(int x,int k){
    	int ret=1;
    	while(k){
    		if(k&1)ret=(ll)ret*x%mod;
    		k>>=1;x=(ll)x*x%mod;
    	}
    	return ret;
    }
    int C(int n,int m){
    	if(n<m)return 0;
    	return (ll)fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    	fac[0]=1;
    	for(int i=1;i<=(1<<n);i++)fac[i]=(ll)fac[i-1]*i%mod;
    	for(int i=0;i<=(1<<n);i++)ifac[i]=Pow(fac[i],mod-2);
    	sort(a+1,a+m+1,greater<int>());
    	f[0][0]=1;
    	for(int i=0;i<m;i++)
    		for(int j=0;j<(1<<n);j++){
    			if(!f[i][j])continue;
    			f[i+1][j]=(f[i+1][j]+f[i][j])%mod;
    			int res=(1<<n)-j-a[i+1];
    			for(int k=0;k<n;k++){
    				if(j&(1<<k))continue;
    				if(res<(1<<k)-1)break;
    				f[i+1][j|(1<<k)]=(f[i+1][j|(1<<k)]-(ll)f[i][j]*C(res,(1<<k)-1)%mod*fac[1<<k])%mod;
    			}
    		}
    	int ans=0;
    	for(int i=0;i<(1<<n);i++){
    		ans=(ans+(ll)f[m][i]*fac[(1<<n)-1-i])%mod;
    	}
    	ans=((ll)ans*(1<<n)%mod+mod)%mod;
    	cout<<ans<<"
    ";
    }
    
  • 相关阅读:
    Visualvm 远程测试 问题
    jsp中文件下载的实现
    MYOB 的一些开发资料
    连接MYOB ODBC,在MyEclipse 下Commit成功,在Tomcat下单独运行,Commit显示Connection 已经关闭
    也说说学习
    objectivec static变量的使用总结
    objective里面的单例模式
    对函数式编程简单理解
    个人技术生涯的感悟(2)
    苹果键盘快捷键图标
  • 原文地址:https://www.cnblogs.com/Trrui/p/10314779.html
Copyright © 2011-2022 走看看