原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1689

 

一开始想枚举逛街的终点,然后开两个大根堆维护b值,分别保证喜爱店不少于k,以及在此前提下逛到的店尽可能多。具体实现是维持第一个堆元素数为k,每加入一个元素,如果c为1,就丢进第一个堆,并把堆顶丢到第二个,c为0直接丢进第二个。如果两个堆的元素b值之和超过T,就从第二个堆删元素。

但是这种写法最后的删元素部分有可能删去对答案有贡献的点,这时再把丢掉的元素维护起来,每次都差一下,然后就T了。

于是考虑每次删元素都看看第三个堆与第二个堆的优劣,删去无用元素,可以省去很多无用计算。

 

#include<queue>
#include<cstdio>
#include<algorithm>
#define MN 100001
using namespace std;
int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<'0'||read_ca>'9') read_ca=getchar();
    while(read_ca>='0'&&read_ca<='9') read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
int n,m,k,a[MN],b[MN],mmh=-1,A;
long long T=0;
priority_queue <int> q,Q,S;
int main(){
    register int i;
    n=read();m=read();k=read();
    for (i=1;i<=n;i++) a[i]=read();
    for (i=1;i<=n;i++) b[i]=read();
    for (i=1;i<=n;i++){
        if (read()) if (int(q.size())<k) q.push(b[i]);else
        q.push(b[i]),Q.push(q.top()),q.pop();else Q.push(b[i]);
        T+=b[i];
        if (int(q.size())<k) continue;
        while (T+a[i]>m&&(!Q.empty())) T-=Q.top(),S.push(-Q.top()),Q.pop();
        while (!S.empty()&&T+a[i]-S.top()<=m) T-=S.top(),Q.push(-S.top()),S.pop();
        while (!S.empty()&&-S.top()<Q.top()){
            T-=S.top();Q.push(-S.top());S.pop();
            while (T+a[i]>m&&(!Q.empty())) T-=Q.top(),S.push(-Q.top()),Q.pop();
        }
        if (T+a[i]<=m&&k+int(Q.size())>mmh) mmh=k+int(Q.size());
    }
    printf("%d\n",mmh);
}
View Code

相关文章: