考虑两个灯之间的暗灯,能从左边或右边点亮两种顺序,而最左端或最右端只有一种点亮顺序。
先不考虑点灯顺序,总共有n - m个灯要点亮,对于连续的一段暗灯,他们在总的点灯顺序中的是等价的,于是问题就可以抽象成有重复元素的组合数:
$ C = frac{ (n - m)! }{ prod_{i = 1}^{k} \, x_{i} ! } $ 。
在考虑一段连续的暗灯内部的点灯顺序,只要让答案乘上 $ 2 ^ {len - 1} $ 即可。
$ igodot $ 技巧&套路:
- 组合数应用的模型,组合数的运用
1 #include <cstdio> 2 #include <algorithm> 3 4 typedef long long LL; 5 const int N = 1005, MOD = 1e9 + 7; 6 7 int n, m, a[N], d[N], pw2[N], fac[N]; 8 9 int Pow(int x, int b, int re = 1) { 10 for (; b; b >>= 1, x = (LL) x * x % MOD) if (b & 1) re = (LL) re * x % MOD; 11 return re; 12 } 13 14 int main() { 15 scanf("%d%d", &n, &m); 16 pw2[0] = fac[0] = 1; 17 for (int i = 1; i <= m; ++i) { 18 scanf("%d", &a[i]); 19 } 20 for (int i = 1; i <= n; ++i) { 21 pw2[i] = pw2[i - 1] * 2 % MOD; 22 fac[i] = (LL) fac[i - 1] * i % MOD; 23 } 24 std::sort(a + 1, a + 1 + m); 25 26 int ans = fac[n - m]; 27 for (int i = 1; i < m; ++i) { 28 int d = a[i + 1] - a[i] - 1; 29 if (d == 0) continue; 30 ans = (LL) ans * Pow(fac[d], MOD - 2) % MOD; 31 ans = (LL) ans * pw2[d - 1] % MOD; 32 } 33 if (a[1] > 1) ans = (LL) ans * Pow(fac[a[1] - 1], MOD - 2) % MOD; 34 if (a[m] < n) ans = (LL) ans * Pow(fac[n - a[m]], MOD - 2) % MOD; 35 printf("%d ", ans); 36 37 return 0; 38 }