[Solution] CF1111D

· · 题解

有一偶数长度字符串 sq 次询问,每次询问给两位置 x, y,求满足下列条件的 s 的排列 p 的方案数。

两种排列方案 p, q​ 不同,当且仅当 \exists 1 \leq i \le |s| 满足 p_i \neq q_i

--- 记字符集为 $\Sigma$,有 $|\Sigma| = 52$。比较显然地,本质不同的询问仅有至多 $|\Sigma|^2$​​ 种。 如果已经钦定各字符在哪一段,设 $c_x$ 为字符 $x$ 的出现次数,则方案数为 $$C = (\frac n 2)!^2 \prod_{x} c_x!^{-1}.$$ 考虑钦定 $s_x, s_y$ 均在前半段,设钦定方案数为 $g$,则答案为 $2Cg$。 考虑求出 $g$。 定义 $f_x$ 表示选择一些字符 $\Sigma'$,使 $\sum_{i \in \Sigma'} c_i = x$ 的方案数。​ $\forall x, y \in \Sigma$​​,利用支持删除操作的背包,在 $f$​​ 中依次删去 $x, y$​​,得到 $f'$​,则 $g_{x, y} = f'_{\frac {|s|} 2 - c_x - c_y}$​。 注意特殊处理 $x = y$ 的情况。 时间复杂度 $\mathcal O(|s|(|\Sigma|^2 + \log|s|))$,空间复杂度 $\mathcal O(|\Sigma|^2 + |s|)$,可过。 --- ```cpp # include <ciso646> # include <cstdio> # include <cstring> # define forletter(i) for (char i('a'); i not_eq 'Z' + 1; i == 'z' ? (i = 'A') : ++i) namespace Main { typedef unsigned int uint; typedef short unsigned int hu; static inline const uint qpow(uint a, uint n, const uint mod) { uint r(1); while (n) { if (n bitand 1) r = 1ull * r * a % mod; a = 1ull * a * a % mod, n >>= 1; } return r; } static inline const uint invp(const uint x, const uint p) { return qpow(x, p - 2, p); } static const uint S(1e5); static const uint P(1e9 + 7); static uint fact[S + 1]{ 1 }, ifact[S + 1]{ 1 }; static char s[S + 2]; static uint n, q; static uint c[128]; static uint f[S + 1]{ 1 }; static uint g[128][128]; static uint bc; static inline const void init() { n = strlen(s + 1); for (register uint i(1); i <= n; ++i) ifact[i] = invp(fact[i] = 1ull * fact[i - 1] * i % P, P); f[0] = 1; for (register uint i(1); i <= n; ++i) ++c[s[i]]; forletter(i) if (c[i]) for (register uint j(n); j >= c[i]; --j) f[j] = (f[j] + f[j - c[i]]) % P; bc = 1ull * fact[n / 2] * fact[n / 2] % P; forletter(i) bc = 1ull * bc * ifact[c[i]] % P; } static inline const void solve(const char a, const char b) { if (!c[a] or !c[b]) return; if (a == b) { if (c[a] > n / 2) return (const void)(g[a][a] = 0); static uint h[S + 1]; for (register uint i(0); i <= n; ++i) h[i] = f[i]; for (register uint i(c[a]); i <= n; ++i) h[i] = (h[i] + P - h[i - c[a]]) % P; return (const void)(g[a][a] = 1ull * h[n / 2 - c[a]] * bc * 2 % P); } if (c[a] + c[b] > n / 2) return (const void)(g[a][b] = 0); static uint h[S + 1]; for (register uint i(0); i <= n; ++i) h[i] = f[i]; for (register uint i(c[a]); i <= n; ++i) h[i] = (h[i] + P - h[i - c[a]]) % P; for (register uint i(c[b]); i <= n; ++i) h[i] = (h[i] + P - h[i - c[b]]) % P; g[a][b] = 1ull * h[n / 2 - c[a] - c[b]] * bc * 2 % P; } static inline const void main() { scanf("%s", s + 1), init(); forletter(i) forletter(j) solve(i, j); scanf("%u", &q); for (register uint i(0); i < q; ++i) { static uint x, y; scanf("%u%u", &x, &y), printf("%u\n", g[s[x]][s[y]]); } } } signed int main() { Main::main(); return 0; } ```