2019HDU多校第五场 1002.three arrays(01字典树)

输入两个数组,可以将这两个数组顺序任意变化,问相同位置异或能生成的字典序最小序列。

一上来奇奇哥就告诉我这多半是01字典树,于是开始思考01字典树。

这题麻烦在于两个数组都能随意排列,一开始想到一个序列建01字典树,另一个序列在上面跑,仔细想了想发现这样要枚举一个数组的排列,铁超时。

自闭了一会儿想到干脆俩数组都建成01字典树然后用字典树跑字典树吧,敲的挺顺的一下就过了样例,3点提交了第一发,之后就wa到了比赛结束…赛后要了数据来测发现小样例完全正确,大样例输出就非常迷,才反应过来数组开小了orz,真实自闭,hdu不相信runtime error。

对于两个序列都建01字典树,之后贪心的dfs跑,如果两颗字典树都有相同的边,就往那边跑,如果实在没有,就只能跑不同的边。

赛后讨论的时候纠结了一下正确性(还不知道是数组开小了导致的wa,orz),思考过后发现是没有问题的,纠结的点在于这种做法要跑到最后才能得到一个值,也许先跑到的不是最小值,并且会导致最小值取不到。这种情况其实是不存在的,一般跑的时候,优先跑同边,这种时候可以保证取到的是最小值,如果两颗字典树在同一位置,都有0和1两个分叉,这种时候虽然确实不能保证先dfs到的是最小值,但是一个dfs的是0边,一个dfs的是1边,这两边完全不会相互影响。

最后也因为不能保证最小值先跑到,所以要排个序再输出。

orz,这辈子估计都不会再开小字典树了。

*2019多校第9场1008用下面这份代码改几行就ac了。

ac代码:

#include

using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;

int _, n, a[maxn], b[maxn];

struct Trie {
    int next[maxn * 30][2];
    bool end[maxn * 30];
    int cnt[maxn * 30], sz, root;

    int newNode() {
        ++sz;
        memset(next[sz], 0, sizeof(next[sz]));
        cnt[sz] = 0;
        end[sz] = 0;
        return sz;
    }

    void init() {
        sz = 0;
        root = newNode();
    }

    void add(int x) {
        int p = root;
        for (int i = 29, c; i >= 0; --i) {
            c = (x >> i) & 1;
            if (!next[p][c]) {
                next[p][c] = newNode();
            }
            p = next[p][c];
            ++cnt[p];
        }
        end[p] = 1;
    }

} A, B;

vector<pair<int, int>> ans;

void dfs(int p1, int p2, int x) {
    int e = min(A.cnt[p1], B.cnt[p2]);
    A.cnt[p1] -= e, B.cnt[p2] -= e;
    if (A.end[p1]) {
        ans.push_back({x, e});
        return;
    }
    if ((A.cnt[A.next[p1][0]]) && (B.cnt[B.next[p2][0]])) {
        dfs(A.next[p1][0], B.next[p2][0], x << 1);
    }
    if ((A.cnt[A.next[p1][1]]) && (B.cnt[B.next[p2][1]])) {
        dfs(A.next[p1][1], B.next[p2][1], x << 1);
    }
    if ((A.cnt[A.next[p1][1]]) && (B.cnt[B.next[p2][0]])) {
        dfs(A.next[p1][1], B.next[p2][0], (x << 1) + 1);
    }
    if ((A.cnt[A.next[p1][0]]) && (B.cnt[B.next[p2][1]])) {
        dfs(A.next[p1][0], B.next[p2][1], (x << 1) + 1);
    }
}

int main() {
    scanf("%d", &_);
    while (_--) {
        scanf("%d", &n);
        ans.clear();
        A.init(), B.init();
        for (int i = 0; i < n; ++i) {
            scanf("%d", &a[i]);
            A.add(a[i]);
        }        
        for (int i = 0; i < n; ++i) {
            scanf("%d", &b[i]);
            B.add(b[i]);
        }
        dfs(A.root, B.root, 0);
        sort(ans.begin(), ans.end());
        for (int i = 0; i < ans.size(); ++i) {
            for (int j = 0; j < ans[i].second; ++j) {
                printf("%d", ans[i].first);
                if (j < ans[i].second - 1)
                    printf(" ");
            }
            if (i < ans.size() - 1)
                printf(" ");
        }
        printf("\n");
    }
    return 0;
}

你可能感兴趣的:(ACM)