P8551 Bassline 题解
分析
这道题做月赛的时候想了好久,最后发现其实很简单。
我们用样例数据来分析:
如图所示,我们将每个区间抽象化为一个一个的长条。题目给我们的两个要求可以理解为 \([x,y]\) 所覆盖的列中没有任意一个长条开始或结束,如图中第 4 列就是绿色长条的开始部分,第 7 列就是绿色长条的结束部分,它们都不满足要求,所以 \([x,y]\) 不能包含这两列。
理解到这里了,这道题就很简单了:我们只需要用有长条开始或者结束的列将最大区间分成几个部分(如下图),取区间长度减一乘以区间内的长条数的最大值即 \(k-(y-x)\) 就行了。
思路
我们使用一个数组存储每一个数(即上面分析时所说的列)是多少个区间的起点和终点,我用的是结构体 x[i]
,当然你也可以用两个数组解决。对于读入的每个区间 \([l_i,r_i]\) ,我们让 x[li].geb++,x[ri].end++
,并且存储最左边的点 left
和最右边的点 right
。
接着,我们从 left
循环到 right
,用 cnt
来记录能被选择的 \([x,y]\) 区间中的元素个数(即 \(y-x\) ),每当遇到一个区间的开始或结束就将 cnt
清零,再用 k
记录每一个数上的区间个数,每次用 cnt*k
跟答案比较取最大值就好了。
程序
#include<bits/stdc++.h>
using namespace std;
int n;
struct Node
{
int beg=0,end=0;
}x[300005];//使用结构体存储每个数字是多少个区间的起点和终点
int main()
{
scanf("%d",&n);
int left=300005,right=-1,k=0,cnt=0;
for(long long i=1;i<=n;i++)
{
int l,r;
scanf("%d%d",&l,&r);
x[l].beg++,x[r].end++;//区间[l,r]开头和结尾的数字的起点个数和终点个数分别+1
left=min(l,left);
right=max(right,r);
}
long long ans=0;//一定记得开long long,不然最后一个点会炸
for(int i=left;i<=right;i++)
{
++cnt;//记录这个可选区间中y-x的值
if(x[i].beg || x[i-1].end)
cnt=0;//如果i是某个区间的起点或者终点就将cnt清零
k+=x[i].beg;//用k记录i上的区间个数
ans=max(ans,cnt*k);//取最优解
k-=x[i].end;
}
printf("%lld\n",ans);
}
标签:P8551,int,题解,Bassline,cnt,区间,长条
From: https://www.cnblogs.com/if-OF/p/P8551.html