版权声明:本文是蒟蒻写的,转载。。。随便吧 https://blog.csdn.net/xgc_woker/article/details/86317691
Decription
有
个人,编号
。他们摔
跤,过程如下:
- 选择一个 的排列;
- 所有人按排列的顺序乖乖♂站♂好;
- 按照站的顺序第 个人和第 个人直抽,第 个人和第 个人直抽,依次类推;
- 一轮摔♂跤结束后,剩余的人将保持相对顺序;
- 重复 直到剩一个人,他将是冠军。
判定两个人胜负的方法:
给定
个不同的正整数,编号为
的人与这
个人摔♂跤会输,其他会赢。对于
,
摔跤时
会赢。
给定
,以及
个数,问有多少种初始排列使得编号为1的人是冠军。
Sample Input
2 1
3
Sample Output
8
首先这是个二叉树,求出答案乘个
考虑进行容斥,设第1个人至少输了k次,那么答案为:
。
设
,为第一个人输掉的状态那么直接考虑DP即可。
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const LL mod = 1e9 + 7;
const int N = 17;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
LL f[1 << N];
LL jc[1 << N], inv[1 << N];
int a[N], bin[N], cnt[1 << N];
LL pow_mod(LL a, int k) {
LL ans = 1;
while(k) {
if(k & 1) (ans *= a) %= mod;
(a *= a) %= mod; k /= 2;
} return ans;
}
LL C(int n, int m) {
if(n < m) return 0;
return jc[n] * inv[m] % mod * inv[n - m] % mod;
}
int main() {
int n = read(), m = read();
for(int i = 1; i <= m; i++) a[i] = read();
bin[0] = 1; for(int i = 1; i <= n; i++) bin[i] = bin[i - 1] * 2;
jc[0] = inv[0] = 1; for(int i = 1; i <= bin[n]; i++) jc[i] = jc[i - 1] * i % mod;
inv[bin[n]] = pow_mod(jc[bin[n]], mod - 2); for(int i = bin[n] - 1; i >= 1; i--) inv[i] = inv[i + 1] * (i + 1) % mod;
cnt[0] = 0; for(int i = 1; i <= bin[n]; i++) cnt[i] = cnt[i >> 1] + (i & 1);
f[0] = 1; sort(a + 1, a + m + 1);
for(int i = m; i >= 1; i--) {
for(int j = bin[n] - 1; j >= 0; j--) {
for(int k = 0; k < n; k++) if(bin[k] & j){
(f[j] += f[j ^ bin[k]] * C(bin[n] - a[i] - j + bin[k], bin[k] - 1) % mod * jc[bin[k]]) %= mod;
}
}
} LL ans = 0;
for(int i = 0; i < bin[n]; i++) {
f[i] = f[i] * jc[bin[n] - i - 1] % mod;
cnt[i] & 1 ? ans = (ans - f[i] + mod) % mod : ans = (ans + f[i]) % mod;
} printf("%d\n", ans * bin[n] % mod);
return 0;
}