[CF1111D]Destroy the Colony
Posted memory-of-winter
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1111D]Destroy the Colony相关的知识,希望对你有一定的参考价值。
题目大意:有一个长度为$n(nleqslant10^5,n=0pmod2)$的字符串,字符集大小为$52$,有$q(qleqslant10^5)$次询问,每次询问第$x,y$个字符在这个字符串的同一侧,并且所有相同字符在字符串的同一侧的方案数。
题解:因为字符集大小只有$52$,所以本质不同的询问只有$52 imes52$种,预处理。
发现若确定了左右各放那几种字符后方案数是一定的,为$dfrac{left(dfrac n2! ight)^2}{prodlimits_{i=1}^{52}cnt_i!}$,$cnt_i$表示字符$i$出现次数。只需要求出左边可以放的字符种类,乘上这个数就是答案。
考虑$DP$,若正常的做,不加入$x,y$两种字符,复杂度是$O(52^3 imes n)$,不可以通过。发现最多只有两种字符不加入,可以退背包,就倒着做背包部分即可,复杂度$O(52^2 imes 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 << ‘ ‘; } return 0; }
以上是关于[CF1111D]Destroy the Colony的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces1111D Destroy the Colony 退背包+组合数
a low memory warning should only destroy the layer’s bitmap
CodeCraft-19 and Codeforces Round #537 (Div. 2) - D. Destroy the Colony(动态规划+组合数学)
Write a function to add two polynomials. Do not destroy the input. Use a linked list implementation
Java重写父类使用@Override时出现The method destroy() of type xxx must override a superclass method的问题解决