UVA 10559 Blocks——区间dp

题目:https://www.luogu.org/problemnew/show/UVA10559

应该想到区间dp。但怎么设计状态?

因为连续的东西有分值,所以应该记录一下连续的有多少个。

  只要记录与边界连续的有多少个就能涵盖所有的连续了。只记一边的边界即可。

两个转移:用掉记录的那些连续的 或 在自己区间中再找一个一样颜色的使连续数量+1。

  用掉了以后剩余部分的连续长度就是0。也许 j-1 和 j 同色,但这个可以在另一个转移里体现,所以没问题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=205;
int T,n,a[N],dp[N][N][N];
int rdn()
{
    int ret=0,fx=1; char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')fx=-1; ch=getchar();}
    while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
    return ret*fx;
}
void init()
{
    memset(dp,0,sizeof dp);
}
int main()
{
    T=rdn();
    for(int t=1;t<=T;t++)
    {
        init();
        n=rdn(); for(int i=1;i<=n;i++) a[i]=rdn();
        for(int i=1;i<=n;i++)
            for(int k=0;k<=(n-i);k++)
                dp[i][i][k]=(k+1)*(k+1);
        for(int d=2,lm=n-d+1;d<=n;d++)
            for(int i=1,j,LM;i<=lm;i++)
            {
                j=i+d-1; LM=n-j;
                for(int k=0;k<=LM;k++)
                {
                    dp[i][j][k]=dp[i][j-1][0]+(k+1)*(k+1);
                    for(int l=i;l<j;l++)
                        if(a[l]==a[j])
                            dp[i][j][k]=max(dp[i][j][k],
                                            dp[i][l][k+1]+dp[l+1][j-1][0]);
                    //printf("dp[%d][%d][%d]=%d
",i,j,k,dp[i][j][k]);
                }
            }
        printf("Case %d: %d
",t,dp[1][n][0]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9672972.html