usaco6.1-Cow XOR:trie树

Cow XOR
Adrian Vladu -- 2005

Farmer John is stuck with another problem while feeding his cows.
All of his N (1 ≤ N ≤ 100,000) cows (numbered 1..N) are
lined up in front of the barn, sorted by their rank in their social
hierarchy. Cow #1 has the highest rank; cow #N has the least rank.
Every cow had additionally been assigned a non-unique integer number
in the range 0..(221 - 1).

Help FJ choose which cows will be fed first by selecting a
sequence of consecutive cows in the line such that the bitwise "xor"
between their assigned numbers has the maximum value. If there are
several such sequences, choose the sequence for which its last cow
has the highest rank. If there still is a tie, choose the shortest
sequence.

TIME LIMIT: 0.5 sec

PROGRAM NAME: cowxor

INPUT FORMAT

  • Line 1: A single integer N
  • Lines 2..N+1: N integers ranging from 0 to 221 - 1, representing the cows‘ assigned
    numbers. Line j describes cow of social hierarchy j-1.

SAMPLE INPUT (file cowxor.in)

5
1
0
5
4
2

INPUT DETAILS:

There are 5 cows. Cow #1 had been assigned with 1; cow #2 with 0; cow #3 with 5; cow #4 with 4; cow #5 with 2.

OUTPUT FORMAT

  • Line 1: Three space-separated integers, respectively: the maximum requested value, the position where the sequence begins, the position where the sequence ends.

SAMPLE OUTPUT (file cowxor.out)

6 4 5

OUTPUT DETAILS:

4 xor 2 = 6 (001) xor (010) = (011)



题目大意:找到一个连续的区间,使各数异或之后的结果最大。

算法:用a[i]表示a[1...i]的异或结果,则任一区间的异或结果s[i...j]=a[i-1] xor a[j].

现在问题变成了,对于每一个j,我们需要找到一个i≤j,使得a[i-1] xor a[j]最大。

这时候我们可以用trie树实现这样的一个查找。

我们将a中的元素先转化成二进制字符串再插入到trie中,因此trie树中每一个节点对应一条0和一条1的边。

此时a[j]的二进制字符串对应一条从trie树的根节点走到叶子节点的路径,我们在找符合条件的a[i-1]的过程就是从根节点出发,在某一深度上尽量沿着与a[j]相反的边来走,就是说,假设a[j]的某一位是1,那a[i-1]应尽量取0(就是走0的边),不存在此边的时候再选另一边。

注意这里的数组不能开到221,usaco会MLE,实际上完全不用这么大,数据虽然很大,但是并不是每个结点都有0,1两条边。

Executing...
   Test 1: TEST OK [0.008 secs, 13748 KB]
   Test 2: TEST OK [0.005 secs, 13748 KB]
   Test 3: TEST OK [0.005 secs, 13748 KB]
   Test 4: TEST OK [0.005 secs, 13748 KB]
   Test 5: TEST OK [0.049 secs, 13748 KB]
   Test 6: TEST OK [0.124 secs, 13748 KB]
   Test 7: TEST OK [0.227 secs, 13748 KB]
   Test 8: TEST OK [0.213 secs, 13748 KB]
   Test 9: TEST OK [0.227 secs, 13748 KB]
   Test 10: TEST OK [0.230 secs, 13748 KB]
   Test 11: TEST OK [0.308 secs, 13748 KB]
   Test 12: TEST OK [0.289 secs, 13748 KB]
   Test 13: TEST OK [0.227 secs, 13748 KB]
   Test 14: TEST OK [0.221 secs, 13748 KB]
   Test 15: TEST OK [0.343 secs, 13748 KB]
   Test 16: TEST OK [0.329 secs, 13748 KB]
   Test 17: TEST OK [0.348 secs, 13748 KB]
   Test 18: TEST OK [0.221 secs, 13748 KB]
   Test 19: TEST OK [0.046 secs, 13748 KB]
   Test 20: TEST OK [0.008 secs, 13748 KB]

All tests OK.

  1 #include <iostream>
  2 #include <cstring>
  3 #include <vector>
  4 #include <stdio.h>
  5 #include <string>
  6 using namespace std;
  7 #define BIT_AT(x,n) ((x & (1<<n))>>n)
  8
  9 const int maxnode = 807152;
 10 const int sigma_size = 2;
 11
 12 // 字母表为全体小写字母的Trie
 13 struct Trie
 14 {
 15     int ch[maxnode][sigma_size]; // ch[i][j]表示i节点通过字母为j的边的连接下一节点的编号,没有即为0
 16     int val[maxnode];
 17     int sz; // 结点总数
 18     void clear()
 19     {
 20         sz = 1;    // 初始时只有一个根结点
 21         memset(ch[0], 0, sizeof(ch[0]));
 22     }
 23     int idx(char c)
 24     {
 25         return c - ‘0‘;    // 字符c的编号
 26     }
 27
 28     // 插入字符串s,附加信息为v。注意v必须非0,因为0代表“本结点不是单词结点”
 29     // 附加信息为i,即第几个单词
 30     void insert(const char *s, int v)
 31     {
 32         int u = 0, n = strlen(s);
 33         for(int i = 0; i < n; i++)
 34         {
 35             int c = idx(s[i]);
 36             if(!ch[u][c])   // 结点不存在
 37             {
 38                 memset(ch[sz], 0, sizeof(ch[sz]));
 39                 val[sz] = 0;  // 中间结点的附加信息为0,因此clear时不用memset()
 40                 ch[u][c] = sz++; // 新建结点
 41             }
 42             u = ch[u][c]; // 往下走
 43         }
 44         val[u] = v; // 字符串的最后一个字符的附加信息为v
 45     }
 46
 47     int find_min(int x,int &min_i)
 48     {
 49         int Min=0;
 50         int u = 0;
 51         for(int i = 0; i <= 21; i++)
 52         {
 53             int tmp=BIT_AT(x,21-i);
 54             int c = (tmp^1);
 55             if(!ch[u][c])
 56                 c=tmp;
 57             u = ch[u][c];
 58             Min=Min*2+c;
 59         }
 60         min_i=val[u];
 61         return Min;
 62     }
 63 };
 64 //////////////////////////////////////////////////////////////////////////////////////
 65 //////////////////////////////////////////////////////////////////////////////////////
 66 Trie trie;
 67 // 将某个数的二进制转换成22位字符串
 68 string toString(int x)
 69 {
 70     string str;
 71     for(int i=21;i>=0;i--)
 72     {
 73         str.append(BIT_AT(x,i)==1?"1":"0");
 74     }
 75     return str;
 76 }
 77
 78 int a[100010]={0};
 79 int b[100010]={0};
 80
 81 int main()
 82 {
 83     freopen("cowxor.in","r",stdin);
 84     freopen("cowxor.out","w",stdout);
 85     int n;
 86     cin>>n;
 87     trie.clear();
 88     // 初始插入0
 89     trie.insert(toString(0).c_str(),0);
 90
 91     int ans=-1,pos1=-1,pos2=-1;
 92     for(int i=1;i<=n;i++)
 93     {
 94         int t;
 95         scanf("%d",&t);
 96         b[i]=t;
 97         a[i]=a[i-1]^t;
 98         int min_i;
 99         int tmp=trie.find_min(a[i],min_i)^a[i];
100         if(ans<tmp/* || (ans==tmp && b[pos2]<t) || (ans==tmp && b[pos2]==t && pos2-pos1>i-min_i-1)*/)
101         {
102             ans=tmp;
103             pos1=min_i+1;
104             pos2=i;
105         }
106         trie.insert(toString(a[i]).c_str(),i);
107     }
108     printf("%d %d %d\n",ans,pos1,pos2);
109
110     return 0;
111 }
时间: 2024-10-29 10:45:58

usaco6.1-Cow XOR:trie树的相关文章

51nod 1295 XOR key (可持久化Trie树)

1295 XOR key  题目来源: HackerRank 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 160 难度:6级算法题 给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R).求A[L] 至 A[R] 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值是多少? Input 第1行:2个数N, Q中间用空格分隔,分别表示数组的长度及查询的数量(1 <= N <= 50000, 1 <= 

hdu 4828 Xor Sum (trie 树模板题,经典应用)

hdu 4825 题目链接 题意:给定n个数,然后给出m个询问,每组询问一个数x,问n中的数y使得x和y的异或和最大. 思路:字典树..把每个数转化成二进制,注意补全前导0,使得所有数都有相同的位数. 如果想要异或和最大,那么每一位尽可能都是1. 所以做法是,先构建字典树,然后每次find的时候,尽可能按照和当前寻找的数的位相反的位的方向走(如果有的话) 比如当前位是1,那我就往0的方向走. 需要注意的是,多组数据,每次要重新初始化一遍. 做法是 在struct 中重新 root = new N

NBUT 1525 Cow Xor(01字典树+前缀思想)

[1525] Cow Xor 时间限制: 2000 ms 内存限制: 65535 K 问题描述 农民约翰在喂奶牛的时候被另一个问题卡住了.他的所有N(1 <= N <= 100,000)个奶牛在他面前排成一行(按序号1..N的顺序),按照它们的社会等级排序.奶牛#1有最高的社会等级,奶牛#N最低.每个奶牛同时被指定了一个不唯一的附加值,这个数在0..2^21 - 1的范围内. 帮助农民约翰找出应该从哪一头奶牛开始喂,使得从这头奶牛开始的一个连续的子序列上,奶牛的附加值的异或最大. 如果有多个这

HDU 5269 ZYB loves Xor I( 01 Trie 树)

题目链接:传送门 题意: 求 for i: 1~n  forj:1~n lowbit(a[i]^a[j]) lowbit(x)表示取x的最低位1. lowbit(3)=1    lowbit(6)=2; 分析: 因为其中有一个异或运算,我们就先来分析这个异或运算.发现如果lowbit(x^y) = 2^p; 那么把x^y转化成2进制后他们的前p-1位一定是相同的.那么思路就来了把所有的数字转换 成01字符串,注意要使他们的长度都相等,然后建一颗trie树.然后遍历的时候如果同时 有左右孩子的话那

BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】

题目分析: 很无聊的一道题目.首先区间内单点对应异或值的询问容易想到trie树.由于题目在树上进行,case1将路径分成两段,然后dfs的时候顺便可持久化trie树做询问.case2维护dfs序,对dfs序建可持久化的trie树.这样做的空间复杂度是O(nw),时间复杂度是O(nw). 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=102000; 5 6 int n,q; 7 int v[maxn

HDU4825 Xor Sum(贪心+Trie树)

今天本来想写一个可持久化Trie树,发现这道题一直没做就补上了. 其实思路很简单,假如说两个数,和同一个数异或,很显然,由于进制,高位上的一个1可以大于低位上所有1,所以即使后面的情况再糟糕,也比取后面好的值高(其实就是1000比0111大) 所以可以建一个01线段树,从高往低插入一个数,比较时取反即可^_^ 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace st

ifrog-1028 Bob and Alice are playing numbers(trie树)

题目链接: Bob and Alice are playing numbers DESCRIPTION Bob and his girl friend are playing game together.This game is like this: There are nn numbers. If op = 11,Bob wants to find two numbers aiai and ajaj,that aiai & ajaj will become maximum value. If

【bzoj3281】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 输入 第一行包含两个整数 N  ,M,含义如问题描述所示.   第二行包含 N个非负整数,表示初始的序列 A . 接下来 M行,每行描述一个

[USACO 6.1.3] Cow XOR

题目大意 给出一个序列,求一个连续的子序列的异或和最大. 题解 先探究一下异或的性质. 1.可逆性: A XOR B XOR B = A; 2.满足结合律: (A XOR B) XOR C = A XOR (B XOR C); 利用以上两个性质有助于我们解题. 假设有一序列 A1,A2,A3......An-1,An ,可以得到另一序列 B1,B2,B3......Bn-1,Bn ,其中Bi表示A序列前i个元素的异或和. 所以,要求A序列从i到j的异或和就是Bj-Bi-1. 用这个结论就可以写一