CodeForces - 1323D Present(思维+数学)
題目鏈接:點擊查看
題目大意:給出一個數列 a ,求出
?
題目分析:如果暴力的話顯然時間復雜度是 n * n 的,我們應該想辦法去優化,比賽的時候想用線段樹,但是不會在維護異或的前提下區間加法,也想過用矩陣維護,但絲毫沒什么用呀,隊友想到了可以按位維護,也就是維護26個線段樹,我覺得太麻煩了就放棄這個題了,補題的時候看了題解,感覺題解已經說的很明白了,在這里再記錄一下吧,感覺還是自己太菜了,需要多做題長見識
題解的意思是,可以按位維護,因為異或等位運算,最大的特點就是,每一位都可以視為獨立的個體,互不影響,互不干預,這樣我們在單獨處理第 k 位的時候,因為要計算 a[ i ] + a[ j ] 后再進行異或,所以顯然某個數大于??的部分是沒有貢獻的,我們可以先讓每個數對??取模,因為后面我們需要二分查找,所以取模后對于整個數組排一下序,到此為止,所有的 a 數組中的每個元素的取值范圍都是??,顯然 a[ i ] + a[ j ] 的取值范圍是??,不難看出第 k 位為 1 時的 a[ i ] + a[ j ] 的取值范圍為??,這樣我們就可以固定下來 i ,從而二分查找符合條件的 j ,記錄下來有多少對 ( i , j ) 可以對第 k 位做出貢獻,因為 a[ i ] + a[ j ] 的范圍上面已經確定下來了,那么當 a[ i ] 確定時,a[ j ]的范圍也就非常容易確定了:?。如果 k 是奇數的話,那么答案的第 k 位就是 1 ,否則答案的第 k 位就是 0
上面是思路,具體實現的話可以用upper_bound和lower_bound搭配使用,并且注意二分的范圍,如果每次都從[1,n]的范圍二分,會導致答案重復,所以我們可以將范圍控制為[1,i]就好了,i 為枚舉的位置
然后因為上面的取模操作,我懶得再開一個新數組儲存答案了,于是就在原數組上修改,不過這樣的話就需要從最高位開始計算答案了,時間復雜度為 n * logn * logC ,C為1e7,也就是 a[ i ] 的最大值
代碼:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=4e5+100;int a[N];int main() { #ifndef ONLINE_JUDGE // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); #endif // ios::sync_with_stdio(false);int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",a+i);int ans=0;for(int i=26;i>=0;i--){for(int j=1;j<=n;j++)a[j]&=(1<<(i+1))-1;sort(a+1,a+1+n);for(int j=1;j<=n;j++){if((upper_bound(a+1,a+j,(1<<(i+1))-1-a[j])-lower_bound(a+1,a+j,(1<<i)-a[j]))&1)ans^=1<<i;if((upper_bound(a+1,a+j,(1<<(i+2))-2-a[j])-lower_bound(a+1,a+j,(1<<(i+1))+(1<<i)-a[j]))&1)ans^=1<<i;}}printf("%d\n",ans);return 0; }?
總結
以上是生活随笔為你收集整理的CodeForces - 1323D Present(思维+数学)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1323C U
- 下一篇: 中石油训练赛 - 奎奎发红包(贪心)