C. Tenzing and Balls
https://codeforces.com/problemset/problem/1842/C
题意:给定n个数,现在要按照规则删除数组中的数,问最多能删多少?规则:i < j且a[i] == a[j],那么可以删除[i, j]区间的所有数。
思路:区间dp,dp[i]代表区间[1, i]内,删完数字后剩下的数字的最小数量。dp[i] = min(dp[i - 1] + 1, rec[a[i]]),其中rec[a[i]]表示如果a[i]作为区间左端点被删除后,[1, i]区间内剩余其他数字的最小数量。 最后答案就是n - dp[n - 1],其中dp[0] = 1, rec[a[0]] = 0(0-indexed)。
总结:这种问题,从全局来思考,每个数字只有作为左端点,在区间内,或者右端点,或者不删除这几种情况。考虑最后一个位置n,如果不删除,则[1, n]少删除一个数,则剩下的数多一个,说明dp[n] = dp[n - 1] + 1。如果删除,那么要找到之前a[n]出现的位置m,并且我们还要知道dp[m - 1],也就是如果位置n要被删除,那么应该是dp[n] = dp[m - 1],因为[m, n]的数都被删了。但是如果一个数字出现了多次,我们就不能精确的找到m,所以我们干脆维护每个数字作为左端点时,前面剩余没被删的数的最小值,就是dp[m - 1]了。。。今日脾气暴躁
inline void solve() {
int n;
cin >> n;
vector<int> a(n);
for (auto& x : a) {
cin >> x;
}
vector<int> dp(n);
vector<int> rec(n + 1, 0x3f3f3f3f);
dp[0] = 1;
rec[a[0]] = 0;
for (int i = 1; i < n; ++i) {
dp[i] = min(dp[i - 1] + 1, rec[a[i]]);
rec[a[i]] = min(rec[a[i]], dp[i - 1]);
}
cout << n - dp[n - 1] << '\n';
}

浙公网安备 33010602011771号