【bzoj4571SCOI2016美味】
4571: [Scoi2016]美味
Time Limit: 30 Sec? Memory Limit: 256 MB
Submit: 656? Solved: 350
[Submit][Status][Discuss]
Description
一家餐廳有 n 道菜,編號 1...n ,大家對第 i 道菜的評價值為 ai(1≤i≤n)。有 m 位顧客,第 i 位顧客的期
望值為 bi,而他的偏好值為 xi 。因此,第 i 位顧客認為第 j 道菜的美味度為 bi XOR (aj+xi),XOR 表示異或
運算。第 i 位顧客希望從這些菜中挑出他認為最美味的菜,即美味值最大的菜,但由于價格等因素,他只能從第?
li 道到第 ri 道中選擇。請你幫助他們找出最美味的菜。
Input
第1行,兩個整數,n,m,表示菜品數和顧客數。
第2行,n個整數,a1,a2,...,an,表示每道菜的評價值。
第3至m+2行,每行4個整數,b,x,l,r,表示該位顧客的期望值,偏好值,和可以選擇菜品區間。
1≤n≤2×10^5,0≤ai,bi,xi<10^5,1≤li≤ri≤n(1≤i≤m);1≤m≤10^5
Output
輸出 m 行,每行 1 個整數,ymax ,表示該位顧客選擇的最美味的菜的美味值。
Sample Input
4 4
1 2 3 4
1 4 1 4
2 3 2 3
3 2 3 3
4 1 2 4
Sample Output
9
7
6
7
?
三步走
●維護xor最大值的話用trie樹可以搞一搞
●維護區間xor最大值可以用可持久化trie樹
●維護區間xor并支持加減的就是可持久化權值線段樹了,這就是本題的算法,用貪心+主席樹實現
?
?
貪心?肯定先確定最高位使得xor后此位為1,由此得到
策略1:從二進制高位向低位貪心,盡量滿足 b的i位與(a[j]+x)的i位不同
?
?
怎么判斷第i位是否可以不同?可以假設(a[j]+x)的i位與b的i位不同,來確定所選的數的第i位,再判定假設是否合法。
合法的條件是什么?記已確定的數為ans,只用查找區間內是否存在數這樣的滿足條件
1.前面位和ans相同
2.此位滿足已確定的數
?
不太容易懂,舉一個例子:
假設b的當前位為1,我們應盡量使a[j]+x當前位為0,前面位確定為ans,ans第i位設定為0,查找區間內是否存在 在[ans,ans+(1<<i)-1]之內的數,如果有,則此位可以為0
?
?
判斷區間的數的個數,權值線段樹
但此時我們注意到查找是雙關鍵字的,一個是區間一個是權值,所以用主席樹來完成操作
總結得出
策略2:用主席樹判斷區間數的存在性問題來確定當前位究竟是什么
?
到了這里,此題也就差不多了,但有幾個細節需要注意
●主席樹空間開夠(我就是這里錯了好久--為什么dev不報RE而是亂搞數組啊!!)
●由于我們查詢的數是a[j]+x,而樹中插入的是a[],所以查詢區間統一減去x并考慮區間是否超界
●最后注意,我們的到的ans是選出來的數,所以輸出時要xor b
?
沒有了-------------------------------------------------------------------
?
?
?
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #define ll long long #define N 200005 #define mx (1<<18)-1 using namespace std; int n,m,a[N],rt[N],ls[N<<5],rs[N<<5],sum[N<<5],sz; void insert(int pre,int &u,int l,int r,int pos){u=++sz;ls[u]=ls[pre];rs[u]=rs[pre];sum[u]=sum[pre]+1;if(l==r)return;int mid=(l+r)>>1;if(pos<=mid)insert(ls[pre],ls[u],l,mid,pos);else insert(rs[pre],rs[u],mid+1,r,pos); }int query(int pre,int u,int l,int r,int L,int R){if(L<=l&&r<=R)return sum[u]-sum[pre];int mid=(l+r)>>1;int t=0;if(L<=mid)t+=query(ls[pre],ls[u],l,mid,L,R);if(R>mid)t+=query(rs[pre],rs[u],mid+1,r,L,R);return t; }int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],0,mx,a[i]);for(int i=1;i<=m;i++){int b,x,l,r;scanf("%d%d%d%d",&b,&x,&l,&r);int ans=0;for(int j=17;j>=0;j--){if(b&(1<<j)){int L=max(ans-x,0),R=ans+(1<<j)-x-1;if(R<0||!query(rt[l-1],rt[r],0,mx,L,R))ans^=(1<<j);}else{ans^=(1<<j);int L=max(ans-x,0),R=ans+(1<<j)-x-1;if(R<0||!query(rt[l-1],rt[r],0,mx,L,R))ans^=(1<<j);}}printf("%d\n",ans^b);}return 0; }?
?
轉載于:https://www.cnblogs.com/wsy01/p/7619807.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的【bzoj4571SCOI2016美味】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【BZOJ】 2463 [中山市选200
- 下一篇: Python 元组遍历排序操作方法