一道区间dp题

9 篇文章 0 订阅
1 篇文章 0 订阅

题意

你有一个有序的数组,现在要插入一个新的数,相信你一定学过二分查找,也知道最坏情况下需要比较几次才能找到新的数该插入什么位置,但是现在,我们稍微改变下套路,把新的数与数组中的每一个数比较都会有一个特定的代价,代价在1-9之间,求最坏情况下,假设你采用最优的比较策略,你会花费多少费用插入新的数。

数据范围

t ( t ≤ 10 ) t(t\le 10) t(t10)组数据,数组大小 n ≤ 100000 n\le 100000 n100000

解法

首先考虑一个常规的区间dp: f [ l ] [ r ] 表 示 查 询 [ l , r ] 中 任 意 一 个 数 的 最 大 代 价 f[l][r]表示查询[l,r]中任意一个数的最大代价 f[l][r][l,r]
转移: f [ l ] [ r ] = m i n k = l r ( m a x ( f [ l ] [ k − 1 ] , f [ k + 1 ] [ r ] ) + a [ k ] ) f[l][r]=min_{k=l}^r(max(f[l][k-1],f[k+1][r])+a[k]) f[l][r]=mink=lr(max(f[l][k1],f[k+1][r])+a[k])
这样做是 O ( n 3 ) O(n^3) O(n3)的,一般来见似乎没有什么办法优化,但是我们发现最终答案非常的小,所以考虑换一种dp状态:
f [ l ] [ k ] 表 示 以 l 为 左 节 点 , 代 价 为 k 时 最 远 的 右 端 点 f[l][k]表示以l为左节点,代价为k时最远的右端点 f[l][k]lk
转移就也是把两个区间拼起来

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
inline int read(){
	char c=getchar();int t=0,f=1;
	while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
	while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
	return t*f;
}
int t,n,a[maxn],at[maxn][10],las[maxn],f[maxn][200];
char s[maxn];
signed main(){
	t=read();
	for(int x=1;x<=t;x++){
		scanf("%s",s+1);n=strlen(s+1);
		memset(f,0,sizeof(f));memset(las,0,sizeof(las));
		for(int i=1;i<=n;i++){
			a[i]=s[i]-'0';
		}
		for(int i=1;i<=n;i++){
			las[a[i]]=i;
			for(int j=1;j<=9;j++)at[i][j]=las[j];//at是序列自动机
		}
		for(int i=1;i<=n+1;i++){
			for(int j=0;j<=180;j++){
				f[i][j]=i-1;
			}
		}
		for(int i=n;i>=1;i--){//倒着转移
			for(int j=1;j<=180;j++){
				f[i][j]=f[i][j-1];
				for(int d=1;d<=min(j,9);d++){
					int p=at[f[i][j-d]+1][d];
					if(p<i)continue;
					f[i][j]=max(f[i][j],f[p+1][j-d]);
				}
			}
		}
		for(int i=0;i<=180;i++)
		if(f[1][i]==n){printf("Case #%d: %d\n",x,i);break;}
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值