字首和與字尾和(HDU6186)
阿新 • • 發佈:2018-12-16
題目連結。題目的大意是:給一個數組,和一個數組的下標·,然後在陣列中去掉這個下標對應的元素,把剩下的元素全部做&/|/^這三種位運算,輸出位運算之後的結果。資料範圍1e5.當然暴力是不可行的。
首先需要知道的是:一個數&自己不變,|自己也是不變,^自己是0。這樣我們對於每一種運算維護兩個陣列,一個字首陣列,一個字尾陣列。這樣兩個結合起來可以達到去除任意一箇中間元素的效果。
//我們只證明一種情況,其他的類似。證明&運算時候這種思想的正確性 //設S[i]=a[1]&a[2]....a[i],E[i]=a[i]&a[i-1}...&a[1]. //由於位運算是滿足交換律的,所欲對於任意一個下標k我們假設結果是T,也就是 //T[k]=a[1]&a[2]...a[k-1]a[k+1]...a[n].就是把k去掉這個式子其實等於 //S[k-1]=a[1]$a[2]....a[k-1],E[k+1]=a[k+1]&a[k]&a[k-1]...&a[1] //T[k]=S[k-1]&E[k+1]所以只需要預處理這樣的字首和與字尾和即可
這樣我們就可以給出具體的實現的程式碼:
#include<iostream> #include<vector> #include<cstring> #include<algorithm> const int maxn = 1e5+ 10; int a[maxn]; using namespace std; int sa[maxn], sb[maxn], sc[maxn]; int ea[maxn], eb[maxn], ec[maxn]; int main() { ios::sync_with_stdio(false); int n, q; while (cin >> n >> q) { for (int i = 1; i <= n; i++) { cin >> a[i]; } sa[1] = sb[1] = sc[1] = a[1]; for (int i = 2;i <= n; i++) { sa[i] = sa[i-1] & a[i]; sb[i] = sb[i-1] |a[i]; sc[i] = sc[i-1] ^ a[i]; } ea[n] = eb[n] = ec[n] = a[n]; for(int i=n-1;i>0;i--) { ea[i] = ea[i+1] & a[i]; eb[i] = eb[i+1] | a[i]; ec[i] = ec[i+1] ^ a[i]; } int tem; for (int i = 0; i <q; i++) { cin >> tem; if (tem == 1) cout << ea[tem + 1] << " " << eb[tem + 1] << " " << ec[tem + 1] << endl; else if (tem == n) cout << sa[tem - 1] << " " << sb[tem - 1] << " " << sc[tem - 1] << " " << endl; else cout << (sa[tem - 1] & ea[tem + 1]) << " " << (sb[tem - 1] | eb[tem + 1]) << " " << (sc[tem - 1] ^ ec[tem + 1]) <<endl; } } return 0; }