http://codeforces.com/contest/1271/problem/D
//主要思路,求前缀和,算出每个点可以扔掉的兵(如果前面某个点扔掉了兵,后面所有点都只能少扔一个)
//两个贪心
//1.每个点的扔点位置尽量靠后,因为可以保留战力
//2.从分数最大的开始扔起,把有限的扔兵机会让给大的分数
#include<iostream>
#include<algorithm>
using namespace std;
const int N=5010;
int n,m,k;
int a[N],b[N],c[N];//攻破所需人数,获得人数,奖励得分
int l[N],d[N],f[N],h[N];//可以扔掉兵攻占i的最晚的点,累加到i的上限兵人数,这个点可以扔掉的兵数
int idx[N];
int ans;
//看看这题有没有解,顺便求个前缀和:d[i]=b[1]+...+b[n]
bool check()
{
int p=k;
for(int i=1;i<=n;i++)
{
if(p<a[i]) return 1;
p+=b[i],d[i]=p;//d[i]累加到i点为止的上限兵人数
}
return 0;
}
//重载运算符
bool cmp(const int &a,const int &b){
return c[a]>c[b];
}
//判断这个点能不能扔兵
bool check2(int x)
{
for(int i=n;i>=x;i--){
if(h[i]==0) return 0;//如果后面有个点开始不能扔兵的话这个点也不能扔兵
}
return 1;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++) {
scanf("%d%d%d",&a[i],&b[i],&c[i]);
l[i]=i,idx[i]=i;//初始化idx,以及扔兵位置
}
//读入每个portal最晚在哪里扔下
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
l[y]=max(l[y],x);
}
//判断题目是否有解
if(check()){
puts("-1");
return 0;
}
//计算到这个点可以扔的兵数
a[n+1]=0;
for(int i=1;i<=n;i++){
h[i]=d[i]-a[i+1];
}
sort(idx+1,idx+1+n,cmp);//把攻占分数从大到小排序
for(int i=1;i<=n;i++)
{
int x=idx[i];//从大到小取出队头
if(check2(l[x])){ //能扔的话,把每个点的上限扔兵数都减去1
for(int j=l[x];j<=n;j++) h[j]--;
ans+=c[x];
}
}
printf("%d\n",ans);
return 0;
}
我也来发个dp做法,贪心什么的太难了qwq
dp的前提条件也有个贪心的过程吧。就是越后面越优。这点卡死了T_T
嗯