1. 程式人生 > >codeforces 1041 E.Vasya and Good Sequences(暴力?)

codeforces 1041 E.Vasya and Good Sequences(暴力?)

nts output following pri sta rom where 通過 other

E. Vasya and Good Sequences time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output

Vasya has a sequence $$$a$$$ consisting of $$$n$$$ integers $$$a_1, a_2, \dots, a_n$$$. Vasya may pefrom the following operation: choose some number from the sequence and swap any pair of bits in its binary representation. For example, Vasya can transform number $$$6$$$ $$$(\dots 00000000110_2)$$$ into $$$3$$$ $$$(\dots 00000000011_2)$$$, $$$12$$$ $$$(\dots 000000001100_2)$$$, $$$1026$$$ $$$(\dots 10000000010_2)$$$ and many others. Vasya can use this operation any (possibly zero) number of times on any number from the sequence.

Vasya names a sequence as good one, if, using operation mentioned above, he can obtain the sequence with bitwise exclusive or of all elements equal to $$$0$$$.

For the given sequence $$$a_1, a_2, \ldots, a_n$$$ Vasya‘d like to calculate number of integer pairs $$$(l, r)$$$ such that $$$1 \le l \le r \le n$$$ and sequence $$$a_l, a_{l + 1}, \dots, a_r$$$ is good.

Input

The first line contains a single integer $$$n$$$ ($$$1 \le n \le 3 \cdot 10^5$$$) — length of the sequence.

The second line contains $$$n$$$ integers $$$a_1, a_2, \dots, a_n$$$ ($$$1 \le a_i \le 10^{18}$$$) — the sequence $$$a$$$.

Output

Print one integer — the number of pairs $$$(l, r)$$$ such that $$$1 \le l \le r \le n$$$ and the sequence $$$a_l, a_{l + 1}, \dots, a_r$$$ is good.

Examples Input
3
6 7 14
Output
2
Input
4
1 2 1 16
Output
4
Note

In the first example pairs $$$(2, 3)$$$ and $$$(1, 3)$$$ are valid. Pair $$$(2, 3)$$$ is valid since $$$a_2 = 7 \rightarrow 11$$$, $$$a_3 = 14 \rightarrow 11$$$ and $$$11 \oplus 11 = 0$$$, where $$$\oplus$$$ — bitwise exclusive or. Pair $$$(1, 3)$$$ is valid since $$$a_1 = 6 \rightarrow 3$$$, $$$a_2 = 7 \rightarrow 13$$$, $$$a_3 = 14 \rightarrow 14$$$ and $$$3 \oplus 13 \oplus 14 = 0$$$.

In the second example pairs $$$(1, 2)$$$, $$$(2, 3)$$$, $$$(3, 4)$$$ and $$$(1, 4)$$$ are valid.

題意 對於任何一個$$$a_i$$$,可以將其表示為$$$2$$$進制並任意更改它裏面1的位置。對於區間[l,r],如果對其中一些數執行任意次這樣的操作,從而使得區間的異或和為0,就稱這段區間是good。給$$$n$$$個數,$$$1\le a_i\le 10^{18}$$$,求有多少個子區間是good。 分析 異或和只與二進制中$$$1$$$的個數有關,所以用$$$b_i$$$記錄$$$(a_i)_2$$$中的$$$1$$$的個數,形成一個新的數組$$$b[n]$$$,之後就不再考慮數組$$$a[n]$$$了。
為了方便敘述,用$$$x\oplus y$$$表示對$$$x,y$$$進行任意調整後,可能的異或值的集合。容易發現兩個數的情況($$$x\lt y$$$),結果是一個公差為2的等差序列: $$$$$$ \begin{align} x\oplus y=\{|y-x|,\ |y-x|+2,\ ...,\ x+y \} \end{align} $$$$$$ 三個數的情況($$$x\lt y\lt z$$$),結果也是公差為2的等差序列: $$$$$$ \begin{align} x\oplus y\oplus z=\{min\{|z-t|,\ t\in x\oplus y\},\ ...,\ x+y+z \} \end{align} $$$$$$ 分析可以發現,區間可能的異或值的範圍,上限是區間和,下限是一個小於最大元素的數,要判斷異或值能否為0,最暴力的方法,就是把$$$min\{...\}$$$裏面遍歷一遍,看0是不是在其中,而這需要很大的代價。
有一個更好的解決辦法,註意到上限是一個很容易維護的值,而下限一定小於區間的最大元素,假設$$$[l,r]$$$內最大和第二大的數分別為$$$b_i,\ b_j$$$,把$$$b_i$$$單獨拿出來,剩下的數形成新的區間,那麽新區間的上限就是的新的區間和,下限就是一個小於$$$b_j$$$的數,所以下限一定小於$$$b_i$$$。要讓原區間下限為0,就轉而去判斷新區間對應的等差序列中有沒有$$$b_i$$$,因為如果有,就可以抵消掉,從而原區間的下限就是0。具體的來說,$$$b_i$$$要在其中,要滿足兩個條件:
【1】上限大於或等於$$$b_i$$$;
【2】$$$b_i$$$與上限同奇偶;
這樣一來,通過上限就能確定區間是否為good,完全避免了對下限的考慮了。但是單獨把$$$b_i$$$提出來還是很麻煩,不如把條件轉化為對整個區間的限制:
【1】區間和大於或等於最大元素的兩倍;
【2】區間和是偶數;
還有一個性質,$$$b_i$$$的範圍是1~63,也就意味著,只要區間的長度不小於64,區間和≥63+$$$b_i$$$≥$$$2b_i$$$,就一定滿足條件【1】,所以只用考慮所有長度小於64的區間,於是問題的規模就縮小到了64n,就變成了一個使勁碼就能做出來的題了。
一種比較好的寫法是,先算求和為偶數的區間的總個數,再遍歷所有長度小於64且和為偶數的區間,從總個數中去掉不滿足條件的,剩下的個數就是答案。 總結 分析問題眼光還是不夠敏銳啊。結合了官方題解+拜讀大佬的代碼,整理出這樣一個還算完整的思路,花了一晚上。什麽時候才能在比賽中,獨立做出這樣的題呢。 代碼
#include<stdio.h>
typedef long long LL;
int cnt(LL x) {
    int res = 0;
    while (x)res += x & 1, x >>=1;
    return res;
}
int b[300005]={0},fre[300005]; 
LL ai;
int cnt0 = 0, cnt1 = 0;
int main(){
    int n;
    scanf("%d", &n);
    for(int i=1;i<=n;++i)    {
        scanf("%I64d", &ai); b[i] = cnt(ai); fre[i] = fre[i - 1] + b[i];
        if (fre[i] & 1)cnt1++;
        else cnt0++;
    }
    /*求和為偶數的區間個數:
     *
     *對於前綴和為奇數的[0,l1], [0,l2], ..., [0,lcnt1]
     * 對l1而言,它和後面的組合起來,[l1+1,l2], [l1+1,l3], ..., [l1+1,lcnt1]的和一定全都是偶數
     * l2~lcnt1也同理,共cnt1-1+cnt1-2+...1=cnt1(cnt1-1)/2個
     * 
     * 對於和為偶數的區間[0,r1], [0, r2], ..., [0,rcnt0]
     * 
     * 不僅和奇數的相同,每個區間本身也要加入計數
     * 所以共cnt0+cnt0-1+...+1=(cnt0+1)cnt0/2個
     */
    LL ans = 1LL * cnt1*(cnt1 - 1) / 2+1LL*cnt0*(cnt0+1)/2;

    //遍歷所有以i為起點的區間
    for(int i=1;i<=n;++i)    {
        int maxn = 0,sum;
        //只檢查到長度為64
        for(int j=0;j<=64&&i+j<=n;++j){
            if (maxn < b[i + j])maxn = b[i + j];
            sum = fre[i + j] - fre[i - 1];
            if ((sum & 1) == 0 && (maxn<<1) > sum)ans--;
        }
    }
    printf("%I64d", ans);
}

codeforces 1041 E.Vasya and Good Sequences(暴力?)