【题解】玲珑学院oj1088 Red Packets

题目链接

题意:给定n个元素,每个元素有费用a和价值b两个属性。可以从n个元素中选取连续的若干个,满足这连续的若干个元素中除去至多m个元素之外的其他元素的费用和不超过k, 这么做可以获得的价值定义为这连续的若干个元素的价值和。求能够获得的最大价值。

分析:滑动窗口。设选取的元素下标集为区间[l,r],只需对每个l求出最大的满足条件的r即可。用两个堆维护判断,一个小根堆用于存储不需要付费的元素,一个大根堆用于存储需要付费的元素。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
struct node
{
	int a,i;
};
struct cmp1
{
	bool operator () (node o1,node o2)
    {
	    return o1.a>o2.a;
    }
};
struct cmp2
{
	bool operator () (node o1,node o2)
    {
	    return o1.a<o2.a;
    }
};
int n,m,k,a[maxn],b[maxn],pos[maxn];
int ans,num,sa,sb;
priority_queue<node,vector<node>,cmp1> Q1;
priority_queue<node,vector<node>,cmp2> Q2;
void init()
{
	ans=0;sa=0;sb=0;num=0;
	while (!Q1.empty()) Q1.pop();
	while (!Q2.empty()) Q2.pop();
}
void work1(int l)
{
	while (!Q1.empty()&&Q1.top().i<l) Q1.pop();
}
void work2(int l)
{
	while (!Q2.empty()&&Q2.top().i<l) Q2.pop();
}
int main()
{
	int T;cin>>T;
	while (T--)
	{
		scanf("%d%d%d",&n,&m,&k);
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		for (int i=1;i<=n;i++) scanf("%d",&b[i]);
		init();
		int r=0;
		for (int l=1;l<=n;l++)
		{
			while (r+1<=n)
			{
				work1(l);
				if (num<m)
				{
					num++;
					r++;sb+=b[r];ans=max(ans,sb);
					Q1.push((node){a[r],r});pos[r]=1;
					continue;
				}
				if (a[r+1]>Q1.top().a&&sa+Q1.top().a<=k)
				{
					r++;sa+=Q1.top().a;sb+=b[r];ans=max(ans,sb);
					Q2.push(Q1.top());pos[Q1.top().i]=2;Q1.pop();Q1.push((node){a[r],r});pos[r]=1;
					continue;
				}
				if (a[r+1]<=Q1.top().a&&sa+a[r+1]<=k)
				{
					r++;sa+=a[r];sb+=b[r];ans=max(ans,sb);
					Q2.push((node){a[r],r});pos[r]=2;
					continue;
				}
				break;
			}
			sb-=b[l];
			work2(l);
			if (pos[l]==1&&!Q2.empty())
			{
				num++;
				sa-=Q2.top().a;
				Q1.push(Q2.top());pos[Q2.top().i]=1;Q2.pop();
			}
			if (pos[l]==1&&Q2.empty()) num--;
			if (pos[l]==2) sa-=a[l];
		}
		printf("%d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值