• Codeforces 1111D(退背包、排列组合)


    要点

    • 优质题解
    • 因为只有某type坏人全部分布在同一撇时,才能一次消灭。所以题目安排完毕后一定是type(x)和type(y)占一半,其余占另一半。
    • 实际情况只有52*52种,则预处理答案
    • 枚举某两种,并连续两次使用退背包得到无排列的方案数,真·答案是有排列的,乘上一个排列数即可,而根据式子,排列数恰好与方案细节无关,是个与(|s|)和全部(cnt[i])有关的定值
    const int maxn = 1e5 + 5;
    const int mod = 1e9 + 7;
    
    string s;
    int q, len, x, y;
    int cnt[55];
    ll f[maxn >> 1], g[maxn >> 1], h[maxn >> 1], Ans[55][55];
    ll fac[maxn], finv[maxn];
    
    inline int id(char c) {
    	return c >= 'A' && c <= 'Z' ? c - 'A' + 26 : c - 'a';
    }
    
    ll ksm(ll a, int b) {
    	ll res = 1LL;
    	for (; b; b >>= 1) {
    		if (b & 1)	res = res * a % mod;
    		a = a * a % mod;
    	}
    	return res;
    }
    
    ll pre() {
    	fac[0] = 1;
    	for (int i = 1; i <= len; i++) {
    		fac[i] = fac[i - 1] * i % mod;
    	}
    	finv[len] = ksm(fac[len], mod - 2);
    	for (int i = len - 1; i; --i) {
    		finv[i] = finv[i + 1] * (i + 1) % mod;
    	}
    
    	ll res = 2LL * fac[len / 2] % mod * fac[len / 2] % mod;
    	for (int i = 0; i < 52; i++) {
    		if (!cnt[i])	continue;
    		res = res * finv[cnt[i]] % mod;
    	}
    	return res;
    }
    
    int main() {
    	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    
    	cin >> s;
    	for (auto i : s) {
    		cnt[id(i)]++;
    	}
    	len = s.length();
    	ll base = pre();
    
    	f[0] = 1;
    	for (int i = 0; i < 52; i++) {
    		if (!cnt[i])	continue;
    		for (int j = len / 2; j >= cnt[i]; --j) {
    			f[j] = (f[j] + f[j - cnt[i]]) % mod;
    		}
    	}
    	for (int i = 0; i < 52; i++) {
    		if (!cnt[i])	continue;
    		for (int j = 0; j <= len / 2; j++) {
    			if (j < cnt[i])	g[j] = f[j];
    			else	g[j] = (f[j] - g[j - cnt[i]] + mod) % mod;
    		}
    		Ans[i][i] = base * g[len / 2] % mod;
    		for (int j = i + 1; j < 52; j++) {
    			if (!cnt[j])	continue;
    			for (int k = 0; k <= len / 2; k++) {
    				if (k < cnt[j])	h[k] = g[k];
    				else	h[k] = (g[k] - h[k - cnt[j]] + mod) % mod;
    			}
    			Ans[i][j] = Ans[j][i] = base * h[len / 2] % mod;
    		}
    	}
    
    	for (cin >> q; q; q--) {
    		cin >> x >> y;
    		cout << Ans[id(s[x - 1])][id(s[y - 1])] << '
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    我的黑客偶像
    IEEE754浮点数
    罗马数字转化为阿拉伯数字
    2020-2021-1 20201221 《信息安全专业导论》第三周学习总结
    base64
    2020-2021-1 20201221曾思源《第二周学习总结》
    师生关系
    教材速读问题
    20201221曾思源自我介绍
    20201221 曾思源 第一周学习总结
  • 原文地址:https://www.cnblogs.com/AlphaWA/p/10829191.html
Copyright © 2020-2023  润新知