题目链接
购买木材-小红书2024笔试(codefun2000)
题目内容
塔子哥想要购买木材。现在商家有一根原木,长度为 n ,但这块原木上只有一些结实的部分适合做木材。商家告诉塔子哥可以从这根原木上选取长度为 k 的一段购买并截取。塔子哥希望他购买的木材能够包含尽可能多的结实部分,请你指出塔子哥购买后能够获得木材的总长度最长是多少。
输入描述
第一行输入两个正整数 n,m,k,代表原木初始长度,结实部分的数量,以及塔子哥能够购买的原木的长度。塔子哥只能购买整数长度区间部分的原木。
接下来的 m 行,每行输入两个正整数 li, ri ,代表原木第 i 块结实部分的起止区间。
1 ⩽ k < n <= 1000000000
1 < m < 100000
0 < li < ri < n保证任意两个区间是不重叠的。
输出描述
一个正整数,代表能够获得的木材最长长度
样例1
输入
5 2 3
1 2
3 5
输出
2
样例1解释
区间(1,2)代表从 1 到 2 这个长度单位的原木是结实部分,可以做木材,区间(3,5)代表从 3 到 5 这个长度单位的原木是结实部分,可以做木材。塔子哥只能购买整数长度区间部分的原木,所以这个样例可以选择购买区间 (2, 5)或(1,4) 的原木,最终收获长度为2的木材。
样例2
输入
7 3 5
1 2
5 7
3 4
输出
3
样例2解释
题解1
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int n,k,m,a[N], pre[N]; // pre[i]表示按区间左端点排序后的,前i个区间的结实部分的长度
LL ans;
struct Inv{
int L, R;
bool operator < (const Inv& A) const {
return L < A.L; // 由于任意两个区间是不重叠的,因此L不可能等于A.L
}
}inv[N];
bool check(int idx, int x){ // 表示从第idx个区间开始,到第idx + x个区间中的某个位置结束这部分的总长度
int L = inv[idx].L, R = inv[idx + x].L;
if(R - L >= k) return false;
else return true;
}
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= m; i++){
scanf("%d%d", &inv[i].L, &inv[i].R);
}
sort(inv + 1, inv + m + 1);
for(int i = 1; i <= m; i++){
pre[i] = pre[i - 1] + inv[i].R-inv[i].L;
}
for(int i = 1; i <= m; i++){ // 枚举每个区间
int left = -1, right = m-i+1, mid;
while(left + 1 < right){ // 二分枚举截取总长度为k的木头的结束部分洛在哪个区间
mid = (left + right)/2;
if(check(i,mid)) left = mid;
else right = mid;
}
ans = max(ans, 1LL*pre[i+left - 1] - pre[i - 1] + min(inv[i].L+k, inv[i + left].R)-inv[i+left].L);
}
printf("%lld\n", ans);
return 0;
}