题意:给定n个数ai,再给定m个公差di。每次从ai中选择连续的x个数(x>=2),若这x个数构成等差数列且公差在bi中存在,则可以删去这x个数。求最多可以删去多少数
dp[i][j]:i~j最多可以删去多少数
初始化j-i==1和j-i==2的情况。
判断端点转移即可
#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 310;
int a[maxn],D[maxn];
int dp[maxn][maxn];
int n, m;
map <int, bool> vis;
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
vis.clear();
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1, x; i <= m; ++i) scanf("%d", &x), vis[x]=1;
memset(dp, 0, sizeof(dp));
for(int i = 1; i < n; ++i)//长度为2
if(vis[a[i+1]-a[i]])
dp[i][i+1] = 2;
for(int i = 1; i < n-1; ++i)//长度为3
if(a[i]-a[i+1]==a[i+1]-a[i+2] && vis[a[i+1]-a[i]]) dp[i][i+2] = 3;
else dp[i][i+2] = max(dp[i][i+1],dp[i+1][i+2]);
for(int len = 4; len <= n; ++len)//dp2和3的区间,合并大区间即可
for(int l = 1; l+len-1<=n; ++l)
{
int r = l+len-1;
if(dp[l+1][r-1]==len-2 && vis[a[r]-a[l]]) dp[l][r] = len;
if(dp[l+2][r-1]==len-3 && vis[a[l+1]-a[l]] && a[l]-a[l+1]==a[l+1]-a[r])
dp[l][r] = len;
if(dp[l+1][r-2]==len-3 && vis[a[r]-a[r-1]] && a[l]-a[r-1]==a[r-1]-a[r])
dp[l][r] = len;
for(int k = l; k < r; ++k)
dp[l][r] = max(dp[l][r], dp[l][k]+dp[k+1][r]);
}
printf("%d\n", dp[1][n]);
}
return 0;
}