P2101-命运石之门的选择【dp,离散化】

前言

我切掉这道题是命运石之门的选择


正题

题目链接:https://www.luogu.org/problemnew/show/P2101


题目大意

n n n个连在一起的高度 h i h_i hi盒子。一个刷子只能直着刷而且得连续都得刷。求至少刷多少次。


解题思路

f i , j f_{i,j} fi,j表示前 i i i个已经刷完了,上一个高度为 j j j的刷过来。首先我们要把 j j j离散化了。
然后考虑 f i , j = m i n { f i − 1 , k ( k ≥ j ) , f i , j − 1 + b i − b j } f_{i,j}=min\{f_{i-1,k(k\geq j)},f_{i,j-1}+b_i-b_j\} fi,j=min{fi1,k(kj),fi,j1+bibj}
这样横着刷的就搞定了,但是还有竖着刷的所以就要加 ( b [ j ] ! = a [ i ] ) (b[j]!=a[i]) (b[j]!=a[i])
然后对于那个 k k k用前缀合搞定。


c o d e code code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const ll N=5100;
ll n,a[N],b[N],f[2][N],mins,m;
int main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+1+n);
	m=unique(b+1,b+n+1)-(b+1);
	memset(f,0x3f,sizeof(f));
	f[0][0]=0;mins=2147483647;
	for(ll i=1;i<=n;i++)
	{
		memset(f[i&1],0x3f,sizeof(f[i&1]));
		f[i&1][0]=f[~i&1][0];
 	    for(ll j=1;j<=m;j++)
	    {
	    	if(b[j]>a[i]) break;
 	    	f[i&1][j]=min(f[~i&1][j],f[i&1][j-1]+b[j]-b[j-1]);
	    }
	    for(ll j=0;j<=m;j++)
	    {
	    	if(b[j]>a[i]) break;
	    	if(b[j]!=a[i])	f[i&1][j]+=1;
	    	if(i==n) mins=min(f[i&1][j],mins);
		}
		for(ll j=m-1;j>=0;j--)
		  f[i&1][j]=min(f[i&1][j+1],f[i&1][j]);
	}
	printf("%lld",mins);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值