【题解】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;
}
posted @ 2019-07-17 14:13  JSOI爆零珂学家yzhang  阅读(530)  评论(0编辑  收藏  举报