arc 093 F Dark Horse

         题意: 我们现在有一个有2的n次方的人的淘汰赛,每次相邻的两个人打,赢得人晋级,以此类推到只剩一个人为止。给定一个集合a[i], 规则如下:1号和a[i]的人打a[i]胜,1号和其他人打 1号胜利,其他号和其他的打,字典序小的胜。问1号胜利的方案数有多少种。

        我们先假装第一个人就在第一个位置,由于都是从一个2^1的人中取胜,到从2^n的人中取胜,所以一号人在哪方案数都是一样的,所以我们可以假装第一个人就在第一个位置,最后算答案的时候×2^n即可。

        接着我们观察1的对手是谁, 我们假设n=3, 那么 n的对手就是 2 , [3,4] , [5,8] 的胜者,即为1向后推 2^0次方的长度到2^n-1次方的长度每一个区间的胜者,所以这些区间的胜者不能为a[i]。由于都和1无关,所以要求就是这些区间中字典序最小的不能是a[i]。正着做不好做,我们考虑某个区间胜者是a[i]的方案数,最后容斥一下就好了。

         令dp[i][state]表示考虑到第i个a[i]了,有那些区间的胜者已经是a[i]了。很显然每个a[i]可以有两种选择,第一种不选,第二种找一个没有选的区间加入到其中,设区间长度为len,就还要找 len-1个比它大的填入到这个区间里。 由于dp的状态的0,1就表示每个区间选了没选,所以state的数值就表示了有多少个人选了。这里注意到要找的是比a[i]大的并不是很好找,所以我们按a[i]从大到小排序,那么这时比a[i]大的数字就是n-state-a[i]个了。

         等等这时候不就求出来了吗,要容斥啥??? 因为对于没有选的区间,我们是随便放剩下的,所以可能会把是a[i]的放到某个区间做最小值了。

          所以 如果state里有j个1,那么我们求出来的就是 有大于等于j的区间被a[i]放了的方案数,我们就根据j的奇偶性加加减减就好啦,最后记得乘2的n此方。

         下附AC代码。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn (1<<17)+5
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n,m;
int a[20];
ll fac[maxn],inv[maxn];
ll dp[20][maxn];
ll quickpow(ll p,ll k)
{
	ll ans=1;
	while(k)
	{
		if(k&1)
			ans=(ans*p)%mod;
		p=(p*p)%mod;
		k>>=1;
	}
	return ans;
}
ll c(ll n1,ll m1)
{
	if(n1<m1) return 0;
	return fac[n1]*inv[m1]%mod*inv[n1-m1]%mod;
}
int getbit(int now)
{
	int res=0;
	while(now)
		res+=(now&1),now>>=1;
	return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d",&a[m-i+1]);
	fac[0]=1;
	for(int i=1;i<=maxn-5;i++)
		fac[i]=fac[i-1]*i%mod;
 
	inv[maxn-5]=quickpow(fac[maxn-5],mod-2);
	for(int i=maxn-5;i>=1;i--)
		inv[i-1]=inv[i]*i%mod;
	inv[0]=1;
 
	dp[0][0]=1;
 
	for(int i=0;i<m;i++)
	{
		for(int state=0;state<(1<<n);state++)
		if(dp[i][state])
		{
			dp[i+1][state]+=dp[i][state];
			dp[i+1][state]%=mod;
 
			for(int j=0;j<n;j++)
			if(((1<<j)&state)==0)
			{
				dp[i+1][state|(1<<j)]+=(dp[i][state]*fac[(1<<j)]%mod*c((1<<n)-state-a[i+1],(1<<j)-1)%mod);
				dp[i+1][state|(1<<j)]%=mod;
			}
		}
	}
 
	ll ans=0;
	for(int state=0;state<(1<<n);state++)
	{
		int cnt=getbit(state);
		ll f=(cnt&1)?-1:1;
		ans=(ans+f*dp[m][state]*fac[(1<<n)-state-1])%mod;
	}
	ans=(ans%mod+mod)%mod;
	printf("%lld\n",(ans*(1<<n))%mod);
}

Especially For U 

By ZRX


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值