← 返回题解列表

P1057 天地皆可往 官方题解

【题意分析】

  • 会增加龙威的疆土先处理,能够为后续行程留下更多余量。会减少龙威的疆土放在后面,并按照离开时的门槛安排顺序。

【部分分:测试点 1∼21\sim 21∼2】

  • 固定一个前往疆土的排列后,从前向后模拟即可求出完成这个排列所需的最小初始龙威。
  • 枚举全部 n!n! 个排列,取这些排列对应答案的最小值。
  • 单次模拟需要 O(n)\mathcal O(n) 的时间,总时间复杂度为 O(n!n)\mathcal O(n!n)

【部分分:测试点 3∼53\sim 53∼5】

  • 二分初始龙威 xx。令 fSf_S 表示已经前往集合 SS 中的疆土时,最多能够剩下多少龙威,不可达状态记为负无穷。
  • iSi\notin SfSaif_S\geq a_i,则有
fS{i}max{fS{i},fS+bi}.f_{S\cup\{i\}}\gets\max\{f_{S\cup\{i\}},f_S+b_i\}.
  • 检查一次需要 O(n2n)\mathcal O(n2^n) 的时间。答案具有单调性,因此可以二分最小的可行 xx

【部分分:测试点 6∼106\sim 106∼10】

  • 特殊性质 A 保证 bi0b_i\geq 0。一旦能够进入某片疆土,完成当地事务后龙威不会下降。
  • 因此按照 aia_i 从小到大前往一定不劣。若当前能够进入后一片疆土,那么前面的疆土只会继续增加龙威。
  • 排序后顺序模拟即可,时间复杂度为 O(nlogn)\mathcal O(n\log n)

【部分分:测试点 11∼1511\sim 1511∼15】

  • 特殊性质 B 保证 bi<0b_i<0。考虑相邻的两片疆土 i,ji,j
  • 若先去 ii 再去 jj,除了进入 ii 需要满足 xaix\geq a_i,进入 jj 还需要满足 x+biajx+b_i\geq a_j
  • 比较两种顺序后可知,应当按照 ai+bia_i+b_i 从大到小排列。这个量表示离开疆土 ii 时至少能够保留的龙威门槛。
  • 排序后顺序模拟,时间复杂度为 O(nlogn)\mathcal O(n\log n)

【部分分:测试点 16∼2016\sim 2016∼20】

  • 先处理所有 bi0b_i\geq 0 的疆土,再处理所有 bi<0b_i<0 的疆土一定不劣。
  • 前一部分按照 aia_i 从小到大排列,后一部分按照 ai+bia_i+b_i 从大到小排列。
  • 设已经完成的龙威变化量之和为 SS。来到疆土 ii 前必须有 Ans+Sai\operatorname{Ans}+S\geq a_i,所以
Ansmax{Ans,aiS},SS+bi.\operatorname{Ans}\gets\max\{\operatorname{Ans},a_i-S\},\qquad S\gets S+b_i.
  • 时间复杂度为 O(nlogn)\mathcal O(n\log n),空间复杂度为 O(n)\mathcal O(n)

【参考代码】

#include <cstdio>#include <vector>#include <algorithm>#define MAXN 200010using namespace std; struct land{    long long Need,Change;}Line[MAXN]; bool Compare(const land &A,const land &B){    if((A.Change>=0)!=(B.Change>=0)) return A.Change>=0;    if(A.Change>=0) return A.Need<B.Need;    return A.Need+A.Change>B.Need+B.Change;} int main(){    int c,T,n;    scanf("%d%d",&c,&T);    while(T-->0){        scanf("%d",&n);        for(int i=1;i<=n;i++) scanf("%lld%lld",&Line[i].Need,&Line[i].Change);        sort(Line+1,Line+n+1,Compare);        long long Sum=0,Ans=0;        for(int i=1;i<=n;i++){            Ans=max(Ans,Line[i].Need-Sum);            Sum+=Line[i].Change;        }        printf("%lld\n",Ans);    }    return 0;}