[COCI2020-2021#6] Anagramistica

[COCI2020-2021#6] Anagramistica

题意

给定 \(n\) 个字符串和正整数 \(k\)

定义两个字符串相似当且仅当两个字符串排序后相等。

可以从中选出一些字符串,求有多少种方案,使得其中恰好有 \(k\) 对字符串相似。

思路

先将所有字符串排序,相同的归为一类,求出 \(cnt_i\) 表示第 \(i\) 种字符串的个数。

定义 \(dp_{i,j}\) 表示前 \(i\) 种字符串,有 \(j\) 对相似的方案数。

转移方程:\(dp_{i,j} = \sum dp_{i-1,j-C_k^{2}}\times C_{cnt_i}^{k}\)

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e3 + 5;
const int mod = 1e9 + 7;
int n, k, dp[N][N], fac[N], facinv[N];
map <string, int> M;
int qpow(int a, int b) {
	int res = 1;
	for (; b; b >>= 1, a = a * a % mod) 
		if (b & 1) res = res * a % mod;
	return res;
}
int C(int x, int y) {
	return fac[x] * facinv[y] % mod * facinv[x - y] % mod;
}
void solve() {
	cin >> n >> k;
	for (int i = 1; i <= n; i ++) {
		string s; cin >> s;
		sort(s.begin(), s.end());
		M[s] ++;
	}
	fac[0] = facinv[0] = 1;
	for (int i = 1; i <= 2000; i ++) {
		fac[i] = fac[i - 1] * i % mod;
		facinv[i] = qpow(fac[i], mod - 2);
	}
	dp[0][0] = 1; int l = 0;
	for (auto p : M) {
		l ++;
		for (int i = 0; i <= k; i ++)
			for (int j = 0; j <= p.second; j ++) {
				if (i < j * (j - 1) / 2) continue;
				dp[l][i] += dp[l - 1][i - j * (j - 1) / 2] * C(p.second, j);
				dp[l][i] %= mod;
			}
	}
	cout << dp[l][k] << "\n"; 
}
signed main() {
	int Case = 1;
//	cin >> Case;
	while (Case --)
		solve();
	return 0;
}
posted @ 2024-09-11 21:53  maniubi  阅读(5)  评论(0编辑  收藏  举报