codeforces|CF1054D Changing Array
阿新 • • 發佈:2018-11-10
因為資料範圍是2e5級別的,所以我們考慮用異或字首和來處理區間的異或情況。(比如說a包括b,那麼我們通過異或可以知道b對於a的補區間的資訊)
之後因為對任意\(a_i\)進行取反操作,會改變它和它之後的區間值(原來相等的都不相等了,原來不相等的都相等了),所以結果是我們對原先的字首和直接取反,就可以表示對它進行取反操作之後的字首和了。
因為不管怎麼取反操作,一個位置的字首和只有兩種,那麼我們顯然就可以預處理出所有的值了。
然後我們可以把相同類別的放在一個map裡面。(注意要避免重複,比如說010和101是一類)
之後把ans值\((==n*(n+1)/2)\)減去重複的就可以了。
因為是要求區間異或和不為0,那麼轉化下來的條件就是字首和選取的兩個不相等即可。
我們要求最大的個數,那麼就是同一類的最好均分,用組合數算就行了。(比如說有5個010的話,分成2個010和3個101就行了)
最後注意一下要先給0類加一。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<map> #define MAXN 200010 using namespace std; long long ans; int pre[MAXN]; map<int,int>m; int n,k,x; int main() { scanf("%d%d",&n,&k); m[0]++; for(int i=1;i<=n;i++) { scanf("%d",&x); pre[i]=pre[i-1]^x; pre[i]=min(pre[i],pre[i]^((1<<k)-1)); m[pre[i]]++; } ans=(long long)(n+1)*n/2; for (map<int,int>::iterator it=m.begin();it!=m.end();it++) { long long x=it->second; ans-=(long long)((x/2)-1)*(x/2)/2; ans-=(long long)((x-x/2)-1)*(x-x/2)/2; } printf("%lld\n",ans); }