2121: 管道(New Online Judge)
题目描述
有一根长度为 len 的横向的管道,该管道按照单位长度分为 len 段。每一段的中央有一个可开关的阀门和一个检测水流的传感器。一开始管道是空的,位于 Li 的阀门会在 Si 时刻打开,并不断让水流入管道。对于位于 Li 的阀门,它流入的水在 Ti (Ti≥Si) 时刻会使得从第 Li-(Ti-Si) 段到第 Li+(Ti-Si) 段的传感器检测到水流。
求管道中每一段中间的传感器都检测到有水流的最早时间。
输入
输入的第一行包含两个整数 n, len,用一个空格分隔,分别表示会打开的阀门数和管道长度。接下来 n 行每行包含两个整数 Li, Si,用一个空格分隔,表示位于第 Li 段管道中央的阀门会在 Si 时刻打开。
对于 30% 的评测用例,n ≤ 200,Si, len ≤ 3000 ;
对于 70% 的评测用例,n ≤ 5000,Si, len ≤ 100000 ;
对于 100% 的评测用例, 1 ≤ n ≤ 100000 , 1 ≤ S i , l e n ≤ 1 0 9 , 1 ≤ L i ≤ l e n , L i − 1 < L i 1 ≤ n ≤ 100000,1 ≤ Si, len ≤ 10^9,1 ≤ Li ≤ len,Li-1 < Li 1≤n≤100000,1≤Si,len≤109,1≤Li≤len,Li−1<Li。
输出
输出一行包含一个整数表示答案。
样例输入
3 10
1 1
6 5
10 2
样例输出
5
题解1(C++ 版本1)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n, len, s[N], Len[N];
bool check(LL x){
vector<pair<LL,LL>> interval;
int cnt = 0;
for(int i = 1; i <= n; i++){
if(x < s[i]) continue; //要保证ti>=si
//位于Li的阀门,可以使得传感器检测到的左边界和右边界
interval.push_back({Len[i] - (x - s[i]), Len[i] + (x - s[i])});
}
sort(interval.begin(), interval.end());
if(interval.size() == 0 || interval[0].first > 1) return false;
LL right = interval[0].second;
for(int i = 1; i < (int)interval.size(); i++){
if(interval[i].first > right + 1) break;
right = max(right, interval[i].second);
}
return right >= len;
}
int main(){
scanf("%d%d", &n, &len);
for(int i = 1; i <= n; i++){
scanf("%d%d", &Len[i], &s[i]);
}
LL L = 0, R = 2e9 + 7, mid;
while(L + 1 < R){
mid = (L + R)/2;
if(check(mid)) R = mid; // 二分答案
else L = mid;
//printf("L =%lld R=%lld mid = %lld", L, R, mid);
}
printf("%lld\n", R);
return 0;
}
题解2(C++版本2)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
const LL INF = 1e9;
int n, len, s[N], Len[N];
bool check(LL x){
int cnt = 0;
LL last_L = 2, last_R = 1LL;
for(int i = 1; i <= n; i++){
if(x < s[i]) continue; //要保证ti>=si
//位于Li的阀门,可以使得传感器检测到的左边界和右边界
cnt++;
LL left = 1LL*Len[i] - min(INF, x - s[i]);
LL right = 1LL*Len[i] + min(INF, x - s[i]);
if(left < last_L) last_L = left, last_R = max(right, last_R);
else if(left <= last_R + 1) last_R = max(right, last_R);
}
if(!cnt) return false;
return last_L <= 1 && last_R >= len;
}
int main(){
scanf("%d%d", &n, &len);
for(int i = 1; i <= n; i++) scanf("%d%d", &Len[i], &s[i]);
LL L = 0, R = 2e9 + 7, mid;
while(L + 1 < R){
mid = (L + R)/2;
if(check(mid)) R = mid; // 二分答案
else L = mid;
//printf("L =%d R=%d mid = %d\n", L, R, mid);
}
printf("%d\n", R);
return 0;
}
题解3 (C++版本3)
#include<bits/stdc++.h>
using namespace std;
#define int long long // #define int long long ,main函数要改成有符号型 signed main()
const int N = 1e5 + 10;
const int INF = 1e9;
int n, len, s[N], Len[N];
bool check(int x){
int cnt = 0;
int last_L = 2, last_R = 1;
for(int i = 1; i <= n; i++){
if(x < s[i]) continue; //要保证ti>=si
//位于Li的阀门,可以使得传感器检测到的左边界和右边界
cnt++;
int left = Len[i] - min(INF, x - s[i]);
int right = Len[i] + min(INF, x - s[i]);
if(left < last_L) last_L = left, last_R = max(right, last_R);
else if(left <= last_R + 1) last_R = max(right, last_R);
}
if(!cnt) return false;
return last_L <= 1 && last_R >= len;
}
signed main(){
scanf("%d%d", &n, &len);
for(int i = 1; i <= n; i++) scanf("%d%d", &Len[i], &s[i]);
int l = 0, r = 2e9, ans = -1;
while(l <= r){
int mid = ((r - l) >> 1) + l;
if(check(mid))ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d\n", ans);
return 0;
}