HDU多校 - three arrays(字典树+bfs)

HDU多校 - three arrays(字典树+bfs)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6625

题意

给出两个数组A,B求任意交换A数组中的顺序和B数组中的数组,求两者对应异或的C数组字典序最小

数据范围: 1 ≤ N ≤ 1 0 5 1\le N \le 10^5 1N105


思路

我们将A数组的数据全部转换成为01串,插入字典树A中,将B数组中的数据全部转换成为01串插入字典树B中。

将两个树同时BFS,显然前缀相等的越多越好,我们就将其分成三类,

  1. 两棵树同时向左边移动
  2. 两棵树同时向右边移动
  3. 两棵树互相反向移动

我们需要做的就是将状态记录下来,方便转移。

因为最多会有N种状态,所以BFS的复杂度就是 O ( N l o g N ) O(NlogN) O(NlogN)

一定要注意,字典树开的大小,为 O ( N ∗ l e n ) O(N*len) O(Nlen) ,千万不要少,这次就是因为少开了空间而一直T。


代码

#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define pb push_back
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}

typedef double db;
typedef long long ll;
const int MAXN = (int)1e6+7;
const int MaxTot = 5e6+7;
const int INF = (int)0x3f3f3f3f;

struct Aho {
    struct state{
        int next[2];
        int cnt,fa,vis;
    }tree[MaxTot];
    int tot;

    inline void init(int lun) {
        tree[0].next[0] = tree[0].next[1] = 0;
        tree[0].cnt = tree[0].fa = tree[0].vis = 0;
        tree[1].next[0] = tree[1].next[1] = 0;
        tree[1].cnt = tree[1].fa = 0;
        tree[1].vis = lun;
        tot = 1;
    }

    inline void insert(char *S,int lun) { //构造字典树,插入S这个串
        int n = strlen(S);
        int now = 1;
        tree[now].cnt ++;
        rep(i,0,n-1) {     //提取出每个字符
            char c = S[i]-'0';
            if (tree[tree[now].next[c]].vis != lun) {
                tree[now].next[c] = ++tot;
                int son = tot;
                tree[son].cnt = 1;
                tree[son].fa = now;
                tree[son].next[0] = tree[son].next[1] = 0;
                tree[son].vis = lun;
            }else {
                tree[tree[now].next[c]].cnt ++;
            }
            now = tree[now].next[c];
        }
        //tree[now].cnt++;          //走到了结束位置,最后++
    }
}a,b;

int N;
char str[50];
int valA[MAXN];
int valB[MAXN];
inline void toString(int tmp) {
    int len = 0;
    if (tmp == 0) str[len++] = '0';
    while (tmp) {
        int to = tmp%2;
        str[len++] = to+'0';
        tmp>>=1;
    }
    rep(i,len,29) {
        str[i] = '0';
    }
    rep(i,0,14)   swap(str[i],str[29-i]);
    str[30] = 0;
}

struct Node{
    int l,r,cnt,dep;
    ll val;
    Node(int l = 0,int r = 0,ll val = 0,int cnt = 0,int dep = 0):l(l),r(r),val(val),cnt(cnt),dep(dep){}
};
vector<int> ans;
inline ll set1(ll x,int id) {
    ll res = x;
    res |= 1LL<<(30-id);
    return res;
}
inline void getAnum(int id,int &l,int &r,int &lid,int &rid) {
    int tl = a.tree[id].next[0];
    int tr = a.tree[id].next[1];
    int lun = a.tree[id].vis;
    if (a.tree[tl].vis != lun) l = 0;
    else          l = a.tree[tl].cnt;

    if (a.tree[tr].vis != lun)  r = 0;
    else           r = a.tree[tr].cnt;
    lid = tl;
    rid = tr;
}
inline void getBnum(int id,int &l,int &r,int &lid,int &rid) {
    int tl = b.tree[id].next[0];
    int tr = b.tree[id].next[1];
    int lun = b.tree[id].vis;
    if (b.tree[tl].vis != lun) l = 0;
    else          l = b.tree[tl].cnt;

    if (b.tree[tr].vis != lun)  r = 0;
    else           r = b.tree[tr].cnt;
    lid = tl;
    rid = tr;
}
inline void setAnum(int id,int l,int r) {
    int tl = a.tree[id].next[0];
    int tr = a.tree[id].next[1];
    int lun = a.tree[id].vis;
    a.tree[tl].cnt = l;
    a.tree[tr].cnt = r;
}
inline void setBnum(int id,int l,int r) {
    int tl = b.tree[id].next[0];
    int tr = b.tree[id].next[1];
    int lun = b.tree[id].vis;
    b.tree[tl].cnt = l;
    b.tree[tr].cnt = r;
}
queue<Node> qu;
void bfs(int N) {
    while (!qu.empty()) qu.pop();
    qu.push(Node(1,1,0,N,0));
    while (!qu.empty()) {
        Node k = qu.front();qu.pop();

        if (k.dep == 30) {
            rep(i,1,k.cnt) {
                ans.pb(k.val);
            }
            continue;
        }
        int cnt = k.cnt;
        int anum0,anum1,alid,arid;
        int bnum0,bnum1,blid,brid;
        getAnum(k.l,anum0,anum1,alid,arid);
        getBnum(k.r,bnum0,bnum1,blid,brid);
        int mn0 = min(cnt,min(anum0,bnum0)); cnt -= mn0;
        int mn1 = min(cnt,min(anum1,bnum1)); cnt -= mn1;
        anum0 -= mn0;bnum0 -= mn0;
        anum1 -= mn1;bnum1 -= mn1;
        int giv01 = min(cnt,min(anum0,bnum1));cnt -= giv01;
        int giv10 = min(cnt,min(anum1,bnum0));cnt -= giv10;
        anum0 -= giv01;bnum1 -= giv01;
        anum1 -= giv10;bnum0 -= giv10;
        if (mn0) {
            ll sta = k.val;
            Node to = Node(alid,blid,sta,mn0,k.dep+1);
            qu.push(to) ;
        }
        if (mn1) {
            ll sta = k.val;
            Node to = Node(arid,brid,sta,mn1,k.dep+1);
            qu.push(to);
        }
        if (giv01) {
            ll sta = set1(k.val,k.dep+1);
            Node to = Node(alid,brid,sta,giv01,k.dep+1);
            qu.push(to) ;
        }
        if (giv10) {
            ll sta = set1(k.val,k.dep+1);
            Node to = Node(arid,blid,sta,giv10,k.dep+1);
            qu.push(to);
        }
        setAnum(k.l,anum0,anum1);
        setBnum(k.r,bnum0,bnum1);
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    rep(ca,1,T) {
        a.init(ca);//不必每次都有
        b.init(ca);
        ans.clear();
        scanf("%d",&N);
        rep(i,1,N) {
            scanf("%d",&valA[i]);
            toString(valA[i]);
            //debug(str);
            a.insert(str,ca);
        }
        rep(i,1,N) {
            scanf("%d",&valB[i]);
            toString(valB[i]);
            //debug(str);
            b.insert(str,ca);
        }
        bfs(N);
        sort(ans.begin(),ans.end());
        rep(i,0,ans.size()-1) {
            printf("%d%c",ans[i],(i==ans.size()-1?'\n':' '));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Best KeyBoard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值