当前位置 : 主页 > 大数据 > 区块链 >

[CF1111D]Destroy the Colony

来源:互联网 收集:自由互联 发布时间:2021-06-22
题目大意: 有一个长度为$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;
}
网友评论