题意
给定一个长度为 $n$ 的数组,求长度为 $n-m$ 的不同子序列个数。($1<=n<=1e5, m<=10$)
Solution
$dp[i][j]$ 表示长度为 $i$,删除 $j$ 个元素的子序列个数,不考虑重复的话,有 $dp[i][j] = dp[i-1][j] + dp[i-1][j-1]$(即已经删除了 $j$ 个和已经删除了 $j-1$ 个再删除这一个的情况)。
考虑去重。如果是单纯求不限长度的不同子序列的去重,容易得到:$dp[i] -= dp[pre[a[i]] - 1]$ ($pre[a[i]]$ 为上一次 $a[i]$ 出现的位置),在此题中也是同理,我们需要剔除 $[pre[a[i]], i]$ 之间的元素,假设我们当前需要剔除 $j$ 个元素,那么在$pre[a[i]]-1$之前我们先需要剔除 $j-(i-pre[a[i]])$ 个元素, $dp[i][j] -= dp[pre[a[i]]-1][j-(i-pre[a[i]])]$,初始化为所有的 $dp[i][0] = 1$。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| #include <bits/stdc++.h> using namespace std; const int N = 1e5 + 5; const int mod = 1e9 + 7; int n, m, k, pre[N], dp[N][12]; int main() { while (cin >> n >> m >> k) { memset(dp, 0, sizeof(dp)); memset(pre, 0, sizeof(pre)); for (int i = 0; i <= n; i++) dp[i][0] = 1; for (int i = 1; i <= n; i++) { int x; cin >> x; for (int j = 1; j <= min(i, m); j++) { dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1]) % mod; if (pre[x] && j - (i - pre[x]) >= 0) dp[i][j] = (dp[i][j] - dp[pre[x] - 1][j - (i - pre[x])] + mod) % mod; } pre[x] = i; } cout << dp[n][m] << '\n'; } return 0; }
|