题目大意: 有一个长度为$n(n\leqslant10^5,n=0\pmod2)$的字符串,字符集大小为$52$,有$q(q\leqslant10^5)$次询问,每次询问第$x,y$个字符在这个字符串的同一侧,并且所有相同字符在字符串的同一
题目大意:有一个长度为$n(n\leqslant10^5,n=0\pmod2)$的字符串,字符集大小为$52$,有$q(q\leqslant10^5)$次询问,每次询问第$x,y$个字符在这个字符串的同一侧,并且所有相同字符在字符串的同一侧的方案数。
题解:因为字符集大小只有$52$,所以本质不同的询问只有$52\times52$种,预处理。
发现若确定了左右各放那几种字符后方案数是一定的,为$\dfrac{\left(\dfrac n2!\right)^2}{\prod\limits_{i=1}^{52}cnt_i!}$,$cnt_i$表示字符$i$出现次数。只需要求出左边可以放的字符种类,乘上这个数就是答案。
考虑$DP$,若正常的做,不加入$x,y$两种字符,复杂度是$O(52^3\times n)$,不可以通过。发现最多只有两种字符不加入,可以退背包,就倒着做背包部分即可,复杂度$O(52^2\times n)$
卡点:阶乘逆元算成了每个数的逆元
C++ Code:
#include <algorithm> #include <cctype> #include <cstdio> #include <iostream> #define maxn 100010 #define N 52 const int mod = 1e9 + 7; inline void reduce(int &x) { x += x >> 31 & mod; } std::string __s; long long C; int n, nn, q; int fac[maxn], inv[maxn]; int s[maxn], cnt[N]; int f[maxn], g[maxn], ans[N][N]; int solve(int x, int y) { std::copy(f, f + nn + 1, g); for (int i = cnt[x]; i <= nn; ++i) reduce(g[i] -= g[i - cnt[x]]); for (int i = cnt[y]; i <= nn; ++i) reduce(g[i] -= g[i - cnt[y]]); return 2 * g[nn] % mod; } int main() { std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0); std::cin >> __s; n = __s.length(), nn = n >> 1; for (int i = 0; i < n; ++i) { s[i + 1] = islower(__s[i]) ? __s[i] - ‘a‘ : __s[i] - ‘A‘ + 26; ++cnt[s[i + 1]]; } fac[0] = fac[1] = inv[0] = inv[1] = 1; for (int i = 2; i <= nn; ++i) { fac[i] = static_cast<long long> (fac[i - 1]) * i % mod; inv[i] = static_cast<long long> (mod - mod / i) * inv[mod % i] % mod; } for (int i = 2; i <= nn; ++i) inv[i] = static_cast<long long> (inv[i - 1]) * inv[i] % mod; C = static_cast<long long> (fac[nn]) * fac[nn] % mod; for (int i = 0; i < N; ++i) C = C * inv[cnt[i]] % mod; f[0] = 1; for (int i = 0; i < N; ++i) if (cnt[i]) for (int j = nn; j >= cnt[i]; --j) reduce(f[j] += f[j - cnt[i]] - mod); for (int i = 0; i < N; ++i) if (cnt[i]) { for (int j = i + 1; j < N; ++j) if (cnt[j]) ans[i][j] = ans[j][i] = solve(i, j); ans[i][i] = f[nn]; } std::cin >> q; while (q --> 0) { static int x, y; std::cin >> x >> y; x = s[x], y = s[y]; std::cout << C * ans[x][y] % mod << ‘\n‘; } return 0; }