版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ccsu_cat/article/details/81539498
多校六第四题,比赛没看这题,并且看了也一定不会写...看了标程和思路后,发现也没那么难,主要还是dp练的太少,题意是给出n个高度为H,左端点和右端点分别为L R,以及血量为W的怪物,你要用激光消灭所有的怪物,消耗值为 x 的的激光可以扣怪物 x 的血量,并且当怪物死了后,该次激光就会穿怪物并透射向后面的怪物。求用最少的激光值消灭所有怪物。
思路:因为怪物死了激光可以穿透,那么某一个区间内,肯定优先杀血量最多的怪物,这样就可以一条射线消灭该射线接触的所有怪物,这个题有点麻烦就是给出的高度以及左端点右端点数值太大,所以需要根据斜率离散化,把所有端点根据斜率排序,设dp[ l ][ r ]为消灭区间 l r 所有怪物所需的最少的激光值,首先找到区间l r 血量最多的怪物x,设怪物x 的血量为Max,左端点为s,右端点为e,那么转移方程肯定就是dp[ l ][ r ]=min(dp[ l ][ k-1 ]+dp[ k+1 ][ r ]+Max), k 属于区间[ s , e ]。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=605;
const LL inf=1e18;
struct P
{
LL x,y;
bool operator==(const P& rhs)const
{
return x*rhs.y==y*rhs.x;
}
bool operator<(const P& rhs)const
{
return x*rhs.y<y*rhs.x;
}
}p[maxn];
LL H[maxn],L[maxn],R[maxn],W[maxn];
LL dp[maxn][maxn];
int Li[maxn],Ri[maxn],n,hn;
int find(P x)
{
return lower_bound(p+1,p+1+hn,x)-p;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld%lld",&H[i],&L[i],&R[i],&W[i]);
p[i*2-1]=(P){L[i],H[i]};
p[i*2]=(P){R[i],H[i]};
}
sort(p+1,p+1+n*2);
hn=unique(p+1,p+1+n*2)-p-1;
for(int i=1;i<=n;i++)
{
Li[i]=find((P){L[i],H[i]});
Ri[i]=find((P){R[i],H[i]});
}
for(int len=1;len<=hn;len++)
for(int l=1;l+len-1<=hn;l++)
{
int r=l+len-1;
dp[l][r]=inf;
int Max=-1,cur=0;
for(int i=1;i<=n;i++)
if(Li[i]>=l&&Ri[i]<=r&&W[i]>Max)
Max=W[i],cur=i;
if(Max==-1)dp[l][r]=0;
else
{
int s=Li[cur],e=Ri[cur];
for(int i=s;i<=e;i++)
dp[l][r]=min(dp[l][r],dp[l][i-1]+dp[i+1][r]+Max);
}
}
printf("%lld\n",dp[1][hn]);
}
}