题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5693
解题思路:连续消除k个数,可以表示为连续消去了若干次2个数,和若干次3个数。即k = 2*i + 3*j,那么每次可以消去2个数,或者3个数。
dp[i][j]表示区间(i,j)最多可以消去的数,如果我要消去i和j,那么就必须要dp[i+1][j-1] == j - i - 1,即中间的数全部被消除了。
如果要消去i,k,j,(i,k)为一个区间,(k+1,j)为另一个区间。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 305;
int n,m,dp[maxn][maxn],c[maxn][maxn];
int a[maxn];
int main()
{
int t,d;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
memset(c,0,sizeof(c));
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
for(int i = 1; i <= m; i++)
{
scanf("%d",&d);
for(int j = 1; j <= n; j++)
for(int k = j + 1; k <= n; k++)
if(a[k] - a[j] == d)
c[j][k] = 1;
}
for(int l = 2; l <= n; l++)
for(int i = 1; i <= n; i++)
{
int j = i + l - 1;
if(j > n) break;
dp[i][j] = max(dp[i+1][j],dp[i][j-1]);
if(c[i][j] && dp[i+1][j-1] == j - i - 1)
dp[i][j] = max(dp[i][j],dp[i+1][j-1] + 2);
for(int k = i; k < j; k++)
dp[i][j] = max(dp[i][j],dp[i][k] + dp[k+1][j]);
//考虑取中间的k
for(int k = i + 1; k < j; k++)
{
if(c[i][k] && dp[i+1][k-1] == k - i - 1)
dp[i][j] = max(dp[i][j],dp[i+1][k-1] + dp[k+1][j] + 2);
if(c[k][j] && dp[k+1][j-1] == j - k - 1)
dp[i][j] = max(dp[i][j],dp[i][k-1] + dp[k+1][j-1] + 2);
if(c[i][k] && c[k][j] && a[k] - a[i] == a[j] - a[k] && dp[i+1][k-1] == k - i - 1 && dp[k+1][j-1] == j - k - 1)
dp[i][j] = max(dp[i][j],j - i + 1);
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}