Atcoder arc093F

北慕城南 提交于 2019-12-11 09:55:33

简单的容斥DP。
显然11所在位置是不重要的,不妨设p1=1p_1=1。那么我们可以发现11要比赛的人是另外NN个大小分别为202^0212^1......2N12^{N-1}的有序集合的最小值。11能获胜即等价于这些集合的最小值均不为AiA_i
直接算不好做,考虑容斥,钦定若干个AiA_i为某些集合的最小值。按ii从大往小考虑,设F[i][s]F[i][s]表示考虑了AiA_i~ AMA_Mss的二进制位对应大小的集合最小值已经被钦定为AiA_i~AMA_M中的人的贡献和,转移简单枚举一下是否钦点AiA_i为某个集合的最小值,是的话系数是组合数,容易计算。
时间复杂度O(NM2N)\mathcal O(NM2^N)

#include <bits/stdc++.h>
#define MOD 1000000007

using namespace std;

typedef long long ll;

ll pow_mod(ll x,int k) {
  ll ans=1;
  while (k) {
  	if (k&1) ans=ans*x%MOD;
  	x=x*x%MOD;
  	k>>=1;
  }
  return ans;
}

inline void add(int &x,ll y) {
  x=(x+y)%MOD;
}

ll facd[70005],facv[70005];

void pre(int n) {
  facd[0]=1;
  for(int i=1;i<=n;i++) facd[i]=facd[i-1]*i%MOD;
  facv[n]=pow_mod(facd[n],MOD-2);
  for(int i=n-1;i>=0;i--) facv[i]=facv[i+1]*(i+1)%MOD;
}

inline ll C(int n,int m) {
  return (n<m)?0:facd[n]*facv[m]%MOD*facv[n-m]%MOD;
}

int f[17][1<<16],num[17];

int dp(int n,int m) {
  f[0][0]=1;
  for(int i=1;i<=m;i++)
    for(int j=0;j<(1<<n);j++)
      if (f[i-1][j]) {
      	add(f[i][j],f[i-1][j]);
      	for(int k=0;k<n;k++)
      	  if (!((j>>k)&1)&&j+(1<<k)<=num[i]) 
			add(f[i][j^(1<<k)],(MOD-f[i-1][j])*C(num[i]-j-1,(1<<k)-1));
	  }
  int ans=0;
  for(int i=0;i<(1<<n);i++)
    if (f[m][i]) {
    	int s=(1<<n)-i-1;
    	ll v=f[m][i];
    	for(int j=0;j<n;j++)
    	  if (!((i>>j)&1)) {
    	  	v=v*C(s,1<<j)%MOD;
    	  	s-=(1<<j);
		  } 
		add(ans,v);
	}
  for(int i=0;i<n;i++) ans=ans*facd[1<<i]%MOD;
  return ans;
}

int main() {
  int n,m;
  scanf("%d%d",&n,&m);
  pre(1<<n);
  for(int i=1;i<=m;i++) {
  	int x;
  	scanf("%d",&x);
  	num[i]=(1<<n)-x+1;
  }
  reverse(num+1,num+m+1);
  printf("%lld\n",(ll)dp(n,m)*(1<<n)%MOD);
  return 0;
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!