USACO 6.1.3 COWXOR 字典树

这题一开始看的时候一点思路都没有,后来看到题解才想到。其实这题并不难,只是涉及到位运算和字典树罢了。

用a[i]表示前i个数的异或和,那么序列[i,j]的异或和就是a[j] xor a[i-1]。

如果单是枚举i和j的话复杂度到了n^2,肯定会爆,那么就要换一种方法。

问题的关键在对于每个a[j],要于找到i使i到j的异或值最大。 

异或最大,感性上认识就是,有差别的位数靠近高位,且越多越好。再看看这个字典树, 如果把26个字母改成0和1的孩子,这样可以形成一个21层的二叉树。从最高位找起,如果有和当前所在的位数相异的位数,就选那条路。 不行,再妥协选相同的位数。

要让这样的做法可行,要插入一个结点选一次(不能选自己之后的结点),且选完课才能把自己插进树里(不能选自己)

代码:

<pre name="code" class="plain">{
ID: ymwbegi1
PROG: cowxor
LANG: PASCAL
}

var
  n,i,ans,p,q,x,f1,s,a1:longint;
  f:array[1..21] of longint;
  a:array[1..600000] of longint;
  c:array[1..600000] of longint;
  t,son:array[1..600000,1..2] of longint;

procedure count(d,f1:longint);
var
  i:longint;
begin
  if f1=0 then
  begin
    s:=t[d,2];
    exit;
  end;
  for i:=1 to t[d,1] do
    if c[son[d,i]]<>f[f1] then
    begin
      count(son[d,i],f1-1);
      exit;
    end;
  count(son[d,1],f1-1);
end;

procedure insert(d,f1,x:longint);
var
  i:longint;
begin
  if f1=0 then
  begin
    t[d,2]:=x;
    exit;
  end;
  for i:=1 to t[d,1] do
    if c[son[d,i]]=f[f1] then
    begin
      insert(son[d,i],f1-1,x);
      exit;
    end;
  inc(a1);
  c[a1]:=f[f1];
  inc(t[d,1]);
  son[d,t[d,1]]:=a1;
  insert(a1,f1-1,x);
end;

begin
  assign(input,'cowxor.in');
  assign(output,'cowxor.out');
  reset(input);
  rewrite(output);
  readln(n);
  for i:=1 to n do
  begin
    read(x);
    if i=1
      then a[i]:=x
      else a[i]:=a[i-1] xor x;
  end;
  ans:=-1;
  a1:=1;
  for i:=1 to n do
  begin
    if a[i]>ans then
    begin
      ans:=a[i];
      p:=1;
      q:=i;
    end;
    f1:=0;
    fillchar(f,sizeof(f),0);
    x:=a[i];
    while x>0 do
    begin
      inc(f1);
      f[f1]:=x mod 2;
      x:=x div 2;
    end;
    if i>1 then
    begin
      count(1,21);
      x:=a[s] xor a[i];
      if (x>ans)or(x=ans)and(i<q)or(x=ans)and(i=q)and(s+1>p) then
      begin
        ans:=x;
        p:=s+1;
        q:=i;
      end;
    end;
    insert(1,21,i);
  end;
  writeln(ans,' ',p,' ',q);
  close(input);
  close(output);
end.


 

你可能感兴趣的:(USACO 6.1.3 COWXOR 字典树)