• [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;
    }
    

      

  • 相关阅读:
    Proximal Gradient Descent for L1 Regularization
    使用Spring Security3的四种方法概述
    理解spring对事务的处理:传播性
    MySQL事务隔离级别详解
    Spring 使用注解方式进行事务管理
    Redis的高级应用-安全性和主从复制
    Redis的高级应用-事务处理、持久化、发布与订阅消息、虚拟内存使用
    mysql 语句优化心得
    Maven搭建Spring Security3.2项目详解
    Java网络编程之TCP、UDP
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/10357940.html
Copyright © 2020-2023  润新知