题意:
有N个外星人,第i个外星人会在ai时间出现,离你距离di,并且必须在bi之前被消灭。你有一把很NB的武器,攻击范围是个半径为R的圆,R可以任意调整,不过你以R的范围每攻击一次就要消耗R单位能量。外星人被攻击一次就会死掉。求需要消灭所有外星人的最小消耗能量。
N<=300, ai,bi,di<=10000
题解:
感觉这篇题解已经写得非常好了。
把每个外星人看做有高度的线段,显然最高的线段一定会被选择,并且可以带走一些外星人,剩下的外星人所代表的线段又一定在被选择的线段上的分割点的两边,又是一个子问题,那么考虑离散化坐标后枚举分割点就好了。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
const int Maxn=3e2+50;
struct Alien{
int L,R,V;
friend inline bool operator <(const Alien &a,const Alien &b){
return a.V<b.V;
}
}alien[Maxn];
int T,n,dp[Maxn*2][Maxn*2],lhs[Maxn*2],tot;
inline int Dp(int l,int r){
if(r<l)return 0;
if(dp[l][r]!=-1)return dp[l][r];
int mx=0;
for(int i=n;i>=1;i--){
if(alien[i].L>=l&&alien[i].R<=r){
mx=i;break;
}
}
if(!mx)return dp[l][r]=0;
dp[l][r]=0x3f3f3f3f;
for(int i=alien[mx].L;i<=alien[mx].R;i++){
dp[l][r]=min(dp[l][r],Dp(l,i-1)+Dp(i+1,r));
}
return (dp[l][r]+=alien[mx].V);
}
int main(){
T=read();
while(T--){
memset(dp,-1,sizeof(dp));
n=read();tot=0;
for(int i=1;i<=n;i++){
alien[i].L=read(),alien[i].R=read(),alien[i].V=read();
lhs[++tot]=alien[i].L,lhs[++tot]=alien[i].R;
}
sort(lhs+1,lhs+tot+1);
sort(alien+1,alien+n+1);
tot=unique(lhs+1,lhs+tot+1)-lhs-1;
for(int i=1;i<=n;i++){
alien[i].L=lower_bound(lhs+1,lhs+tot+1,alien[i].L)-lhs;
alien[i].R=lower_bound(lhs+1,lhs+tot+1,alien[i].R)-lhs;
}
printf("%d\n",Dp(1,tot));
}
}