题目思路
- 这个题目如果一个数满足条件,那么后面的都满足,可以采用二分的方式快速找到答案。
- 为了求出水能够覆盖的范围,采用区间合并检验水是否覆盖整个管道。
区间合并
如何检验水是否覆盖管道?
- 把每一个被水覆盖的区间存起来
- 把这些区间按照左端点大小进行排序
- 遍历这些端点,左边依次取左端点,右边取当前已经遍历了的右端点的最大值
- 如果右边 > 左边 + 1,则没有完全覆盖
typedef long long ll
typedef pair<ll, ll> pll // 用pair类型存储端点值,方便排序
int CheckFull(ll res, vector<int>& l, vector<int>& s)
{// res是要检测的值,l是存放Li的数组,s是存放Si的数组
vector<pll> border; // 建立一个pll类型可变数组
for(int i = 1; i < n + 1; i++)// 从1到n
{
if(res >= s[i])// 时间到了,该放水了
{
ll left = l[i] - (res - s[i]);
ll right = l[i] + (res - s[i]);
border.push_back({left, right});// 储存好水能够覆盖的范围
}
}
sort(border.begin(), border.end());// 按照左端点排序
if(border.empty())
return 0;
if(border[0].first > 1)
return 0;
ll rightmax = border[0].second;
for(int i = 1; i < border.size(); i++)
{
ll leftcmp = border[i].first;
if(leftcmp > rightmax + 1)
return 0;
rightmax = max(rightmax, border[i].second);
}
if(rightmax < len)
return 0;
return 1;
}
二分
- 取一个中间的数,如果满足就往左,如果不满足就往右找答案
while (Max > Min)
{
ll mid = (Max + Min) >> 1;
if (CheckFull(mid, l, s))
{
Max = mid;
}
else
{
Min = mid + 1;
}
}
完整代码
using namespace std;
#include<iostream>
#include<vector>
#include<utility>
#include<algorithm>
typedef pair<long long, long long> pll;
typedef long long ll;
int n, len;
int CheckFull(ll res, vector<int>& l, vector<int>& s)
{
vector<pll> border;
for(int i = 1; i < n + 1; i++)
{
if(res >= s[i])
{
ll left = l[i] - (res - s[i]);
ll right = l[i] + (res - s[i]);
border.push_back({left, right});
}
}
sort(border.begin(), border.end());
if(border.empty())
return 0;
if(border[0].first > 1)
return 0;
ll rightmax = border[0].second;
for(int i = 1; i < border.size(); i++)
{
ll leftcmp = border[i].first;
if(leftcmp > rightmax + 1)
return 0;
rightmax = max(rightmax, border[i].second);
}
if(rightmax < len)
return 0;
return 1;
}
int main()
{
cin >> n >> len;
vector<int> l(n + 1);
vector<int> s(n + 1);
for (int i = 1; i <= n; i++)
{
cin >> l[i];
cin >> s[i];
}
ll Max = 2e9 + 10;
ll Min = 1;
while (Max > Min)
{
ll mid = (Max + Min) >> 1;
if (CheckFull(mid, l, s))
{
Max = mid;
}
else
{
Min = mid + 1;
}
}
cout << Max;
return 0;
}