【2017ccpc final G
阿新 • • 發佈:2018-12-16
【連結】
acm.hdu.edu.cn/showproblem.php?pid=6249
【題意】
給你m個區間,要求你選出k個區間,使得區間並的覆蓋範圍最大
1≤T≤100
1≤K≤M
1≤N,M≤2000
1≤Li≤Ri≤N
【思路】
一開始我們得出錯誤的dp轉移:
先按右端點排序,dp[i][j]表示前i個區間集合,當前已經選了j個的最大的覆蓋範圍,但是顯然需要再列舉是哪個右端點轉移過來的。顯然是O(n^3)的複雜度顯然不行,但是我們錯誤地記錄了轉移到的最大的貢獻來自於哪個右端點,其實這樣是錯誤的。哎,思維不夠嚴謹。
正確的做法是:改變dp狀態設計。可以觀察到,n的範圍只有2000,那麼這個條件肯定是要用的。我們設計dp[i][j]表示當前位於值為i的點,並且選了j個區間的最大dp值,顯然,對於一個點,我們會選擇能覆蓋這個點的最遠的區間右端點,維護一下這個,對於每個點,選與不選轉移即可
【程式碼】
#include<bits/stdc++.h> using namespace std; const int maxn = 2e3 + 5; int L[maxn], R[maxn]; int dp[maxn][maxn]; int up[maxn]; int main() { int t; scanf("%d", &t); int ca = 0; while (t--) { memset(dp, 0, sizeof(dp)); memset(up, 0, sizeof(up)); int n, m, k; scanf("%d%d%d", &n, &m, &k); for (int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); for (int j = x; j <= y; j++) { up[j] = max(up[j], y); } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= k; j++) { dp[i][j] = max(dp[i][j], dp[i - 1][j]); if (up[i]) { dp[up[i]][j] = max(dp[up[i]][j], dp[i - 1][j-1] + up[i] - i + 1); } } } printf("Case #%d: %d\n", ++ca, dp[n][k]); } }