洛谷P5283 & LOJ3048:[十二省聯考2019]異或糉子——題解 BZOJ3261:最大異或和 BZOJ2006:[NOI2010]超級鋼琴

https://www.luogu.org/problemnew/show/P5283html

https://loj.ac/problem/3048node

小糉是一個喜歡吃糉子的好孩子。今天她在家裏本身作起了糉子。ios

小糉面前有 種互不相同的糉子餡兒,小糉將它們擺放爲了一排,並從左至右編號爲 1 到 n。第 ii 種餡兒具備一個非負整數的屬性值 a_i。每種餡兒的數量都足夠多,即小糉不會由於缺乏原料而作不出想要的糉子。小糉準備用這些餡兒來作出 k 個糉子。git

小糉的作法是:選兩個整數數 lr,知足 1lrn,將編號在 [l,r] 範圍內的全部餡兒混合作成一個糉子,所得的糉子的美味度爲這些糉子的屬性值的異或和。(異或就是咱們常說的 xor 運算,即 C/C++ 中的 ˆ 運算符或 Pascal 中的 xor 運算符)post

小糉想品嚐不一樣口味的糉子,所以它不但願用一樣的餡兒的集合作出一個以上的 糉子。url

小糉但願她作出的全部糉子的美味度之和最大。請你幫她求出這個值吧!spa

UPD:手癢了因而仍是把代碼寫了……code

不要在乎我只是忽然詐了一個屍。htm

以及場外選手題解口胡以後看了一下正解發現差很少?blog

正好一直想要詐一個屍,就用這個詐一個屍吧。

順(主)便(要)聊聊心路歷程。

——————

看到異或取最大第一眼想到線性基,而後看到連續的數就想到了BZOJ3261:最大異或和 。(天哪我記性真好一年前的東西我還記得)

然而此時並看不出兩者的關係。

而後想暴力,枚舉$O(n^2)$,但$k$與$n$並不是一個數量級的。

因而想到了BZOJ2006:[NOI2010]超級鋼琴 對前$k$大值的處理方法。(天哪我記性真好一年前的東西我還記得*2)

而超級鋼琴那道題咱們是用了st表維護的,可是異或顯然不能用st表維護。

那就可持久化trie唄!瓜熟蒂落的聯繫到了一塊兒。

因而題解以下:首先預處理前綴異或和$s$,創建可持久化trie,則原$[l,r]$的異或和即爲$s[r] \; xor \; s[l-1]$。

因而固定$l$求$r$使得$s[r] \; xor \; s[l-1]$儘量的最大(設爲$w$吧),而後將這些信息一塊兒扔到堆裏面(同時咱們把$r$所在的範圍$L,R$一塊兒扔裏面)。

每次彈出一個$(l,r,w,L,R)$的時候,咱們就要找第二大的$[l,r]$扔進去,超級鋼琴告訴咱們,第二大的$r$必定在$[L,r-1]$和$[r+1,R]$當中,咱們乾脆把區間分紅兩份各求一遍直接都扔進去就行了。

複雜度一個建trie$O(nloga_i)$一個預處理$O(nloga_i)$一個彈$O(kloga_i)$。

(老年選手不會算複雜度了不知道對不對orz)

另外洛谷須要開O2

 

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
typedef long long ll;
const int N=5e5+5;
const int B=33;
inline ll read(){
    ll X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int son[2],sum,num;
}tr[50*N];
int tot,rt[N],pool;
ll s[N];
void insert(int y,int &x,ll k,int pos,int now){
    tr[x=++pool]=tr[y];tr[x].sum++;
    if(now<0){tr[x].num=pos;return;}
    bool p=k&(1LL<<now);
    insert(tr[y].son[p],tr[x].son[p],k,pos,now-1);
    return;
}
int query(int nl,int nr,ll k,int now){
    if(now<0)return tr[nr].num;
    bool p=k&(1LL<<now);
    int delta=tr[tr[nr].son[p^1]].sum-tr[tr[nl].son[p^1]].sum;
    if(delta>0)return query(tr[nl].son[p^1],tr[nr].son[p^1],k,now-1);
    else return query(tr[nl].son[p],tr[nr].son[p],k,now-1);
}
struct data{
    int l,r;
    ll w;
    int L,R;
    bool operator <(data b)const{
        return w<b.w;
    }
};
priority_queue<data>q;
int main(){
    int n=read(),k=read();
    for(int i=1;i<=n;i++)s[i]=s[i-1]^read();
    for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],s[i],i,B);
    for(int i=1;i<=n;i++){
        int l=i;int r=query(rt[l-1],rt[n],s[l-1],B);
        q.push((data){l,r,s[r]^s[l-1],l,n});
    }
    ll ans=0;
    while(k--){
        data tmp=q.top();q.pop();
        ans+=tmp.w;
        int i=tmp.l,j=tmp.r;
        if(tmp.L<=j-1){
            int t=query(rt[tmp.L-1],rt[j-1],s[i-1],B);
            q.push((data){i,t,s[t]^s[i-1],tmp.L,j-1});
        }
        if(j+1<=tmp.R){
            int t=query(rt[j],rt[tmp.R],s[i-1],B);
            q.push((data){i,t,s[t]^s[i-1],j+1,tmp.R});
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

+++++++++++++++++++++++++++++++++++++++++++

 +本文做者:luyouqi233。               +

 +歡迎訪問個人博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

相關文章
相關標籤/搜索