链接:E-Removal
题意:给出序列 s1, s2, ..., sn ,1<=s[i]<=10。问删除m个数后,有多少种不同的序列。
题解:定义dp[i][j]代表长度为i,最末尾的数字为j的子序列方案数,sum[i]代表长度为i的子序列个数。
sum[0] = 1。
从 1 ~ n 遍历序列,当遍历到 s[i] 时 sum[1] ~ sum[i] 就会增加一些以 s[i] 结尾的情况。状态转移:sum[j] += (sum[j-1] - dp[j][s[i]]) % mod。多增加的情况就是 sum[j-1] 后面在增加一个 s[i] ,但是如果以 s[i] 结尾的序列以前就出现过,那么新增加的情况中就会有 dp[j][s[i]] 个重复的情况,减去即可。dp[j][s[i]] = sum[j-1],因为结尾是 s[i] 已经定了,能变得就只剩下前面 j-1 个了。
#include <bits/stdc++.h> using namespace std; const double EPS = 1e-6; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; const int maxn = 1e5 + 10; int n, m, k; int s[maxn]; long long dp[maxn][11]; long long sum[maxn]; int main() { while(scanf("%d%d%d", &n, &m, &k) != EOF){ for(int i = 1; i <= n; i++) scanf("%d", &s[i]); memset(dp, 0, sizeof(dp)); memset(sum, 0, sizeof(sum)); sum[0] = 1; for(int i = 1; i <= n; i++){ for(int j = i; j >= 1 && j >= i - m; j--){ sum[j] += (sum[j-1] - dp[j][s[i]]) % mod; dp[j][s[i]] = sum[j-1]; } } printf("%lld\n", (sum[n-m] % mod + mod) % mod); } return 0; }