題目鏈接
題意:
給定一個數列,找出這個數列中長度爲偶數的連續子列的異或和
並且要求長度爲偶數的同時滿足在L到R之間
最後結果mod 1e9+7
題解:
n,L,R<=1e5,所以不能考慮n2暴力了
之前比較經典的就有選任意兩位數異或的總和
那個題可以考慮枚舉二進制位,然後看每一位的貢獻有多少
其實就是每一位有多少種異或後成1的方法
算出來之後乘這一二進制位的權重即可
這道題肯定也是類似,需要對每一二進制位進行分開考慮
然後一步一步分析差別
首先,這道題需要考慮的是一個連續子列
連續子列我們可以維護一個前綴和
如果sum[r] xor sum[l−1]==1說明l−r的貢獻爲1
如果xor爲0,說明這之間的異或也爲0,沒有貢獻
那麼枚舉每個前綴的二進制位
看在某一個二進制位上這個前綴的前面有多少個與他相反的前綴
然後每一二進制位綜合起來乘上權值就可以算出來最後的結果
然後,考慮一下偶數的限制
其實很簡單,兩個奇數或者兩個偶數相減才是偶數
比如前綴下標l是1,r是5,相減是4個,中間有數2,3,4,5
l是2,r是4,相減2個,中間數是3,4
所以對把剛才那個維護個數的數組再加一維,這一維存奇偶數位置
這樣就把偶數的限制解決了
最後解決一下L,R的限制
這樣其實數組不用改變
你只要保證,數組中的個數所對應的位置和當前這個位置是在L到R即可
那麼,其實就是對於每個位置,如果他到和當前位置如果距離剛好是L
就把這個位置作爲貢獻加入,直到往後枚舉如果他和枚舉的位置距離成R的時候
再把他減去,就保證了這個位置和後面的位置形成的區間長度都在L到R之間
這樣一步一步解決完了
只要寫出來代碼就行了
還有一個比較直接的問題,題目沒有限定L,R一定爲偶數
如果區間裏只有奇數,即L==R並且爲奇數那麼結果肯定是0
還有如果L,R爲奇數的時候,但不可能出現奇數,所以往中間減少一下
AC代碼
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int mod=1e9+7;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
ll c[2][2],a[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,l,r;
cin>>n>>l>>r;
if(l==r&&l&1){cout<<0;return 0;}
if(l&1)l++;if(r&1)r--;
for(int i=1;i<=n;i++)cin>>a[i],a[i]^=a[i-1];
ll ans=0;
for(int i=0;i<=31;i++){
memset(c,0,sizeof c);
for(int j=1;j<=n;j++){
if(j>=l)c[j&1][(a[j-l]>>i)&1]++;
ans=(ans+c[j&1][(a[j]>>i)&1^1]*(1ll<<i)%mod)%mod;
if(j>=r)c[j&1][(a[j-r]>>i)&1]--;
}
}
cout<<ans;
return 0;
}