1. 程式人生 > >[十二省聯考 2019][堆][可持久化trie樹]異或粽子

[十二省聯考 2019][堆][可持久化trie樹]異或粽子

mes 逆運算 color pst 數據 cal pri read 最小

題意

小粽是一個喜歡吃粽子的好孩子。今天她在家裏自己做起了粽子。

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

小粽的做法是:選兩個整數數l,r

,滿足1<=l<=r<=n,將編號在[l,r]範圍內的所有餡兒混合做成一個粽子,所得的粽子的美味度為這些粽子的屬性值的異或和。(異或就是我們常說的

運算,即 C/C++ 中的 ^ 運算符或 Pascal 中的 xor 運算符)

小粽想品嘗不同口味的粽子,因此它不希望用同樣的餡兒的集合做出一個以上的粽子。

小粽希望她做出的所有粽子的美味度之和最大。請你幫她求出這個值吧!

輸入格式:

第一行兩個正整數 n, k,表示餡兒的數量,以及小粽打算做出的粽子的數量。

接下來一行為 n 個非負整數,第 i 個數為 ai?,表示第 i 個粽子的屬性值。 對於所有的輸入數據都滿足:1?n?5×1e5, 1?k?min?{ n(n−1)2, 2×1e5}, 0?ai?42949672950

輸出格式:

輸出一行一個整數,表示小粽可以做出的粽子的美味度之和的最大值。

內存限制:1024 MB 時間限制:2000 ms

題解:

由異或自為逆運算的性質,求出異或前綴和 l~r異或和為a[r]^a[l-1]

這樣問題就轉化為 求a[0]=0, a[0]~a[n] 中任意兩數前k大異或和之和

類似於超級鋼琴

做法一

我們先固定右端點 r,然後在 [0,r−1]查一個數異或 sumr 最大。這個可以用可持久化 01trie 實現。

我們將 n個數放入堆中,每次取出最大的那個狀態。設這個狀態左端點在 [l,r],與 sumx異或起來最大的位置在 k,那麽我們把狀態的左端點分割成[l,k-1][k+1,r]後放入堆中。

時間復雜度 O(nlog?n)

做法二

註意到這是一個關於三角(ai xor aj,0≤i≤j≤n)的求值,並且有ai xor aj=aj xor ai

所以我們先把答案乘二然後再除回去,這樣我們要求的就是最大的2k個有序對,這個就很好處理了.對角線上的元素並不影響,因為ai xor ai=0是最小的.

可以對每一個i求出第t(初始為1)大的ai xor aj,然後把結果扔到堆裏,每次取堆頂,然後把堆頂對應的i的第t+1大的ai xor aj扔進堆裏.

做法一代碼 註意可持久化trie的邊界問題 因為可能要查找區間[0,r],實際上rt[-1]=0 註意特判

 1 #include<cstdio>
 2 #include<queue>
 3 using namespace std;
 4 const int N=5*1e5+15;
 5 int n,k; long long a[N],ans;
 6 
 7 struct point{int l,r,pos; long long he,val;};
 8 inline bool operator <(const point a,const point b) {return a.val<b.val;}
 9 priority_queue<point> q;
10 
11 int rt[N],cnt;
12 struct tree{int ch[2],pos,sum;}t[N*40];
13 inline void insert(int& now,int las,int pos,long long x)
14  {if(las<0) las=0; else las=rt[las];
15  
16   now=++cnt; int tmp=now; 
17   for(int i=31;i>=0;i--)
18    {t[tmp]=t[las]; t[tmp].sum++;
19     long long cmp=((x>>i)&1);
20     tmp=t[tmp].ch[cmp]=++cnt; las=t[las].ch[cmp];
21    }
22    t[tmp]=t[las]; t[tmp].sum++; t[tmp].pos=pos;
23  }
24  
25 inline int ask(int l,int r,long long x)
26  {
27   if(l==-1) l=0; else l=rt[l];
28   
29   for(int i=31;i>=0;i--)
30   {long long cmp=((x>>i)&1);
31    if(t[t[r].ch[cmp^1]].sum>t[t[l].ch[cmp^1]].sum)
32     {l=t[l].ch[cmp^1],r=t[r].ch[cmp^1];} 
33    else 
34     {l=t[l].ch[cmp],r=t[r].ch[cmp];}
35   }
36   return t[r].pos;    
37  }
38  
39 inline long long read()
40  {long long re=0; char ch=getchar();
41   while(!(0<= ch && ch<=9)) ch=getchar();
42   while(0<= ch && ch<=9) {re=re*10+ch-0; ch=getchar();}
43   return re;
44  } 
45 int main() 
46 {
47  n=read(); k=read();    
48  for(int i=1;i<=n;i++) a[i]=(read()^a[i-1]);    
49  
50  for(int i=0;i<=n;i++) {insert(rt[i],i-1,i,a[i]);}    
51     
52  for(int i=1;i<=n;i++)    
53      {point s;
54       s.l=0; s.r=i-1; s.he=a[i];
55       s.pos=ask(s.l-1,rt[s.r],s.he);
56       s.val=(s.he^a[s.pos]);
57       q.push(s);
58      }
59     
60  while(k--)    
61  {point s,x=q.top(); q.pop(); ans+=x.val;
62   
63   s.l=x.l; s.r=x.pos-1; s.he=x.he;
64   if(s.l<=s.r) 
65     { s.pos=ask(s.l-1,rt[s.r],s.he);
66       s.val=(s.he^a[s.pos]);
67       q.push(s);
68     }
69  
70   s.l=x.pos+1; s.r=x.r; s.he=x.he;
71   if(s.l<=s.r) 
72     { s.pos=ask(s.l-1,rt[s.r],s.he);
73       s.val=(s.he^a[s.pos]);
74       q.push(s);
75     }    
76  }    
77   printf("%lld",ans);    
78     
79 return 0;
80 }

技術分享圖片

[十二省聯考 2019][堆][可持久化trie樹]異或粽子