牛客周賽 Round 12 D 小美的區間異或和

Link

首先這個題目的限制卡的很死,最好是O(n)解決,其次當看到異或的時候,就可以考慮按照二進制位進行計算。

對於這個題,我們定義\(dp_i\)表示以\(a_i\)爲最右端的子區間的答案的和

那麼首先可以想到,貢獻給這個答案的有兩個部分,包括\(a_i\)的和不包括的,其中不包括\(a_i\)的部分的答案就會是
\(dp_{i-1}\),然後對於包括的部分呢?

我們按照每一個二進制位進行計算貢獻,並且統計一下前面有多少次可能的和此位異或後爲1的

然後在把這個數可以提供的次數統計上來繼續向後計算就可以了.

#include<iostream>
#include<cstdio>
using namespace std;
int n;
long long a[200005];
long long ans;
long long dp[200005];
long long cnt[200005][2];
const long long mod=1e9+7;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;++i){
        dp[i]=dp[i-1];
        for(int j=0;j<31;++j){
            int f=(a[i]>>j)&1;
            dp[i]=(dp[i]+cnt[j][1-f]*(1<<j)%mod)%mod;
            cnt[j][f]=(cnt[j][f]+i)%mod;
            //爲什麼這裏會是加i呢?因爲往後計算的時候會有i個最右端是a[k]的區間包括着這裏的a[i]
        }
    }
    for(int i=1;i<=n;++i){
        ans=(ans+dp[i])%mod;
    }
    cout<<ans;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章