Problem Codeforces Global Round 1 - D. Jongmah
Time Limit: 3000 mSec
Problem Description
Input
Output
Print one integer: the maximum number of triples you can form.
Sample Input
10 6
2 3 3 3 4 4 4 5 5 6
Sample Output
3
题解:动态规划,对这种状态定义不熟悉,主要还是没有发现最优方案所具有的性质,其实个人感觉dp往往是在一定的观察的基础上进行的,发现最优结果所必须具有的一些特征,然后利用这种特征减少状态总数,使得dp能够进行。这道题的一个性质就是我们可以让最优结果中对每个i,不会出现三个及三个以上(i, i+1, i+2)型的三元组,因为这样的三元组可以被3个i,3个i+1,3个i+2所替代,而不产生任何影响,这样一来我们就可以对每个i,枚举它所组成的三元组的个数,具体状态定义:
dp[i][j][k],考虑前i种数,(i-1, i, i+1)有j个,(i, i+1, i+2),有k个的最多三元组数
不记录(i-2, i-1, i)的个数是因为在状态转移时用不到,用dp[i][j][k]更行dp[i+1][k][t]即可。转移方程很简单,详见代码。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define REP(i, n) for (int i = 1; i <= (n); i++) 6 #define sqr(x) ((x) * (x)) 7 8 const int maxn = 1000000 + 100; 9 const int maxm = 200000 + 100; 10 const int maxs = 10000 + 10; 11 12 typedef long long LL; 13 typedef pair<int, int> pii; 14 typedef pair<double, double> pdd; 15 16 const LL unit = 1LL; 17 const int INF = 0x3f3f3f3f; 18 const double eps = 1e-14; 19 const double inf = 1e15; 20 const double pi = acos(-1.0); 21 const int SIZE = 100 + 5; 22 const LL MOD = 1000000007; 23 24 int n, m; 25 int a[maxn]; 26 int dp[maxn][3][3]; 27 28 int main() 29 { 30 ios::sync_with_stdio(false); 31 cin.tie(0); 32 //freopen("input.txt", "r", stdin); 33 //freopen("output.txt", "w", stdout); 34 cin >> n >> m; 35 int x; 36 for (int i = 0; i < n; i++) 37 { 38 cin >> x; 39 a[x]++; 40 } 41 memset(dp, -INF, sizeof(dp)); 42 dp[0][0][0] = 0; 43 for (int i = 0; i <= m; i++) 44 { 45 for (int j = 0; j < 3; j++) 46 { 47 for (int k = 0; k < 3; k++) 48 { 49 int lim = a[i + 1] - j - k; 50 if (lim < 0) 51 continue; 52 for (int t = 0; t < 3 && t <= lim; t++) 53 { 54 dp[i + 1][k][t] = max(dp[i + 1][k][t], dp[i][j][k] + t + (lim - t) / 3); 55 } 56 } 57 } 58 } 59 cout << dp[m + 1][0][0] << endl; 60 return 0; 61 }