方块消除 UVA10559

题意:给一排方块,每个方块有一个颜色,每次可以选几个连续颜色相同方块消除,得分为方块数平方,求最大总得分。

按照一般的序列dp思路,dp[i][j]应当从dp[i][k]和dp[k][j]中转移(i<=k<=j),但本题中可能两边都剩下方块一起消,无法转移,状态也不好表示。

我预处理时先用分块的思想,把颜色相同的小块分为一个大块。

所以这个题以[i,j]这个区间中最后一个方块j怎样消除为决策,j可以直接就在当前消除,或者把中间的消除后,和左边一个颜色相同的大块拼起来(这个大块需要枚举).但是注意,和左边某个大块拼起来后,也不一定立即消除,有可能还和左边的左边的一个大块拼起来,所以还需要再开一维,dp[i][j][k]表示j的左边挂着k个和j一个颜色的小块。

看似状态n^3,转移最坏n,但是注意转移时枚举的是大块,一般数据会大大降低时间。还有dp[i][j][k]中的i,j都是大块的端点,每对i,j对应的k也不会很多,所以记搜实际状态数不多(数据组数<=15,980ms)

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
int n,A[500],B[500],L[500],R[500];
bool vis[210][210][210];
LL dp[210][210][210];
using namespace std;
LL Max(LL a,LL b){
	if (a>b) return a;
	else return b;
}
LL Sq(LL a){return a*a;}
LL Dfs(int l,int r,int k){
	LL &ans=dp[l][r][k];
	if (vis[l][r][k]) return ans;
	vis[l][r][k]=1;
	if (l>r) return ans=0;
	
	ans=Dfs(l,L[B[r]]-1,0)+Sq(r-L[B[r]]+1+k);
	for (int i=B[r]-1;i>=B[l];i--)
		if (A[R[i]]==A[r])
			ans=Max(ans,Dfs(l,R[i],k+r-L[B[r]]+1)+Dfs(R[i]+1,L[B[r]]-1,0));
	return ans;
}
void InIt(){
	memset(vis,0,sizeof(vis));
	memset(B,0,sizeof(B));
	memset(L,0,sizeof(L));
	memset(R,0,sizeof(R));
	memset(dp,0,sizeof(dp));
	scanf("%d",&n);
	int i,cnt=0;
	for (i=1;i<=n;i++) scanf("%d",&A[i]);
	for (i=1;i<=n;i++) 
		if (A[i]!=A[i-1]) B[i]=++cnt;
		else B[i]=cnt;
	for (i=1;i<=n;i++) if (!L[B[i]]) L[B[i]]=i;
	for (i=n;i>=1;i--) if (!R[B[i]]) R[B[i]]=i;
}
int main(){
	int test_case;
	scanf("%d",&test_case);
	for (int i=1;i<=test_case;i++){
		InIt();
		printf("Case %d: %lld\n",i,Dfs(1,n,0));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lerbon23james/article/details/80138580
今日推荐