NC17137 Removal
原题地址:
数据没锅,是我的锅orz,谢谢邓老师帮我找bug
基本思路:
这题的本质是一个挺简单的计数dp,和这道题其实比较像https://ac.nowcoder.com/acm/contest/4853/C 我们看m比较小所以只要将前i个里取j个变换成前i个里j个不取就行了。
我们设dp[i][j]表示前i个数中j个不取,那么不考虑重复的情况我们可以考虑这样的转移方程: 即在第i个位置取或不取的情况。
那么考虑去重,去重的方法其实和上面那题思路完全一样,对于每个位置a[i]我们直接减去a[i]上一次出现的位置结尾的所有长度相同的子序列,只是对于找长度相同我们做一个转换,前i个里j个不取的子序列的长度即为(i - j),长度相同转化为在上一个位置要几个不取即是解这样一个方程 那么得到去重的转移方程
;根据上面两个转移方程就能成功得到答案了。
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF 0x3f3f3f3f
const int maxn = 1e5 + 50;
const int mod = (int)1e9 + 7;
int n,m,k,a[maxn];
int last[15],dp[maxn][15];//前i个数中j个不取;
signed main() {
while(cin >> n >> m >> k){
mset(last,-1);
mset(dp,0);
rep(i,1,n) cin >> a[i];
rep(i,1,10) dp[i][i] = 1;
rep(i,0,n) dp[i][0] = 1;
rep(i,1,n){
rep(j,1,min(i-1,m)){
dp[i][j] = (dp[i-1][j-1] + dp[i-1][j]) % mod;
int num = last[a[i]] + j - i;//算出长度相等等同于几个不取;
if(last[a[i]] != -1 && num >= 0) dp[i][j] = (dp[i][j] - dp[last[a[i]] - 1][num] + mod) % mod;
}
last[a[i]] = i;//更新这个数字上次出现的位置;
}
cout << dp[n][m] << endl;
}
return 0;
}

京公网安备 11010502036488号