题目链接: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;
}