[Nowcoder] 2021牛客国庆集训派对day1 Removal
https://ac.nowcoder.com/acm/contest/21698/E
f[i][j]
前 i 个删了 j 个,本质不同子序列个数
对于 s[i]
考虑 s[k]
满足 s[k]=s[i]
且 k
最大
假设 f[i-*][*]
都不重不漏
首先有 f[i][j] = f[i - 1][j] + f[i - 1][j - 1]
那么会有一些重复计数的
考虑 \(w=xs_k=xs_i\),那么所有以 \(s_k\) 结尾的子序列都会被计算一次
换句话说,我们希望 f[i][j]
中,所有以 s[i]
结尾的子序列都在 i
处被统计到
可递归的,对于 f[i-*][*]
都满足在 i-*
处被统计到(即 s[k]
),那么重复的状态就是 \(w=xs_k=xs_i\)
考虑一下 f[k][j]
于是有 f[i][j] = f[i - 1][j] + f[i - 1][j - 1] - f[k - 1][j - (i - k)]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, m, k, s[N], lst[30];
ll f[N][30];
void add(ll &a, ll b) {
a = (a + b) % mod;
}
void sol() {
memset(lst, 0, sizeof lst);
f[0][0] = 1;
for(int i = 1 ; i <= n ; ++ i) {
for(int j = 0 ; j <= min(i, m) ; ++ j) {
if(j >= 1) add(f[i][j], f[i - 1][j - 1]);
add(f[i][j], f[i - 1][j]);
if(lst[s[i]] >= 1 && j >= i - lst[s[i]]) add(f[i][j], -f[lst[s[i]] - 1][j - (i - lst[s[i]])]);
}
lst[s[i]] = i;
}
cout << (f[n][m] % mod + mod) % mod << endl;
for(int i = 0 ; i <= n ; ++ i) {
for(int j = 0 ; j <= m ; ++ j) {
f[i][j] = 0;
}
}
}
int main() {
ios :: sync_with_stdio(0);
cin.tie(0), cout.tie(0);
while(cin >> n >> m >> k) {
for(int i = 1 ; i <= n ; ++ i) {
cin >> s[i];
}
sol();
}
}