购买木材-小红书2024笔试(codefun2000)

23 篇文章 0 订阅
14 篇文章 0 订阅

题目链接
购买木材-小红书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;
}
  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值