big (Trie)

来源:互联网 发布:粒子群算法matlab实例 编辑:程序博客网 时间:2024/06/11 00:24

10.4

思路:
每次操作相当于把前面几个数都在二进制意义下左移一位,然后与后面的所有数异或起来,再找x。
对手做的是将 x在二进制下左移一位,把超出二进制下n位的部分接到最后。而异或 i个数后左移等价于开始时先把前 i个数左移一位,再异或起来。
这是因为,这个运算只是二进制位上的位置变化,而对于按位异或时,二进制位置上的规律变化之后,不同数间的每个二进制位还是对的上的,而按位异或只要保证位置相对,位置上的交换其实没有关系。然后尽管x选取本身也会左移,但是鉴于我们并不关心x到底是什么,所以查找时就直接查找x左移之后的值操作后最小的最大值就行了 。
问题转化为选一个数,使它左移位后与 m+1 个给定数分别异或的最小值最大。
将 m+1 个数建立一棵字典树,从上到下遍历来最大化结果:走到一个点时,如往下只有0,说明我们这一位取1异或后只能是1,累计结果中加上这一位的值,只有 1也一 样;如果既有 0又有 1,说明这一位无论怎么取最后都是0, 分别往下走再比较即可 。

#include <cstdio>#include <iostream>using namespace std;struct node{    int big, num, dep;    node *ch[2];}pool[5000010], *tail = pool,*root;int n,m,a[200010],b[200010];node *newnode(int p){    node *nd = ++tail;    nd->dep = p;    nd->ch[0] = nd->ch[1] = 0;    return nd;}void insert(int x){    node *p = root;    for(int i=n-1; i>=0; i--){        int idx = ( (1<<i) & x ) > 0;        if( !p->ch[idx] )            p->ch[idx] = newnode(i);        p = p->ch[idx];    }}int wrk(int x){    return (x<<1) % (1<<n) + (x<<1) / (1<<n);}//(2x/2^n + 2x) mod 2^n void dfs(node *nd){    if(!nd->ch[1] && !nd->ch[0]){        nd->big = 0, nd->num = 1;        return ;    }    if(!nd->ch[1]){        dfs(nd->ch[0]);        nd->num = nd->ch[0]->num;        nd->big = nd->ch[0]->big + (1<<(nd->dep)-1);    }    else if(!nd->ch[0]){        dfs(nd->ch[1]);        nd->num = nd->ch[1]->num;        nd->big = nd->ch[1]->big + (1<<(nd->dep)-1);    }    else{        dfs(nd->ch[0]), dfs(nd->ch[1]);        if(nd->ch[0]->big > nd->ch[1]->big)            nd->big = nd->ch[0]->big, nd->num = nd->ch[0]->num;        else if(nd->ch[0]->big < nd->ch[1]->big)            nd->big = nd->ch[1]->big, nd->num = nd->ch[1]->num;        else nd->big = nd->ch[0]->big, nd->num = nd->ch[0]->num + nd->ch[1]->num;    }}int main(){    freopen ("big.in", "r", stdin);    freopen ("big.out", "w", stdout);    scanf("%d%d", &n, &m);    for(int i=1; i<=m; i++)        scanf("%d", &a[i]), b[1] ^= a[i];    root = newnode(n);    for(int i=1; i<=m; i++)        b[i+1] = b[i] ^ a[i] ^ wrk(a[i]);    for(int i=1; i<=m+1; i++)        insert( b[i] );    dfs( root );    printf("%d\n%d\n", root->big, root->num);    return 0;}
原创粉丝点击