【问题描述】
油库里是幻想乡特有的一种生物。每只油库里都有一个战斗力值和一个能量值。当两只油库里战斗时,总是战斗力值高的一位获胜。获胜者的战斗力值将变成自己的原战斗力值-对手的战斗力值+对手的能量值。败者将死去。若两者战斗力值一样,则同归于尽。
思考熊发现了很多油库里,他想知道通过互相战斗之后油库里中战斗力值+能量值最高的一个可能到达多少。你能帮他们求出来吗?(假设除了考察的那只油库里之外,其他油库里之间不会发生战斗)
【输入格式】
第一行是一个整数N,代表当前有多少油库里。
接下来的N行,每一行有两个整数u,v,代表这只油库里的战斗力值和能量值。
【输出格式】
输出一个整数,代表油库里中的战斗力值+能量值最高的一个能达到多少。
【样例输入】
2
1 2
2 1
【样例输出】
4
【数据规模与约定】
对于 100%的数据, 1≤u,v≤10^9,1<=N<=10^5。
数据范围可得算法为O(n)/O(nlogn)。
可以得出,当油库里可以攻击另一个油库里,且另一个油库里的攻击力<这只油库里的能量值,则杀掉他一定是优的
考虑排序,将杀掉更优的所有油库里排序
对于油库里i,找到所有攻击力比他小的,加上他们的能量值和攻击力的差值、
此时攻击力会上升,则继续找,直到攻击力无法上升为止。可以用前缀和加二分实现。
如果这个油库里杀掉别的油库里,且这个油库里在更优的油库里中,则他杀掉了自己,二分中减去即可。
所以下一次的left就为right,因为攻击力是递增的。
1 #include<cstdio>
2 #include<iostream>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int maxn=1e5+7;
7 long long a[maxn],b[maxn];
8 long long c[maxn];
9 struct node{
10 long long q,w;
11 }r[maxn];
12 int temp=0;
13 int n;long long ans=0;
14 bool comp(const node &qw,const node &we)
15 {
16 return qw.q<we.q;
17 }
18 long long max(long long x,long long y)
19 {
20 if(x<y)return y;
21 return x;
22 }
23 int main()
24 {
25 freopen("zyougamaya.in","r",stdin);
26 freopen("zyougamaya.out","w",stdout);
27 scanf("%d",&n);
28 for(int i=1;i<=n;i++)
29 {
30 scanf("%I64d%I64d",&a[i],&b[i]);
31 if(a[i]<b[i])
32 {
33 r[++temp].q=a[i];
34 r[temp].w=b[i]-a[i];
35 }
36 }
37 sort(r+1,r+temp+1,comp);
38 for(int i=2;i<=temp;i++)
39 r[i].w+=r[i-1].w;
40 for(int i=1;i<=n;i++)
41 {
42 long long x=a[i],y=b[i];long long pre=0;long long xx=a[i];int left=1,right=temp;
43 while(1)
44 {
45 int start=left;
46 while(left<=right)
47 {
48 int mid=(left+right)>>1;
49 if(r[mid].q<xx)
50 left=mid+1;
51 else right=mid-1;
52 }
53 if(r[right].q==xx)break;
54 if(right==start-1)break;
55 xx=x+r[right].w;
56 //if(a[i]<b[i])
57 //xx=xx+a[i]-b[i];
58 if(xx==pre)break;
59 pre=xx;
60 left=right;right=temp;
61 }
62 if(pre==0)//没重
63 ans=max(ans,x+y);
64 else if(x-y<0)ans=max(ans,xx+y+x-y);
65 else ans=max(ans,xx+y);
66 }
67 printf("%I64d",ans);
68 return 0;
69 }