P8551 Bassline 题解

P8551 Bassline 题解

分析

这道题做月赛的时候想了好久,最后发现其实很简单。

我们用样例数据来分析:

如图所示,我们将每个区间抽象化为一个一个的长条。题目给我们的两个要求可以理解为 [ x , y ] [x,y] [x,y] 所覆盖的列中没有任意一个长条开始或结束,如图中第 4 列就是绿色长条的开始部分,第 7 列就是绿色长条的结束部分,它们都不满足要求,所以 [ x , y ] [x,y] [x,y] 不能包含这两列。

理解到这里了,这道题就很简单了:我们只需要用有长条开始或者结束的列将最大区间分成几个部分(如下图),取区间长度减一乘以区间内的长条数的最大值即 k − ( y − x ) k-(y-x) k(yx) 就行了。

思路

我们使用一个数组存储每一个数(即上面分析时所说的列)是多少个区间的起点和终点,我用的是结构体 x[i] ,当然你也可以用两个数组解决。对于读入的每个区间 [ l i , r i ] [l_i,r_i] [li,ri] ,我们让 x[li].geb++,x[ri].end++ ,并且存储最左边的点 left 和最右边的点 right

接着,我们从 left 循环到 right ,用 cnt 来记录能被选择的 [ x , y ] [x,y] [x,y] 区间中的元素个数(即 y − x y-x yx ),每当遇到一个区间的开始或结束就将 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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值