標籤:span class sum pre 沒有 進位 思路 array 關注
題目大意:
給你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.
Code Forces 1030E