Codeforces 1110D Jongmah (DP)
阿新 • • 發佈:2019-02-08
ces pri 選擇 mes spa cpp sin 假設 其余
題意:你有n個數字,範圍[1, m],你可以選擇其中的三個數字構成一個三元組,但是這三個數字必須是連續的或者相同的,每個數字只能用一次,問這n個數字最多構成多少個三元組?
解析:首先我們容易發現,我們發現,假設有3個三元組(x, x + 1, x + 2),我們不妨把這3個三元組換成(x, x, x), (x + 1, x + 1, x + 1), (x + 2, x + 2, x + 2)這3個三元組。那麽,對於每個x,最多有2個(x, x + 1, x + 2)這樣的三元組。這樣,每個階段的狀態數就是有限的了。
設dp[i][j][k]為數字1到i,有j個(i - 1, i , i + 1)三元組,k個(i , i + 1, i + 2)三元組可以組成的最多的三元組的數目,我們現在考慮向i + 1轉移。因為前面有j個(i - 1, i , i + 1),k個(i , i + 1, i + 2),假設本來有t個i + 1,那麽現在可用來構成新的三元組的i + 1有t - j - k個。
這t - j - k個i + 1可以用來構成(i + 1, i + 2, i + 3),也可用來構成(i + 1, i + 1, i + 1)。我們就可以枚舉這些i + 1是形成什麽樣的三元組來進行狀態轉移了。初態:dp[0][0][0] = 0,其余負無窮。末態:dp[m + 1][0][0]。因為m + 1肯定沒有數,所以dp[m + 1][0][0]是m + 1處的唯一合法狀態,也就是答案。
代碼:
#include <bits/stdc++.h> #define ls(x) (x << 1) #define rs(x) ((x << 1) | 1) #define lowbit(x) (x & (-x)) #define LL long long #define INF 0x3f3f3f3f using namespace std; const int maxn = 1000010; int a[maxn], cnt[maxn]; int dp[maxn][3][3]; int main () { int n, m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); cnt[a[i]]++; } memset(dp, -0x3f, sizeof(dp)); dp[0][0][0] = 0; for (int i = 0; i <= m + 1; i++) { for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) { if(dp[i][j][k] < 0) continue; int now = cnt[i + 1] - j - k; for (int t = 0; t < 3 && t <= now; t++) { dp[i + 1][k][t] = max(dp[i + 1][k][t], dp[i][j][k] + (now - t) / 3 + t); } } } printf("%d\n", dp[m + 1][0][0]); return 0; }
Codeforces 1110D Jongmah (DP)