POJ 1390 Blocks

POJ

算法:区间 D P DP DP

状态:
f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示消去 i − j i-j ij这段区间, k k k是右边可以利用的数(就是留下来准备合在一起的数)

每次消去这段数有两种方法:

  • 直接消去这个数
  • 留下这个数,枚举 i i i,消掉 i − k i-k ik这段,然后和 i i i合到一起再消掉

转移方程:

直接消去的方式:

f[l][r][x]=dfs(l,r-1,0)+num*num;//直接消去右边 

留下这个数和其他数合并后消去的方式:

if(co[i]==co[r])
 f[l][r][x]=max(f[l][r][x],dfs(i+1,r-1,0)+dfs(l,i,num));//区间dp,先留着r,消掉i+1到r这段,在消掉l到i这段 
注意:
  • 由于状态是 O ( n 3 ) O(n^3) O(n3)的,转移是 O ( n ) O(n) O(n)的,总复杂度为 O ( n 4 ) O(n^4) O(n4)
  • 预处理读数时可以先把相同的合在一起,区间长度减小了
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define rep(i,a,b) for(register int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int maxn=1e5+10;
const int maxm=1e3+10;
int n;
int f[210][210][210];
int len[maxm],co[maxm];

template <class t> inline void read(t &x) {
	x=0;char ch=getchar();int f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
	x*=f;
}

int dfs(int l,int r,int x) {
	int num=len[r]+x;
	if(l>r) return 0;
	if(l==r) return num*num;
	if(f[l][r][x]!=-1) return f[l][r][x];
	f[l][r][x]=dfs(l,r-1,0)+num*num;//直接消去右边 
	for(int i=l;i<=r-1;i++)
		if(co[i]==co[r])
			f[l][r][x]=max(f[l][r][x],dfs(i+1,r-1,0)+dfs(l,i,num));//区间dp,先留着右区间一块,消完中间再消右边 
	return f[l][r][x];
}

void readdata() {
	int T;read(T);
	int cnt=0;
	while(T--) {
		cnt++;
		read(n);
		memset(f,-1,sizeof(f));
		int tot=1;
		rep(i,1,n) {
			int x;read(x);
			if(i==1) {co[1]=x;len[1]=1;continue;}
			if(i!=1 && x==co[tot]) {
				co[i]=tot;
				len[tot]++;
			}
			else {
				tot++;
				len[tot]=1;
				co[tot]=x;
			}
		}
		printf("Case %d: %d\n",cnt,dfs(1,tot,0));
	}
}

int main() {
	freopen("input.txt","r",stdin);
	//freopen("fire.out","w",stdout);
	readdata();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值