Algo:在给定N个输入的情况下找到针对各种间隔limis的数组中的max Xor,以及p,q,其中0 <= p <= i <= q <= N

时间:2013-11-28 09:28:38

标签: c++ c algorithm bit-manipulation cin

问题陈述如下:

  

Xorq发明了一种加密算法,该算法广泛使用按位XOR运算。该加密算法使用一系列非负整数x1,x2,... xn作为关键字。为了有效地实现该算法,Xorq需要为给定的整数a,p和q找到(a xor xj)的最大值,使得p <= j <= q。帮助Xorq实现此功能。

     

输入

     

第一行输入包含单个整数T(1 <= T <= 6)。 T测试案例如下。

     

每个测试用例的第一行包含由单个空格分隔的两个整数N和Q(1 <= N <= 100,000; 1 <= Q <= 50,000)。下一行包含由单个空格(0 <= xi <2 ^ 15)分隔的N个整数x1,x2,... xn。接下来的Q行中的每一行描述由三个整数ai,pi和qi组成的查询(0 <= ai&lt; 2 ^ 15,1 <= pi&lt; = qi&lt; = N)。

     

输出

     

对于每个查询,打印(ai xor xj)的最大值,使pi&lt; = j&lt; = qi在一行中。

int xArray[100000];
cin >>t; 
for(int j =0;j<t;j++)   
{        
    cin>> n >>q;

    //int* xArray = (int*)malloc(n*sizeof(int));
    int i,a,pi,qi;        

    for(i=0;i<n;i++)
    {
        cin>>xArray[i];                         
    }

    for(i=0;i<q;i++)
    {
      cin>>a>>pi>>qi;
        int max =0;
      for(int it=pi-1;it<qi;it++)
      {
          int t =  xArray[it] ^ a;
          if(t>max)               
              max =t;

      }   
      cout<<max<<"\n" ;
    } 

除了问题文本中所述的那些(数字未分类)之外,不得做出任何其他假设。 代码功能齐全,但速度不够快;从stdin那里读到的确很慢或者还有什么我想念的吗?

2 个答案:

答案 0 :(得分:0)

XOR翻转位。 XOR的最大结果是0b11111111。

获得最佳结果

  • 如果第i个地方的'a'有1,那么你必须使用第i位= 0的钥匙对其进行异或
  • 如果第i个地方的'a'为0,那么你必须使用第i位= 1的钥匙对它进行异或

简单地说,对于你需要的B位!B

另一个显而易见的事情是高阶位比低阶位更重要。

那是:

  • 如果最高位置的'a'有B并且您找到了最高位=!B
  • 的密钥
  • 然后具有最高位=!B的所有键都比这个更差

这会将您的数字量平均减少一半。

如何从所有密钥构建一个巨大的二叉树,并按树的顺序从树中对它们进行排序,从MSB到LSB。然后,将A从MSB逐位切换到LSB将告诉您接下来要采用哪个左右分支以获得最佳结果。当然,这会忽略PI / QI限制,但肯定会给你最好的结果,因为你总是选择i级的最佳可用位。

现在,如果您注释其子元素的低/高索引范围的树节点(在构建树时仅执行一次),那么稍后在查询案例A-PI-QI时您可以使用它来过滤掉不属于索引范围的分支。

关键是如果您按照MSB-> LSB位顺序排序树级别,那么在“上级节点”执行的决策可以保证您当前处于最佳分支中,并且它将保持即使所有的分支都是最差的:

处于第3级,

的结果
0b111?????
然后

可以扩展到

0b11100000
0b11100001
0b11100010
等等,但即使是?????扩张不佳,总体结果仍然大于

0b11011111

如果您甚至在第3级选择了另一个分支,这将是最好的结果。

我绝对不知道准备树成本需要多长时间,但查询它有32位的A-PI-QI似乎是N次比较和跳跃的32倍,肯定比随机迭代0更快100000次和xor / maxing。而且由于您有多达50000个查询,因此构建此类树实际上可能是一项很好的投资,因为每个密钥集都会构建一次这样的树。

现在,最好的部分是你实际上不需要整棵树。您可以仅从前两个或四个或八个位构建此类,并使用节点中的索引范围将xor-max循环限制为较小的部分。在最坏的情况下,你最终会得到与PiQi相同的范围。充其量只能归结为一个元素。

但是,看看最大的N个键,我认为整个树实际上可能适合内存池,你可能会在没有任何xor-maxing循环的情况下离开。

答案 1 :(得分:0)

我花了一些时间来研究这个问题,并且它可以在各种编程竞赛的背景下找到它。虽然蛮力方法很直观,但它并没有真正解决挑战,因为它太慢了。 为了编写更快的算法,你需要推测这个问题有一些限制因素:

  • 输入包含最多100k个数字,但只有32768(2 ^ 15)个可能的数字
    • 每个输入数组有Q,最大50k,测试用例;每个测试用例由3个值组成,a,pi和qi。由于0 <= a <2 ^ 15并且有50k个案例,因此有可能再次出现相同的值。

我找到了2个解决问题的方法:splitting the input in sqrt(N)区间和building a segment tree(可以找到这些方法的一个很好的解释here

最大的问题是,对于每个测试用例,你可以为a设置不同的值,这会使以前的结果无用,因为你需要计算max(a ^ x [i]),少数测试用例。但是,当Q足够大且值a重复时,可以使用以前的结果。

一旦完成两种方法的实施,我将回到实际结果