zoukankan      html  css  js  c++  java
  • 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
    ",ans,pos1,pos2);
    109 
    110     return 0;
    111 }
  • 相关阅读:
    极简代码搞定视频剪辑
    python 遍历本地文件
    安装Anaconda需要知道的pc信息
    ng4 路由多参数传参以及接收
    Js之设置日期时间 判断日期是否在范围内
    VsCode显示左边折叠代码+-按钮
    H5+.Net Webapi集成微信分享前后端代码 微信JS-SDK wx.onMenuShareTimeline wx.onMenuShareAppMessage
    压测工具之JMeter之环境配置及运行
    C# 交集、差集、并集、去重
    Nginx初学者指南
  • 原文地址:https://www.cnblogs.com/oneshot/p/4087826.html
Copyright © 2011-2022 走看看