[BZOJ4260] Codechef REBXOR (01字典樹,異或前綴和)
阿新 • • 發佈:2018-06-29
AC href chef 其中 復雜度 ons 包含 end DC
不過這題需要註意以下空間不能開太大。
Description
Input
輸入數據的第一行包含一個整數N,表示數組中的元素個數。
第二行包含N個整數A1,A2,…,AN。
Output
輸出一行包含給定表達式可能的最大值。
Sample Input
5
1 2 3 1 2
Sample Output
6
HINT
滿足條件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。
對於100%的數據,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。
Source
By yts1999
Solution
這道題,似乎也是套路題啊,只不過多了那麽一點點思路。
考慮幾點:
- 我們所選的區間不能相交。
- 顯而易見的貪心,我們所選的區間必須是區域內異或和最大的。
於是我們考慮用 01字典樹 來求解。
我們可以很方便地處理出在一段區間內最大異或和的區間。
直接記錄一遍異或前綴和,然後一個一個插入並查詢即可。
但是由於不能選相交的區間,我們不能考慮直接選兩個最大的區間。
可以考慮用一個數組:
\[f[maxn]\]
用於儲存前 ( 1 , i ) 區間的異或最大值。
那麽我們記錄完之後,直接從後面再開始一遍選最大區間。
我們從 n枚舉到 1;
\[Ans=\max_{i=1}^n(Ans,f[i-1]+query(sub[i]))\]
其中sub 數組表示 n 到 i 異或後綴和。
如以上求解即可,時間復雜度 O(2*nlogn)。
代碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=400008;
int c[maxn],f[maxn];
int n,m,pre[maxn],sub[maxn];
int ch[32*maxn][2];
int val[32*maxn];
int num[32*maxn];
int sz,ans=-1;
void init()
{
memset(ch[0],0,sizeof(ch[0]));
sz=1;
}
void insert(int a)
{
int u=0;
for(int i=32;i>=0;i--)
{
int c=((a>>i)&1);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
num[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
num[u]++;
}
val[u]=a;
return;
}
int query(int x)
{
int u=0;
for(int i=32;i>=0;i--)
{
int c=((x>>i)&1);
if(ch[u][c^1]&&num[ch[u][c^1]])
u=ch[u][c^1];
else u=ch[u][c];
}
return x^val[u];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&c[i]);
for(int i=1;i<=n;i++)
pre[i]=pre[i-1]^c[i];
for(int i=n;i>0;i--)
sub[i]=sub[i+1]^c[i];
for(int i=1;i<=n;i++)
f[i]=max(f[i-1],query(pre[i])),
insert(pre[i]);
init(); insert(sub[n+1]);
for(int i=n;i>0;i--)
ans=max(ans,query(sub[i])+f[i-1]),
insert(sub[i]);
cout<<ans<<endl;
return 0;
}
[BZOJ4260] Codechef REBXOR (01字典樹,異或前綴和)