题目
题意:
有n个数,对于每个数i,可以自己用3个来形成一个答案,或者是用连续的3个数形成一个答案。输出最多的答案数。
分析:
对于每一个元素,它只有三种状态:1:[i-2,i-1,i]、2:[i-1,i,i+1]、3:[i,i+1,i+2]。并且这三种状态均不超过3种,如果超过就直接用每个元素自己的3个就可以了。既然每个元素只有3种状态,那么我们就可以用动态规划了。dp[i][j][k][l]表示考虑[1…i]且i的第1种状态有j个,第二个状态有k个,第三个状态有l个的最多方案数。我们注意到,第一种状态可以用前一个元素的第2中状态表示,并且第一种状态不会对后面的答案产生影响,是无用状态,所以我们就省略了这一层的枚举。
考虑转移,dp[i][k[l] = dp[i-1][j][k]+l+(cnt[i]-j-k-l)/3。当前状态的三个状态,有两个状态由前面的转移,剩下的一个状态枚举出来即可。
#include <iostream>
using namespace std;
int dp[1000005][3][3],num[1000005];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
num[x] ++;
}
for (int i = 1; i <= m; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
for (int l = 0; l < 3 && j + k + l <= num[i]; l++)
{
dp[i][k][l] = max(dp[i][k][l],dp[i-1][j][k] + l + (num[i] - j - k - l) / 3);
}
}
}
}
cout << dp[m][0][0] << '\n';
return 0;
}