Loading

[Nowcoder] 2021牛客国庆集训派对day1 Removal

https://ac.nowcoder.com/acm/contest/21698/E

image


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();
    }
}
posted @ 2021-10-12 23:26  nekko  阅读(42)  评论(0)    收藏  举报