Educational Codeforces Round 83 (Rated for Div. 2) E.Array Shrinking(区间dp/合并问题+分段问题)

题目

n(n<=500)个数,第i个数为ai(1<=ai<=1e3),

每次你可以选择两个相邻的且相等(不妨值为v)的数,将这两个数替换为一个v+1的数,后面的数会跟上来

问以这样的方式合并,a[]数组最后最少能剩几个数

思路来源

https://www.cnblogs.com/zxytxdy/p/12454472.html

题解

学了区间dp之后,感觉这个题好sb啊,可惜当时不会orz

两种做法,

第一种,前一半是合并的区间dp,dp[l][r]维护这一段能合成一段的最大值,

只要能合并成一段,就加一个seg[l,r],代价为1,最后用所有seg来为最终的结果做分段的区间dp

第二种,dp[l][r]仍维护这一段能合成一段的最大值,ans[l][r]代表这一段最少剩几个,

如果能合成一段,ans[l][r]显然为1,否则ans[l][r]=min(ans[l][r],ans[l][k]+ans[k+1][r])(l<=k<r)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m,dp[N][N],a[N],f[N];
struct seg{
	int l,r;
}e[N*N];
bool operator<(seg a,seg b){
	return a.r<b.r;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		dp[i][i]=a[i];		
	}
	for(int len=2;len<=n;++len){
		for(int l=1;l+len-1<=n;++l){
			int r=l+len-1;
			dp[l][r]=-1;
			for(int k=l;k<r;++k){
				if(~dp[l][k] && dp[l][k]==dp[k+1][r]){
					dp[l][r]=dp[l][k]+1;
//					printf("[%d,%d]\n",l,r);
					e[++m]=(seg){l,r};
					break;
				}
			}
		}
	}
	sort(e+1,e+m+1);
	int now=1;
	for(int i=1;i<=n;++i){
		f[i]=f[i-1]+1;//f[i]<=i 从前面的段多加一个 
		while(now<=m && e[now].r==i){
			f[i]=min(f[i],f[e[now].l-1]+1);
			now++;
		}
	}
	printf("%d\n",f[n]);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值