\(\\\)
給出乙個長為 \(n\) 的數列 \(a\) 和 \(k\),多次詢問:
對於乙個區間 \([l_i,r_i]\),問區間內有多少個不為空的子段異或和為 \(k\) 。
\(\\\)
注意到一件有趣的事,就是每次詢問的 \(k\) 相同。
因為 \(a\oplus a=0\),所以子段異或問題可以看作字首異或和的異或,即
\[a[i]\oplus a[i+1]\oplus...\oplus a[j]=sum[i-1]\oplus sum[j]
\]其中 \(sum[i]=a[1]\oplus a[2]\oplus...\oplus a[i]\) 。
那麼問題轉化為,存在對少對 \(i,j\in[l_i-1,r_i],i!=j\) ,滿足
\[sum[i]\oplus sum[j]=k
\]注意區間問題,因為區間做差的原理是減掉 \(l-1\) 。
然後可以注意到,乙個值 \(x\) 若想要構成 \(k\) ,其對應的另乙個值是固定的。
也就是說,我們的組合方案是確定的。
當新加入乙個可選值 \(x\) ,我們的方案數就會 \(+cnt[x^k]\) ,其中 \(cnt[i]\) 表示當前含有可選值 \(i\) 的個數。
可以證明,這種計數方式不會算重,因為每個數字加入時只會計算當前已經有對應的值。
當去掉乙個值的時候,方案數 \(-cnt[x^k]\) 即可。
\(\\\)
還有乙個問題,就是關於 \(k=0\) 的情況。
此時每個值顯然不能計算上自己和自己異或的貢獻。
刪除時當然也要注意不能多減掉自己異或自己的情況。
只需在add
和del
的時候交換一下操作順序即可,具體看**。
\(\\\)
突然失智......debug 2h 竟只是因為 \(l\) 沒有減 \(1\) ......
還要注意,剛開始 \(0\) 號位置也有乙個貢獻。
#include#include#include#include#include#include#include#define n 100010
#define r register
#define gc getchar
using namespace std;
typedef long long ll;
inline ll rd()
while(isdigit(c))
return f?-x:x;
}ll n,m,k,ans,bl[n],cnt[1<<18],s[n],res[n];
struct qq[n];
inline bool cmp1(q x,q y)
while(nowlq[i].r)
res[q[i].id]=ans;
} for(r ll i=1;i<=m;++i) printf("%lld\n",res[i]);
return 0;
}
CQOI2018 異或序列
哈哈哈我竟然秒切了省選題 莫隊 異或。考慮異或的性質,乙個數同時異或兩次等於沒有進行操作。那麼我們設a i 為前i個數的異或和,顯然對於乙個區間 l,now a l 1 oplus a now 就是這個區間裡面所有的數的異或和。如果 a l 1 oplus a now k 那麼ans 這等同於 a ...
CQOI2018 異或序列
已知乙個長度為n的整數數列 a 1,a 2,a n 給定查詢引數l r,問在 a l,a a r 區間內,有多少子串行滿足異或和等於k。也就是說,對於所有的x,y i x y r 能夠滿足 a x bigoplus a bigoplus bigoplus a y k 的x,y有多少組。輸入格式 輸入...
CQOI2018 交錯序列
這個題簡直有毒,o a b 3logn 的做法不卡常只比 o 2 n n 多 10 分 看到 a 和 b 簡直小的可憐,於是可以往矩陣上聯想 發現這個柿子有些特殊,好像可以二項式定理搞一搞 於是 x ay b 可以寫成 n y ay b 於是接下來就二項式定理好了 n y ay b sum a bi...