题意:给定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;
}