2019多校第五场 HDU6625 three arrays(贪心,带删除操作01字典树)

链接HDU6625 three arrays

题意:

给出长度为 n n 的两个序列 a a b b ,对序列内随意排序, a [ i ] b [ i ] = c [ i ]      ( 1 i n ) a[i]\oplus b[i]=c[i]\;\;(1\le i\le n) ,这样得到序列 c c ,要求得出字典序最小的序列 c c

其中 1 n 1 0 5 1\le n\le 10^5 a , b [ 0 , 2 30 ) a,b\in[0,2^{30})



分析:

要求字典序最小,那么只要贪心地从序列 a , b a,b 中尽可能把异或值小的匹配全部选出来,然后从小到大排个序就是答案,

这个就可以很好地用01字典树实现了,先把序列 a , b a,b 分别建成两棵01字典树,然后同时遍历,优先找同为0或同为1的(这样异或就可以尽可能地小),每次遍历完后删除这个值。

因为01字典树删除操作并不是真正的删除,而是利用一个记录访问次数结点次数的数组 n u m [ u ] num[u] ( 详见->传送门 ),所以只要遍历的时候令 n u m [ u ] 1 num[u]-1 即可。



以下代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+50;
const int max_base=30;
int n;
struct bit_tire
{
    int ch[30*maxn][2],val[30*maxn],num[30*maxn],tot;

    void init()
    {
        tot=1;
        ch[0][0]=ch[0][1]=0;
        val[0]=0;
        num[0]=0;
    }

    void ins(int x)
    {
        int u=0;
        num[u]++;
        for(int i=max_base;i>=0;i--)
        {
            int c=(x>>i)&1;
            if(!ch[u][c])
            {
                ch[tot][0]=ch[tot][1]=0;
                val[tot]=0;
                num[tot]=0;
                ch[u][c]=tot++;
            }
            u=ch[u][c];
            num[u]++;
        }
        val[u]=x;
    }
}t[2];
bool check(int ua,int ub,int c1,int c2)  //子结点存在&&其num值>0
{
    return t[0].ch[ua][c1]&&t[0].num[t[0].ch[ua][c1]]&&t[1].ch[ub][c2]&&t[1].num[t[1].ch[ub][c2]];
}
int get_min()
{
    int ua=0,ub=0;
    for(int i=max_base;i>=0;i--)
    {
        if(check(ua,ub,0,0))       //同为0
        {
            ua=t[0].ch[ua][0];
            ub=t[1].ch[ub][0];
        }
        else if(check(ua,ub,1,1))  //同为1
        {
            ua=t[0].ch[ua][1];
            ub=t[1].ch[ub][1];
        }
        else if(check(ua,ub,0,1))  //0和1
        {
            ua=t[0].ch[ua][0];
            ub=t[1].ch[ub][1];
        }
        else                       //1和0
        {
            ua=t[0].ch[ua][1];
            ub=t[1].ch[ub][0];
        }
        t[0].num[ua]--;
        t[1].num[ub]--;
    }
    return t[0].val[ua]^t[1].val[ub];
}
int ans[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        t[0].init();
        t[1].init();
        scanf("%d",&n);
        int a,b;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a);
            t[0].ins(a);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&b);
            t[1].ins(b);
        }
        for(int i=1;i<=n;i++)
            ans[i]=get_min();
        sort(ans+1,ans+n+1);
        for(int i=1;i<=n;i++)
        {
            if(i>1)
                printf(" ");
            printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

发布了214 篇原创文章 · 获赞 40 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Ratina/article/details/98980201