zoukankan      html  css  js  c++  java
  • Code Forces 1030E

    题目大意

    给你n个数,你可以交换一个数的任意二进制位,问你可以选出多少区间经过操作后异或和是0。

    思路分析:

    根据题目,很容易知道,对于每个数,我们可以无视它的1在那些位置,只要关注它有几个1即可,如果它的1的数量可以通过加减为0,那么这个区间就是合法的。

    可以看到,两个数(分别有x,y个1,且x〉y)通过交换位置再进行异或操作,可能获得的新数中1的数量为y-x,y-x+2,y-x+4,...,x+y-2,x+y。

    那么对于每一个左端点(l),它的合法右端点(r)的数量为sum[r]-sum[l-1]为偶数的r的个数(sum为前缀和数组)。同时,这个区间还要满足区间内1的数量最多的数(假设它在第k位)要小于sum[k]-sum[l-1]的一半,因为假如说它不满足这一条件的话,那么就没有足够多的1同它相抵消,也就不会合法。

    那么我们应该如何避免这种状况呢?

    很简单,可能会是不合法右端点的几个点(最多64个)直接暴力做就行了。

    代码:

    var
      a,sum,odd,even:array[0..300000]of longint;
      i,j,s,max,n,m:longint;
      ans,x:int64;
    begin
      read(n);
      for i:=1 to n do
      begin
        read(x);
        while x>0 do
        begin
          a[i]:=a[i]+x and 1;
          x:=x>>1;
        end;
      end;
      for i:=1 to n do
      begin
        sum[i]:=sum[i-1]+a[i];
        odd[i]:=odd[i-1]; even[i]:=even[i-1];
        if sum[i]and 1=1 then inc(odd[i]) else inc(even[i]);
      end;
      for i:=1 to n do
        if sum[i-1]and 1=1 then ans:=ans+odd[n]-odd[i-1]
          else ans:=ans+even[n]-even[i-1];
      writeln(ans);
      for i:=1 to n do
      begin
        if i+64>n then m:=n else m:=i+64;
        s:=0; max:=0;
        for j:=i to m do
        begin
          if a[j]>max then max:=a[j];
          s:=s+a[j];
          if (2*max>s)and(s mod 2=0) then dec(ans);
        end;
      end;
      writeln(ans);
    end.
  • 相关阅读:
    hdu_5791_Two(DP)
    hdu_5783_Divide the Sequence(贪心)
    hdu_5769_Substring(后缀数组)
    hdu_5778_abs(暴力)
    hdu_5776_sum(前缀和维护)
    hdu_5777_domino(贪心)
    [wikioi2069]油画(贪心)
    [bzoj 1503][NOI 2004]郁闷的出纳员(平衡树)
    数据结构练习
    [poj3274]排排站(Hash)
  • 原文地址:https://www.cnblogs.com/WR-Eternity/p/9735488.html
Copyright © 2011-2022 走看看