[AtCoder ARC093F]Dark Horse
题目大意:有2n个人,每相邻的两个人比赛一次。令两个人的编号为a,b(a⩽,若a\neq 1,则a的人获胜;否则若b\in S则b获胜,不然1获胜。钦定1获胜,问可以的开始的顺序的方案数
题解:状压DP,令开始的第i位的人的编号为p_i,发现到只有\min\limits_{i\in[2^{j-1}+1,2^j]}\{p_i\}(1\leqslant j\leqslant n)的人会和1打,考虑容斥,令f_{i,j}为到了要放S中的第i个人,现在第k个段([2^{k-1}+1,2^k])中的最小值在S中的状态为1<<k \& j,时可以战胜1的方案数。(发现一个很优美的东西,j==已经放置的人数)
卡点:无
C++ Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <cstdio> #define N 1 << 16 | 3 const int mod = 1000000007; int n, m, s[20]; long long fac[N], inv[N]; long long f[17][N], ans, U; void update( long long &x, long long y) { if ((x += y) >= mod) x -= mod;} long long C( long long a, long long b) { if (a < b) return 0; return fac[a] * inv[b] % mod * inv[a - b] % mod; } int main () { scanf ( "%d%d" , &n, &m); U = 1 << n; for ( int i = 1; i <= m; i++) scanf ( "%d" , s + m - i); fac[0] = fac[1] = inv[0] = inv[1] = 1; for ( int i = 2; i < U; i++) { fac[i] = fac[i - 1] * i % mod; inv[i] = inv[mod % i] * (mod - mod / i) % mod; } for ( int i = 2; i < U; i++) inv[i] = inv[i - 1] * inv[i] % mod; f[0][0] = 1; for ( int i = 0; i < m; i++) { for ( int j = 0; j < U; j++) { update(f[i + 1][j], f[i][j]); for ( int k = 0; k < n; k++) { if (!(j & (1 << k))) update(f[i + 1][j | 1 << k], f[i][j] * fac[1 << k] % mod * C(U - j - s[i], (1 << k) - 1) % mod); } } } for ( int i = 0; i < U; i++) { long long tmp = f[m][i] * fac[U - i - 1] % mod; update(ans, __builtin_parity(i) ? (mod - tmp) : tmp); } printf ( "%lld\n" , ans * U % mod); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步