题目传送门
题意:
n个城堡,m条单向边,单向边的方向永远是下标大的城堡到下标小的城堡。
初始时你的军队有k个士兵。
现在你依次占领n个城堡,占领顺序是先占领下标小的城堡,再占领下标大的城堡。
占领第
个城堡,需要拥有 个士兵,但是并不消耗士兵。占领第 个城堡后,你的军队会新增 个士兵。保卫第
个城堡会获得 个金币。保卫一个城堡需要把一个士兵留在该城堡。
军队的移动顺序是下标小的城堡到下标大的城堡,不会反向移动。
当你在第
个城堡时,你可以派一个士兵保卫第 个城堡。当你在第
个城堡时,你可以派一个士兵保卫第 个城堡。要求必须存在第 个城堡到第 个城堡的单向边。一个士兵保卫城堡就会离开军队。
如果不能占领所有城堡,那就输出-1。
问你在占领所有城堡后最多能获得多少个金币。
数据范围:
。 。题解:
需要观察到2个切入点才能解决。
切入点1:如果要把一个士兵安排到第
个城堡,那么一定要保证能占领后面所有的城堡。切入点2:如果要把一个士兵安排到第
个城堡,那么一定是合法的最靠后的城堡向第 个城堡派士兵。因此,每个城堡都对应一个可向自身派遣士兵的最靠后的城堡。
依次保卫金币数最多的城堡即可。保卫该城堡后,要满足可以占领所有城堡。
感受:
set用错,直接调了两个小时bug。
欲哭无泪。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 5005 ;
const int maxm = 1e6 + 5 ;
const ll mod = 998244353 ;
int n , m , k ;
int f[maxn] , now[maxn] , suf[maxn] ;
int a[maxn] , b[maxn] , c[maxn] ;
struct node
{
int x , y ;
bool operator <(const node &s) const
{
if(y != s.y) return y > s.y ;
else return y == s.y ;
}
} ;
set<node> s ;
bool no()
{
int sum = k ;
for(int i = 1 ; i <= n ; i ++)
{
if(sum < a[i]) return 1 ;
else sum += b[i] ;
}
return 0 ;
}
void solve()
{
int ans = 0 ;
for(auto v : s)
{
int u = f[v.x] ;
bool flag = 0 ;
for(int i = u ; i <= n ; i ++)
if(now[i] - 1 < suf[i + 1]){flag = 1 ; break ;}
if(!flag)
{
for(int i = u ; i <= n ; i ++) now[i] -- ;
ans += v.y ;
}
}
printf("%d\n" , ans) ;
}
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]) ;
for(int i = 1 ; i <= n ; i ++) f[i] = i ;
for(int i = 1 ; i <= m ; i ++)
{
int u , v ;
scanf("%d%d" , &u , &v) ;
f[v] = max(f[v] , u) ;
}
for(int i = n ; i >= 1 ; i --)
suf[i] = max(a[i] , suf[i + 1] - b[i]) ;
if(no()){printf("-1\n") ; return 0 ;}
now[0] = k ;
for(int i = 1 ; i <= n ; i ++) now[i] = now[i - 1] + b[i] ;
for(int i = 1 ; i <= n ; i ++) s.insert(node{i , c[i]}) ;
solve() ;
return 0 ;
}
来源:CSDN
作者:敲代码的欧文
链接:https://blog.csdn.net/Irving0323/article/details/104315958