题意:
一个人从高
L
的洞中爬出来,最多可以爬
分析:
二分答案,最后一天不需要下落,所以可以枚举最后一天的方案。现在要判断这个答案是否会被追兵追上,可以 o(n) 预处理出在第 i 中方案不被选择时,追兵最少用多少天才能追上这个人。
当方案按照每天净上升排完序后,不选择第
注意:如果净上升 ≤0 那么这种方案对于预处理毫无意义。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <string>
using namespace std;
typedef long long LL;
typedef vector <int> VI;
typedef pair <int,int> PII;
#define FOR(i,x,y) for(int i = (int)(x);i < (int)(y);++ i)
#define IFOR(i,x,y) for(int i = (int)(x);i > (int)(y);-- i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define fi first
#define se second
const int maxn = 100010;
int n, li[maxn];
LL L, sum[maxn], c[maxn];
struct Num{
LL a, b;
bool operator < (const Num& rhs) const{
return a-b > rhs.a-rhs.b;
}
}s[maxn];
void Init() {
LL ca = 0;
int idx = 1;
FOR(i, 2, n+1) {
ca = ca+s[i].a-s[i].b-c[idx];
if(ca <= 0) break;
++ idx;
}
li[1] = idx;
FOR(i, 2, n+1) {
if(i-1 > idx) {li[i] = idx; continue;}
if(idx == n) {li[i] = n; continue;}
ca += s[i-1].a-s[i-1].b+s[i].b-s[i].a;
while(ca > 0 && idx < n) {
++ idx;
ca += s[idx+1].a-s[idx+1].b-c[idx];
}
li[i] = idx;
}
}
int ff = n+1;
bool judge(int x) {
-- x;
FOR(i, 1, n+1) {
LL lim = L-s[i].a;
if(li[i] <= x) continue;
if(i > x && sum[x] >= lim) return true;
if(i <= x && sum[x+1]-s[i].a+s[i].b >= lim) return true;
}
return false;
}
int main() {
while(~scanf("%d%lld", &n, &L)) {
LL mx = -1;
FOR(i, 1, n+1)
scanf("%lld%lld", &s[i].a, &s[i].b),
mx = max(mx, s[i].a);
s[n+1].a = s[n+1].b = 0;
FOR(i, 1 ,n+1) scanf("%lld", c+i);
if(mx >= L) {printf("1\n"); continue;}
sort(s+1, s+n+1);
ff = n;
FOR(i, 1, n+1) if(s[i].a <= s[i].b) {ff = i; break;}
sum[0] = 0;
FOR(i, 1, n+1) sum[i] = sum[i-1]+s[i].a-s[i].b;
Init();
int l = 1, r = ff;
//cout << l << " " << r << endl;
if(l > r) {printf("-1\n"); continue;}
while(l < r) {
int mid = (l+r) >> 1;
if(judge(mid)) r = mid;
else l = mid+1;
}
if(judge(l)) printf("%d\n", l);
else printf("-1\n");
}
return 0;
}