前言
我切掉这道题是命运石之门的选择
正题
题目链接: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{fi−1,k(k≥j),fi,j−1+bi−bj}
这样横着刷的就搞定了,但是还有竖着刷的所以就要加
(
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);
}