【題解】玲瓏學院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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章