zzulioj 2275: 跳跳的区间游戏(区间贪心)

2275: 跳跳的区间游戏

时间限制: 2 Sec   内存限制: 128 MB
提交: 50   解决: 12
[ 提交][ 状态][ 讨论版][命题人: admin]

题目描述

跳跳来到了第二个游戏,游戏规则为,跳跳有一个含有n个非负整数的数列与m个区间,每个区间可以表示为li,ri。
他要选择其中k个区间, 并使得这些区间的交的那些位置所对应的数的和最大。(是指k个区间共同的交,即每个区间都包含这一段,具体可以参照样例)

在样例中,5个位置对应的值分别为1,2,3,4,6,那么选择2,5与4,5两个区间的区间交为4,5,它的值的和为10。

输入

第一行输入三个整数n,k,m(1<=n<=100000,1<=k<=m<=100000)。 
接下来一行n个整数ai,表示小A的数列(0<=ai<=10^9)。 
接下来m行,每行两个整数li,ri,表示每个区间(1<=li<=ri<=n)。

输出

一行表示答案

样例输入

5 2 3
1 2 3 4 6
4 5
2 5
1 4

样例输出

10

按照左端点排序,枚举区间,先把右端点放入队列里,首先把队列里小于当前枚举区间l的全都pop掉,因为肯定不相交;然后如果队列里的数量大于等于k把前面的扔掉,因为后面的右端点一定比前面最优,这样,这个区间就是 (l ,q.top()),这一块被覆盖了k次,前缀和可以直接求出它的值,然后更新ans就好了

#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long 
struct node{
	int x,y;
}mat[100005];
ll sum[100005];
int cmp(node a,node b)
{
	return a.x <b.x ;
}

int main()
{
	int n,m,k;
	long long a;
	sum[0]=0;
	while(~scanf("%d%d%d",&n,&k,&m))
	{
		priority_queue<int,vector<int>,greater<int> >q;
		for(int i=1;i<=n;i++)
		{//预处理,计算前缀和 
			scanf("%lld",&a);
			sum[i]=sum[i-1]+a; 
		}
		for(int i=0;i<m;i++)
		{
			scanf("%d%d",&mat[i].x ,&mat[i].y);
		}
		ll ans=0;
		sort(mat,mat+m,cmp);
		for(int i=0;i<m;i++)
		{//开始枚举 
			q.push(mat[i].y);
			while(q.size()>k||q.top()<mat[i].x)
			{//如果>k,删除右端点小的,右端点大的更优||队列中的与当前i不不相交 
				q.pop();
			}
			if(q.size()==k&&q.top()>=mat[i].x)//更新ans值 
				ans=max(ans,sum[q.top()]-sum[mat[i].x-1]);
		}
		printf("%lld\n",ans);
	}
	return 0;
}
 

猜你喜欢

转载自blog.csdn.net/bbhhtt/article/details/80301707