• 题解 POJ1390 【Blocks】


    题目链接:Link

    Problem

    Solution

    首先不难想出一个二维的dp,然后你会发现你被这玩意儿弄跪了:

    1
    10
    9 1 1 9 1 10 1 10 8 9 
    

    二维dp的问题在于:已经积攒起来的方块只能随着分治的过程下放,没法积攒起来备用。
    因此我们可以把维度增加一维,即: $ f(i,j,k)= $ 区间i到j,且在j的右侧已积累了k个与j号方块颜色相同的方块,此时的最优解
    显然有两种选择。
    第一种:先合并再说,此时 $ f(i,j,k)=f(i,j-1,0)+(k+c_j)^2 $
    第二种:先对里面的动手,则必然存在一个p,其中 $ i le p < j $ , 且 $ b_p = b_j $ ,先把p+1到j-1之间的合并掉,此时: $ f(i,j,k)=f(i,j,k+c_j)+f(p+1,j-1,0) $

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=205;
    int T,kase,n,a[maxn],f[maxn][maxn][maxn],b[maxn],c[maxn],tot;
    int dp(int i,int j,int k)
    {
    	int &res=f[i][j][k];
    	if(res) return res;
    	if(i==j) return res=(c[i]+k)*(c[i]+k);
    	res=dp(i,j-1,0)+(k+c[j])*(k+c[j]);
    	for(int p=i;p<j;p++)
    		if(b[p]==b[j]) res=max(res,dp(i,p,k+c[j])+dp(p+1,j-1,0));
    	return res;
    }
    int main()
    {
    	#ifdef local
    	freopen("pro.in","r",stdin);
    	#endif
    	scanf("%d",&T);
    	while(T-->0)
    	{
    		scanf("%d",&n);
    		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    		tot=0;
    		int lst=0;
    		for(int i=1;i<=n;i++)
    		{
    			if(a[i]!=lst) { b[++tot]=a[i]; c[tot]=1; lst=a[i]; }
    			else c[tot]++;
    		}
    		memset(f,0,sizeof(f));
    		for(int i=1;i<=tot;i++) f[i][i][0]=c[i]*c[i];
    		printf("Case %d: %d
    ",++kase,dp(1,tot,0));
    	}
    	return 0;
    }
    
  • 相关阅读:
    【Day 04】 德州实行最严堕胎法,女性权益何去何从?
    【Day 03】 刚出生就遭遇疫情的娃娃们,将受到哪些影响?
    【Day 01】 房子不用买了,打印出来就能住:3D打印将如何改变居住生态?
    docker安装mysql-MacBook pro m1芯片
    jmeter调接口报415
    安装jenkins
    好用的编辑器总结
    屏障、释放一致性及原子操作
    Java的锁机制
    Java线程模型
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11622914.html
Copyright © 2020-2023  润新知