[ARC093F] Dark Horse

[题目链接]

https://atcoder.jp/contests/arc093/tasks/arc093_d

[题解]

首先一个重要观察是 , (1) 无论在哪个位置其贡献都是一样的 , 因此只需考虑 (1)(1) 号位的答案 , 最后将其乘以 (2 ^ {N}) 就是最终的答案。

(1) 在一号位时 , 会和 ((2) , (3 , 4) , (5 , 6 , 7 , 8)....) 这些区间的最小值比较。 也就是说 , 这 (N) 个区间的最小值不能是给定的 (M) 个数中的某一个。

考虑容斥原理 ,用总方案数 - 至少一个区间不满足 + 至少两个区间不满足 + ......

不妨将 (M) 个数从大到小排序 , 从前往后进行动态规划 , 设 (f_{S , i}) 表示 (N) 个区间的占有情况为 (S) , 考虑到第 (i) 个数的方案数。 那么转移只需考虑是否用当前数 "占有" 一个区间即可 , 需要乘上一个组合数。

时间复杂度 : (O(2 ^ NN))

[代码]

#include<bits/stdc++.h>

using namespace std;

#define rep(i , l , r) for (int i = (l); i < (r); ++i)

typedef long long LL;

const int MN = 17 , mod = 1e9 + 7 , MS = 1 << 17;

int n , m , a[MN] , fac[MS] , dp[MN][MS] , ifac[MS] , cnt[MS] , all;

inline bool cmp(int x , int y) {
	  return x > y;
}
inline void inc(int &x , int y) {
	  x = x + y < mod ? x + y : x + y - mod;
}
inline void dec(int &x , int y) {
	  x = x - y >= 0 ? x - y : x - y + mod;
}
inline int qPow(int a , int b) {
	  int c = 1;
	  for (; b; b >>= 1 , a = 1ll * a * a % mod) if (b & 1) c = 1ll * c * a % mod;
	  return c;
}
inline int binom(int n , int m) {
	  if (n < m) return 0;
	  else return 1ll * 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]);
		sort(a + 1 , a + 1 + m , cmp);
		fac[0] = 1; all = 1 << n;
		for (int i = 1; i <= all; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
		ifac[all] = qPow(fac[all] , mod - 2);
		for (int i = all - 1; i >= 0; --i) ifac[i] = 1ll * ifac[i + 1] * (i + 1) % mod;
		cnt[0] = 0;
		for (int i = 1; i < all; ++i) cnt[i] = cnt[i >> 1] + (i & 1);
		dp[0][0] = 1;
		for (int i = 1; i <= m; ++i)
			  for (int s = 0; s < all; ++s) if (dp[i - 1][s]) {
			  		inc(dp[i][s] , dp[i - 1][s]);
			  		for (int j = 0; j < n; ++j)
			  				if ((s >> j & 1) == 0) inc(dp[i][s | 1 << j] , 1ll * dp[i - 1][s] * binom(all - s - a[i] , (1 << j) - 1) % mod * fac[1 << j] % mod);  				
				}
		int ans = 0;
		for (int s = 0; s < all; ++s)
				if (cnt[s] & 1) dec(ans , 1ll * dp[m][s] * fac[all - s - 1] % mod);
				else inc(ans , 1ll * dp[m][s] * fac[all - s - 1] % mod);
		printf("%d
" , 1ll * ans * all % mod);
	  return 0; 
}
原文地址:https://www.cnblogs.com/evenbao/p/14321147.html