鱼肉炸弹题解

题目

题目描述

舒克和贝塔终于下定决心要去营救被关押在众猫聚居的\(A\)城中的大米。

\(A\)城的构造是很奇怪的。\(A\)城中的所有\(N\)栋建筑沿着一条直线排列,没有两栋楼的高度相同,而大米就被关押在其中的某栋建筑中。每一栋建筑的顶上都有一些猫在看守。如果按照从一端到另一端的顺序将所有的建筑编号为\(1\)~\(N\),那么第\(i\)栋建筑的高度为\(Hi\),顶上开始时的猫的数量为\(Ci\)

每一只猫不但可以看守住其所在建筑的楼顶,还可以看守住那些比它所在建筑要低的楼的楼顶,前提是没有被其他楼挡住\(A\)城中的建筑是很高的,高到可以忽略他们之间的距离和它们的水平面积。于是可以认为,\(i\)上的猫能够看守楼\(j\)的楼顶,当且仅当楼\(i\)的高度不低于楼\(j\),且楼\(i\)到楼\(j\)之间的所有楼房的高度都低于楼\(i\)

现在神勇的贝塔已经潜入\(A\)城内部营救大米,而舒克则负责驾驶直升机提供空中支援。按照约定,贝塔找到并救出大米后会爬上楼顶释放信号让舒克前来接应。

舒克的飞机上装备了\(K\)枚鱼肉炸弹。每一枚鱼肉炸弹都可以在被投放到某一座楼的楼顶一段时间后使该楼所有猫失去行动能力。假设第\(i\)栋楼被\(Si\)只猫看守(注意\(Si\)只猫包括在该楼上的\(Ci\)只,已经在其他楼上的所有能看守该楼顶的猫),他希望使用这\(k\)枚鱼肉炸弹能够使的\(Si\)的最大值最小。请输出这个最小值。

输入格式

输入格式:

第一行有两个整数\(N\)\(K\)

第二行至第\(n+1\)行有两个整数,依次是编号为\(1\)的楼到编号为\(N\)的楼的高度\((Hi)\)和楼顶的猫数\((Ci)\).

输出格式

你只需要输出一个整数,表示使用\(K\)枚炸弹所能达到的\(Si\)中的最大值最小能是多少。

样例

3 2
1 2
3 1
2 2
1

数据范围与提示

数据规模:\(1<=N<=100000,1<=k<=5,1<=Hi<=10^9,0<=Ci<=10^9\).


思路

这道题是一道树形\(DP!!!\)

建树

我们首先就要建树:
我们再这个区间中,选出最高那栋楼为根,然后在左区间和右区间继续这样建树。

我们把样例来看一下,建出的树如下:
在这里插入图片描述
再给一个例子。
我们楼的高度为\(1\ 5\ 3\ 4\ 2\)
那我们建出的树为:
在这里插入图片描述
我们求最大值就使用\(RMQ\)算法就可以了。否则会有很大几率给你\(T\)掉,火车头都没用...


DP

我们令\(f[i][j]\)为当前以\(i\)为根,放了\(j\)个炸弹的最优值。
如果我们的根上不放炸弹:

f[fa][i+j]=min(f[fa][i+j],max(f[lson][i],f[rson][j])+c[fa]);

我们左边放\(i\)个炸弹,右边放\(j\)个炸弹。
最大的加上根本来的猫数,和原来的取较小值。

如果我们根上放炸弹:

f[fa][i+j+1]=min(f[fa][i+j+1],max(f[lson][i],f[rson][j]);

我也就不解释了。


代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,k,h[maxn],c[maxn],lson[maxn],rson[maxn];
int f[maxn][6],ff[maxn][20];
map<int,int> mp;

void read(int &x) {
    int f=1; x=0; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0' && ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    x*=f;
}

void ST_perwork() {
	for(int i=1;i<=n;i++) ff[i][0]=h[i];
	int t=log(n)/log(2)+1;
	for(int j=1;j<t;j++) {
		for(int i=1;i<=n-(1<<j)+1;i++)
			ff[i][j]=max(ff[i][j-1],ff[i+(1<<(j-1))][j-1]);
	}
	return ;
}

int ST_query(int l,int r) {
	int k=log(r-l+1)/log(2);
	return max(ff[l][k],ff[r-(1<<k)+1][k]);
}

int build(int l,int r) {
	if(l==r) return l;
	int maxx=ST_query(l,r);
	int x=mp[maxx];
	/*
	int maxx=0,x;
	for(int i=l;i<=r;i++)
		if(maxx<h[i]) maxx=h[i],x=i;
	*/
	if(x>l) lson[x]=build(l,x-1);
	if(x<r) rson[x]=build(x+1,r);
	return x;
}

void DP(int root) {	
	if(!root) return ;
	DP(lson[root]),DP(rson[root]);
	for(int i=0;i<=k;i++) {
		for(int j=0;j<=k-i;j++) {
			f[root][i+j]=min(f[root][i+j],max(f[lson[root]][i],f[rson[root]][j])+c[root]);
			if(i+j<k) f[root][i+j+1]=min(f[root][i+j+1],max(f[lson[root]][i],f[rson[root]][j]));
		}
	}
	return ;
}

int main() {
	memset(f,0x3f,sizeof(f));
	read(n),read(k);
	for(int i=1;i<=n;i++) read(h[i]),read(c[i]),mp[h[i]]=i;
	ST_perwork();
	f[0][0]=0;
	int root=build(1,n);
	DP(root);
	printf("%d",f[root][k]);
	return 0;
}
posted @ 2020-12-15 13:33  凌曦月lx  阅读(83)  评论(0编辑  收藏  举报