前言
我切掉这道题是命运石之门的选择
正题
题目链接:https://www.luogu.org/problemnew/show/P2101
题目大意
nnn个连在一起的高度hih_ihi盒子。一个刷子只能直着刷而且得连续都得刷。求至少刷多少次。
解题思路
fi,jf_{i,j}fi,j表示前iii个已经刷完了,上一个高度为jjj的刷过来。首先我们要把jjj离散化了。
然后考虑fi,j=min{fi−1,k(k≥j),fi,j−1+bi−bj}f_{i,j}=min\{f_{i-1,k(k\geq j)},f_{i,j-1}+b_i-b_j\}fi,j=min{fi−1,k(k≥j),fi,j−1+bi−bj}
这样横着刷的就搞定了,但是还有竖着刷的所以就要加(b[j]!=a[i])(b[j]!=a[i])(b[j]!=a[i])
然后对于那个kkk用前缀合搞定。
codecodecode
#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);
}