hdu5693 区间dp

版权声明:转载请注明出处 https://blog.csdn.net/jay__bryant/article/details/82430732

题意:给定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;
}

猜你喜欢

转载自blog.csdn.net/jay__bryant/article/details/82430732