[数学] [dp优化] CF1740F Conditional Mix
首先,每次选择两个交集为空的集合合并,等价于最终将原集合恰好拆分为若干个集合,每个集合内部无重复元素。
不妨记这些集合为
考虑判定
于是不难想到,若有
于是考虑找到一个合法且“字典序”最大的集合
不过比较“字典序”还是太麻烦了,其实可以这样比较,假如
对于刚刚构造的
我们记
于是就容易了,不妨设
于是得到了
代码
写的比较难看。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define ADD(a, b) a = (a + b) % mod
const int N = 2e3 + 5, mod = 998244353;
int n, a[N], cnt[N], Lim[N], ans, f[2][N][N], g[N][N], s[N];
signed main(){
cin >> n;
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]), ++cnt[a[i]];
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
Lim[i] += min(i, cnt[j]);
for(int S = 1; S <= Lim[1]; ++S) f[1][S][S] = 1;
for(int i = 2; i <= n; ++i){
int id = (i & 1), _id = (id ^ 1);
for(int S = 0; S <= Lim[i - 1]; ++S)
for(int j = 0; j <= S / (i - 1); ++j)
g[S][j] = (g[S][j - 1] + f[_id][S][j]) % mod, f[_id][S][j] = 0;
for(int S = 0; S <= Lim[i]; ++S)
for(int j = 0; j <= S / i; ++j)
if(S - j <= Lim[i - 1] && j <= S - j)
f[id][S][j] = (g[S - j][min(S - j, (S - j) / (i - 1))] - g[S - j][min(j - 1, (S - j) / (i - 1))] + mod) % mod;
}
for(int i = 0; i <= n; ++i) ADD(ans, f[n & 1][n][i]);
cout << ans;
return 0;
}