Decription
有
2
n
2^n
2n个人,编号
1
,
2
,
3
…
1,2,3…
1,2,3…。他们摔
♂
♂
♂跤,过程如下:
- 选择一个 2 n 2^n 2n的排列;
- 所有人按排列的顺序乖乖♂站♂好;
- 按照站的顺序第 1 1 1个人和第 2 2 2个人直抽,第 3 3 3个人和第 4 4 4个人直抽,依次类推;
- 一轮摔♂跤结束后,剩余的人将保持相对顺序;
- 重复 3 , 4 3,4 3,4直到剩一个人,他将是冠军。
判定两个人胜负的方法:
给定
m
m
m个不同的正整数,编号为
1
1
1的人与这
m
m
m个人摔♂跤会输,其他会赢。对于
2
≤
x
<
y
≤
2
n
2≤x<y≤2^n
2≤x<y≤2n,
x
,
y
x,y
x,y摔跤时
x
x
x会赢。
给定
n
,
m
n,m
n,m,以及
m
m
m个数,问有多少种初始排列使得编号为1的人是冠军。
Sample Input
2 1
3
Sample Output
8
首先这是个二叉树,求出答案乘个
2
n
2^n
2n
考虑进行容斥,设第1个人至少输了k次,那么答案为:
∑
k
=
1
n
(
−
1
)
k
F
(
k
)
\sum_{k=1}^n(-1)^kF(k)
∑k=1n(−1)kF(k)。
设
f
(
S
)
f(S)
f(S),为第一个人输掉的状态那么直接考虑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;
}