小红书2023秋招提前批-精华帖子(双指针或者二分加前缀和)
https://oj.algomooc.com/problem.php?id=5801
小红书的推荐帖子列表为\([0,n)\),其中所有的帖子初始状态为“普通”,现在运营同学把其中的一些帖子区间标记为了“精华”。
运营同学选择了固定长度\(k\),对整个帖子列表截取,要求计算在固定的截取长度k下,能够截取获得的最多精华帖子数量。
输入
第一行输入三个正整数\(n,m,k\),分别代表初始帖子列表长度,精华区间的数量,以及运营同学准备截取的长度。
接下来的m行,每行输入两个正整数\(l_i,r_i\),代表第i个左闭右开区间。
\(1 ≤ k ≤ n ≤ 1000000000\)
\(1 ≤ m ≤ 100000\)
\(0 ≤ l_i < r_i ≤ n\)保证任意两个区间是不重叠的。
输出
一个正整数,代表截取获得的最多的精华帖子数量。
样例输入
5 2 3
1 2
3 5
样例输出
2
提示
这是一个长度为5的帖子列表,如果用0表示普通帖子,1表示精华帖子,则该列表为[0, 1, 0, 1, 1]。 用长度k = 3的区间截取列表,最多能够包含2个精华帖子。
这个帖子列表长度是1e9,所以这个题肯定是枚举帖子个数,而不是枚举帖子长度,所以我们用双指针
下面解释一下代码意思:
这里指的是从[a[l].e+1,.....a[r].e)就已经超过k了,所以l可以不要了
while(a[r].e-a[l].e>k){
sum-=a[l].e-a[l].s;
l++;
}
而这里则是需要减去第一个瓷砖块中未被覆盖的瓷砖,也就是下图中蓝色部分,因为sum已经加上了那三块的长度。
ans = max(ans, sum - max(0, (a[r].e - k - a[l].s)));
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+100;
struct node{
int s,e;
}a[maxn];
int n,m,k;
int cmp(node x,node y){
return x.s<y.s;
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=m;i++){
cin>>a[i].s>>a[i].e;
}
sort(a+1,a+m+1,cmp);
int ans=0,sum=0;
for(int l=1,r=1;r<=m;r++){
sum+=(a[r].e-a[r].s);
while(a[r].e-a[l].e>k){
sum-=a[l].e-a[l].s;
l++;
}
ans = max(ans, sum - max(0, (a[r].e - k - a[l].s)));
}
cout<<ans<<endl;
}
这个也可以用前缀和加二分写,https://blog.csdn.net/qq_43406895/article/details/132767517
上面这个题和下面这个题基本一样:
https://leetcode.cn/problems/maximum-white-tiles-covered-by-a-carpet/solutions/1496434/by-endlesscheng-kdy9/
或者看这个解析
https://blog.csdn.net/qq_43406895/article/details/131605543