洛谷P5470/LOJ3158[NOI2019]序列(贪心)

对于不用配对的$k-l$个元素,很明显选最大的是最优的。

然后重复$l$次凑对:如果当前还有不用配对的可以选(某一次凑了两个,或者一开始就有对出现),那么选没选的里面的最大值;否则要么选一个没选的和已选的凑对,再在另一个序列里再选一个,要么选都每选过的一对,这个可以用堆来做。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=200050;
char rB[1<<21],*S,*T,wB[1<<21];
int wp=-1;
inline char gc(){return S==T&&(T=(S=rB)+fread(rB,1,1<<21,stdin),S==T)?EOF:*S++;}
inline void flush(){fwrite(wB,1,wp+1,stdout);wp=-1;}
inline void pc(char c){if(wp+1==(1<<21))flush();wB[++wp]=c;}
inline int rd(){
    char c=gc();
    while(c<48||c>57)c=gc();
    int x=c&15;
    for(c=gc();c>=48&&c<=57;c=gc())x=(x<<3)+(x<<1)+(c&15);
    return x;
}
short buf[25];
inline void wt(ll x){
    short l=-1;
    while(x>9){
        buf[++l]=x%10;
        x/=10;
    }
    pc(x|48);
    while(l>=0)pc(buf[l--]|48);
    pc('\n');
}
int a[N],b[N],ra[N],rb[N];
bool usea[N],useb[N];
inline bool cmpa(int x,int y){return a[x]>a[y];}
inline bool cmpb(int x,int y){return b[x]>b[y];}
struct dta{
    int p;
    dta(int p):p(p){}
    inline bool operator <(const dta &x)const{return a[p]<a[x.p];}
};
struct dtb{
    int p;
    dtb(int p):p(p){}
    inline bool operator <(const dtb &x)const{return b[p]<b[x.p];}
};
struct dte{
    int p;
    dte(int p):p(p){}
    inline bool operator <(const dte &x)const{return a[p]+b[p]<a[x.p]+b[x.p];}
};
priority_queue<dta> Qb,qa;
priority_queue<dtb> Qa,qb;
priority_queue<dte> Qe;
int main(){
    int T=rd(),n,k,l,i,tot,x,y,p,q,t,maxn;
    ll ans;
    while(T--){
        n=rd();k=rd();l=rd();
        for(i=1;i<=n;++i){a[i]=rd();ra[i]=rb[i]=i;}
        for(i=1;i<=n;++i)b[i]=rd();
        memset(usea,0,sizeof(usea));memset(useb,0,sizeof(useb));
        sort(ra+1,ra+n+1,cmpa);sort(rb+1,rb+n+1,cmpb);
        for(i=1,ans=tot=0;i<=k-l;++i){
            usea[ra[i]]=useb[rb[i]]=1;
            ans+=a[ra[i]]+b[rb[i]];
        }
        while(!Qa.empty())Qa.pop();
        while(!qa.empty())qa.pop();
        while(!Qb.empty())Qb.pop();
        while(!qb.empty())qb.pop();
        while(!Qe.empty())Qe.pop();
        for(i=1;i<=n;++i)if(usea[i])if(useb[i])++tot;
        else{Qa.push(dtb(i));qb.push(dtb(i));}
        else if(useb[i]){Qb.push(dta(i));qa.push(dta(i));}
        else{
            Qe.push(dte(i));
            qa.push(dta(i));qb.push(dtb(i));
        }
        while(l--){
            while(!Qa.empty()&&useb[Qa.top().p])Qa.pop();
            while(!Qb.empty()&&usea[Qb.top().p])Qb.pop();
            while(!Qe.empty()&&(usea[Qe.top().p]||useb[Qe.top().p]))Qe.pop();
            while(usea[qa.top().p])qa.pop();
            while(useb[qb.top().p])qb.pop();
            if(tot){
                --tot;
                x=qa.top().p;y=qb.top().p;qa.pop();qb.pop();
                ans+=a[x]+b[y];
                usea[x]=useb[y]=1;
                if(x==y)++tot;
                else{
                    if(useb[x])++tot;
                    else Qa.push(dtb(x));
                    if(usea[y])++tot;
                    else Qb.push(dta(y));
                }
                continue;
            }
            if(!Qa.empty()){y=Qa.top().p;x=qa.top().p;}
            else x=y=0;
            if(!Qb.empty()){p=Qb.top().p;q=qb.top().p;}
            else p=q=0;
            t=Qe.empty()?0:Qe.top().p;
            ans+=(maxn=max(a[t]+b[t],max(a[x]+b[y],a[p]+b[q])));
            if(maxn==a[x]+b[y]){
                Qa.pop();qa.pop();
                usea[x]=useb[y]=1;
                if(useb[x])++tot;
                else Qa.push(dtb(x));
            }else if(maxn==a[p]+b[q]){
                Qb.pop();qb.pop();
                usea[p]=useb[q]=1;
                if(usea[q])++tot;
                else Qb.push(dta(q));
            }else{
                Qe.pop();
                usea[t]=useb[t]=1;
            }
        }
        wt(ans);
    }
    flush();
    return 0;
}
View Code

 

posted @ 2019-07-28 14:29  wangyuchen  阅读(200)  评论(0编辑  收藏  举报