zoukankan      html  css  js  c++  java
  • 【题解】Luogu P5470 [NOI2019]序列

    原题传送门

    同步赛上我一开始想了个看似正确却漏洞百出的贪心:按(a_i+b_i)的和从大向小贪心

    随便想想发现是假的,然后就写了个28pts的暴力dp

    杜神后半程说这题就是个贪心,但我没时间写了 (实际是没想明白)

    我们来说这道题的正解:

    我们先珂以满足和最大,再满足并集大小大于等于(l)。所以我们先将(a)序列和(b)序列排序,取出两个序列的前(k)

    如果并集大小大于等于(l)就直接统计答案

    否则我们要凑满(l)个都包含的,在凑的过程中动态更新答案

    我们在两个序列中都选中前(k-l)个不含有并集的数,并加入答案中,易知这些数一定含在答案中(这个珂以在草稿纸上推一推)。接下来考虑如何凑并集元素,一次凑一组:

    1.两个都没被选中的情况下的最大值,并将它们选中

    2.一个被选中的情况下的最大值。假设(a[rk[i]])选中了,但(b[rk[i]])没选中,我们就要找到一个最小的j使得(a[rk[j]])没被选中,我们就珂以选中(b[rk[i])(a[rk[j]]),使得a中不成对的还是(k-l)个。a,b反之亦然

    我们求出1、2两种情况贡献最大值并更新选中状态(都用堆维护,具体细节见代码),重复(l)次即可求出答案

    注意:两次2也许就会将两个都没选中的变成都选中,所以要及时舍掉不合法的

    #include <bits/stdc++.h>
    #define N 200005
    #define ll long long
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register ll x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int T,n,k,l,a[N],b[N],ar[N],br[N],va[N],vb[N],vis[N];
    ll ans;
    inline bool cmpa(register int x,register int y)
    {
        return a[x]>a[y];
    }
    inline bool cmpb(register int x,register int y)
    {
        return b[x]>b[y];
    }
    struct node{
        int pos,val;
        inline bool operator < (const node &it) const {
            return val<it.val;
        }
    };
    inline bool chkmax(register int &a,register int b)
    {
        return a<b?a=b,1:0;
    }
    int main()
    {
        T=read();
        while(T--)
        {
            n=read(),k=read(),l=read();
            for(register int i=1;i<=n;++i)
                a[i]=read(),ar[i]=i,va[i]=vb[i]=vis[i]=0;
            for(register int i=1;i<=n;++i)
                b[i]=read(),br[i]=i;
            sort(ar+1,ar+1+n,cmpa);
            sort(br+1,br+1+n,cmpb);
            for(register int i=1;i<=k;++i)
                va[ar[i]]=1,vb[br[i]]=1;
            ans=0;
            priority_queue<int> pa,pb;
            priority_queue<node> qa,qb;
            for(register int i=1;i<=n;++i)
                if(va[i]&&vb[i])
                    qb.push((node){i,a[i]+b[i]}),vis[i]=1;
            if(qb.size()>=l)
            {
                for(register int i=1;i<=n;++i)
                {
                    if(va[i])
                        ans+=a[i];
                    if(vb[i])
                        ans+=b[i];
                }
            }
            else
            {
                for(register int i=1,tot=0;i<=k;++i)
                    if(!vb[ar[i]])
                    {
                        if(tot<k-l)
                            ans+=a[ar[i]],vis[ar[i]]=1,pa.push(b[ar[i]]);
                        else
                            qa.push((node){ar[i],a[ar[i]]+b[ar[i]]});
                        ++tot;
                    }
                for(register int i=1,tot=0;i<=n;++i)
                    if(!va[br[i]])
                    {
                        if(tot<k-l)
                            ans+=b[br[i]],vis[br[i]]=1,pb.push(a[br[i]]);
                        else
                            qb.push((node){br[i],a[br[i]]+b[br[i]]});
                        ++tot;
                    }
                int af=1,bf=1;
                while(l--)
                {
                    while(af<=k&&vis[ar[af]])
                        ++af;
                    while(bf<=k&&vis[br[bf]])
                        ++bf;
                    while(!qa.empty()&&vis[qa.top().pos]&&!(va[qa.top().pos]&&vb[qa.top().pos]))
                        qa.pop();
                    while(!qb.empty()&&vis[qb.top().pos]&&!(va[qb.top().pos]&&vb[qb.top().pos]))
                        qb.pop();
                    int maxx=0,typ=-1;
                    if(!qa.empty())
                        maxx=qa.top().val,typ=0;
                    if(!qb.empty()&&chkmax(maxx,qb.top().val))
                        typ=1;
                    if(!pa.empty()&&af<=k&&chkmax(maxx,pa.top()+a[ar[af]]))
                        typ=2;
                    if(!pb.empty()&&bf<=k&&chkmax(maxx,pb.top()+b[br[bf]]))
                        typ=3;
                    ans+=maxx;
                    if(typ==0)
                        vis[qa.top().pos]=1,qa.pop();
                    else if(typ==1)
                        vis[qb.top().pos]=1,qb.pop();
                    else if(typ==2)
                        vis[ar[af]]=1,pa.pop(),pa.push(b[ar[af]]);
                    else
                        vis[br[bf]]=1,pb.pop(),pb.push(a[br[bf]]);
                }
            }
            write(ans),puts("");
        }
        return 0;
    }
    
  • 相关阅读:
    用msi安装MySQL时MySQL Server组件不能安装,或安装失败
    在Django中连接MySQL数据库(Python3)
    2,简单的Python爬虫
    把自己的电脑做成服务器,并搭建自己的网站
    任务计划程序(让计算机自动执行程序)
    1,Python爬虫环境的安装
    response和request的区别以及常见问题解决
    Microsoft Visual Studio 2010 Service Pack 1 更新 (KB3002340)
    设置radiobutton 都不选中
    QQ邮件发送问题
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/11200711.html
Copyright © 2011-2022 走看看