有很多楼,每个楼有一个高度 Hi 和一个猫数 Ci, i i i 楼比 j j j 楼高时, j j j 楼的值就会加上 i i i 楼的值,让我们去掉一些楼,使剩下的楼的值中最大值是所有方案里最小的。
首先我们考虑建树,以当前高度最高的点为根节点,它左边是左子树,右边是右子树。
当然,最高的为根。
long long get(long long l,long long r)
{
if(l>r) return 0;
if(l==r) return r;
long long ans=0,mid=0;
for(long long i=l; i<=r; i++)
{
if(h[i]>ans)
{
ans=h[i];
mid=i;
}
}
a[mid].l=get(l,mid-1);
a[mid].r=get(mid+1,r);
return mid;
}
然后我们考虑怎样DP,我们可以设 f [ x ] [ i + j ] f[x][i+j] f[x][i+j] 为当前 x x x 号节点,给左子树 i i i 个炸弹,给右子树 j j j 个炸弹所获得的最小值; f [ x ] [ i + j + 1 ] f[x][i+j+1] f[x][i+j+1] 为当前 x x x 号节点,给左子树 i i i 个炸弹,给右子树 j j j 个炸弹,自己给一个炸弹所获得的最小值;
可得动态转移方程:
f [ x ] [ i + j ] = m i n ( f [ x ] [ i + j ] , m a x ( f [ a [ x ] . l ] [ i ] , f [ a [ x ] . r ] [ j ] ) + c [ x ] ) ; f[x][i+j]=min(f[x][i+j],max(f[a[x].l][i],f[a[x].r][j])+c[x]); f[x][i+j]=min(f[x][i+j],max(f[a[x].l][i],f[a[x].r][j])+c[x]);
i f ( i + j < k ) if(i+j
f [ x ] [ i + j + 1 ] = m i n ( f [ x ] [ i + j + 1 ] , m a x ( f [ a [ x ] . l ] [ i ] , f [ a [ x ] . r ] [ j ] ) ) ; f[x][i+j+1]=min(f[x][i+j+1],max(f[a[x].l][i],f[a[x].r][j])); f[x][i+j+1]=min(f[x][i+j+1],max(f[a[x].l][i],f[a[x].r][j]));
#include
#include
#include
#include
#include
using namespace std;
long long n,k,root,h[100010],c[100010],f[201000][10];
long long v[100010];
struct node
{
long long l,r;
}a[100010];
long long get(long long l,long long r)
{
if(l>r) return 0;
if(l==r) return r;
long long ans=0,mid=0;
for(long long i=l; i<=r; i++)
{
if(h[i]>ans)
{
ans=h[i];
mid=i;
}
}
a[mid].l=get(l,mid-1);
a[mid].r=get(mid+1,r);
return mid;
}
void dfs(long long x)
{
v[x]=1;
if(!v[a[x].l])
dfs(a[x].l);
if(!v[a[x].r])
dfs(a[x].r);
for(long long i=0; i<=k; i++)
for(long long j=0; j<=k-i; j++)
{
f[x][i+j]=min(f[x][i+j],max(f[a[x].l][i],f[a[x].r][j])+c[x]);
if(i+j<k)
f[x][i+j+1]=min(f[x][i+j+1],max(f[a[x].l][i],f[a[x].r][j]));
}
}
int main()
{
memset(f,0x3f,sizeof(f));
f[0][0]=0;
cin>>n>>k;
for(long long i=1; i<=n; i++)
scanf("%lld%lld",&h[i],&c[i]);
root=get(1,n);
dfs(root);
cout<<f[root][k];
return 0;
}