好吧,我想到的是枚举决策。。。
居然是个类似于区间DP的感觉。恩。。确实是呀,只不过是需要在DP的时候附加上额外的条件
定义状态dp[i][j][k]表示区间i~j且右边附加了k个与j同色的方块的最大值
每次考虑把最右边的消去,既然是考虑把最右边的消去的话,那么就有两种消去方法,第一种是直接这一次消去,第二种是留着以后消去。
关于第二种消去的办法是枚举i~j中除去j以外的每段与j同色的色块的右端,考虑把当前的最右边的色块附在这一段的最右边,语言感觉有点没有表述的清楚,
状态转移方程是dp[i][j][k]=dp[i][ri][0]+(j-ri+k)*(j-ri+k),其中ri是把右端消去后的新起始点,也就是右边第一个不与j同色方块的位置
第二种转移则是枚举每一段与j同色的右端,假设为le,方程是dp[i][j][k]=max(dp[i][j][k],dfs(dp[i][le][k+j-ri])+dfs(dp[le+1][ri][0]))相当于两段之和
挺好的题目
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxm=210;
int times,n,kcase,color[maxm],dp[maxm][maxm][maxm],dfs(int i=1,int j=n,int k=0);
void init();
int main(){
ios_base::sync_with_stdio(false);
cin>>times;
while(times--){
cin>>n;
init();
for(int i=1;i<=n;++i)
cin>>color[i];
cout<<"Case "<<++kcase<<": "<<dfs()<<endl;
}
return 0;
}
void init(){
memset(dp,0,sizeof dp);
}
int dfs(int i, int j, int k){
if(i>j)
return 0;
if(dp[i][j][k])
return dp[i][j][k];
int ri=j;
while(ri>=i&&color[j]==color[ri])--ri;
dp[i][j][k]=dfs(i,ri,0)+(j-ri+k)*(j-ri+k);
for(int le=i;le<=ri;++le)
if(color[le+1]!=color[le]&&color[le]==color[j])
dp[i][j][k]=max(dfs(i,le,j-ri+k)+dfs(le+1,ri,0),dp[i][j][k]);
return dp[i][j][k];
}

2万+

被折叠的 条评论
为什么被折叠?



