Codeforces 976E/925C (01Trie树)

传送门


题面:

C. Big Secret
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Vitya has learned that the answer for The Ultimate Question of Life, the Universe, and Everything is not the integer 54 42, but an increasing integer sequence a1,,an

. In order to not reveal the secret earlier than needed, Vitya encrypted the answer and obtained the sequence b1,,bn

using the following rules:

  • b1=a1
; bi=aiai1 for all i from 2 to n, where xy is the bitwise XOR of x and y
  • .

It is easy to see that the original sequence can be obtained using the rule ai=b1bi

.

However, some time later Vitya discovered that the integers bi

in the cypher got shuffled, and it can happen that when decrypted using the rule mentioned above, it can produce a sequence that is not increasing. In order to save his reputation in the scientific community, Vasya decided to find some permutation of integers bi so that the sequence ai=b1bi

is strictly increasing. Help him find such a permutation or determine that it is impossible.

Input

The first line contains a single integer n

(1n105

).

The second line contains n

integers b1,,bn (1bi<260

).

Output

If there are no valid permutations, print a single line containing "No".

Otherwise in the first line print the word "Yes", and in the second line print integers b1,,bn

 — a valid permutation of integers bi. The unordered multisets {b1,,bn} and {b1,,bn} should be equal, i. e. for each integer x the number of occurrences of x in the first multiset should be equal to the number of occurrences of x in the second multiset. Apart from this, the sequence ai=b1bi

should be strictly increasing.

If there are multiple answers, print any of them.

Examples
Input
Copy
3
1 2 3
Output
Copy
No
Input
Copy
6
4 7 7 12 31 61
Output
Copy
Yes
4 12 7 31 7 61 
Note

In the first example no permutation is valid.

In the second example the given answer lead to the sequence a1=4

, a2=8, a3=15, a4=16, a5=23, a6=42

.


Codeforces (c) Copyright 2010-2018 Mike Mirzay

    题目描述:给你一个n个数的数列,问你是否可以使数列中的某些元素调换,使得新数列满足,Ai=(B1 xor B2 xor...Bi)严格单调递增。

    题目分析:因为这道题所要我们求的是异或和递增,我们不妨从最终的异或和开始倒推,每次都让他递减,那我们就可以贪心的选择减少得最少的。

    而因为这题我们维护的是异或和,因此我们可以通过Trie树进行维护。

    具体的做法是,我们从最高位往地位去枚举,如果当前的位数为s=1,则无论x取0还是1都会使得最终的s变小,而我们希望减少量不至于太大,因此我们优先考虑x=0的情况,如果找不到x=1,再考虑x=0的情况。

    如果当前的位数s=0,则如果我们取x=1,会使得s在这一位上变大,这种操作只在高位存在s从1变成0的情况下才能够成立,如果成立,则从减少变化量的角度来讲,则优先得从x=0来考虑,x=1找不到再找x=0的。

    整体是的做法就类似与在Trie树上去做一趟数位dp,不断寻找符合条件的数,最后存储即可。

    具体可以看一下代码

#include <bits/stdc++.h>
#define maxn 6000005
using namespace std;
typedef long long ll;
int n;
struct Trie{
    int trie[maxn][2];//trie树
    int cnt[maxn];//每个节点所经过的数量
    int root=0;//根
    ll val[maxn];//中断点的坐标
    ll xorsum=0;//异或和
    ll ans[maxn/10];//答案
    int C=0;
    int newroot(){//新开结点
        trie[C][0]=trie[C][1]=-1;
        cnt[C]=0;
        return C++;
    }
    void Insert(ll x){//trie树的插入
        ll p=root;
        for(int i=60;i>=0;i--){
            ll id=(x>>i)&1;
            if(trie[p][id]==-1) trie[p][id]=newroot();
            p=trie[p][id];
            cnt[p]++;
        }
        val[p]=x;
    }
    bool check(ll xorsum,ll &res,int index,bool limit,int dep){//limit代表前一位是否有从1变为0的情况,dep代表深度
        if(index!=root&&(cnt[index]==0||index==-1)) return false;
        if(dep==-1){//深度为-1证明完全满足条件,则最终结果为val[index]
            res=val[index];
            cnt[index]--;
            return true;
        }
        int id=(xorsum>>dep)&1;//获取当前异或和的深度的位数
        if(id==0){//判断当前位为0
            bool ret=(check(xorsum,res,trie[index][0],limit,dep-1))||
            (!limit&&check(xorsum,res,trie[index][1],limit,dep-1));
            if(ret==0) return false;
            cnt[index]--;
            return true;
        }
        else{//判断当前位为1的情况
            bool ret=(check(xorsum,res,trie[index][0],limit,dep-1))||
            (check(xorsum,res,trie[index][1],false,dep-1));
            if(ret==0) return false;
            cnt[index]--;
            return true;
        }
    }
    void solve(){
        for(int i=n-1;i>=0;i--){
            ll res;
            bool ret=check(xorsum,res,root,true,60);
            if(ret==0){
                puts("No");
                return;
            }
            ans[i]=res;
            assert(xorsum>(xorsum^res));
            xorsum^=res;
        }
        puts("Yes");
        for(int i=0;i<n;i++){
            cout<<ans[i]<<" ";
        }
        puts("");
    }
}Tree;
int main()
{
    scanf("%d",&n);
    Tree.root=Tree.newroot();
    for(int i=0;i<n;i++){
        ll x;
        scanf("%I64d",&x);
        Tree.Insert(x);
        Tree.xorsum^=x;
    }
    Tree.solve();
}

原文地址:https://www.cnblogs.com/Chen-Jr/p/11007295.html