洛谷 P4168 [Violet]蒲公英 解题报告
P4168 [Violet]蒲公英
題目背景
親愛的哥哥:
你在那個城市里面過得好嗎?
我在家里面最近很開心呢。昨天晚上奶奶給我講了那個叫「絕望」的大壞蛋的故事的說!它把人們的房子和田地搞壞,還有好多小朋友也被它殺掉了。我覺得把那么可怕的怪物召喚出來的那個壞蛋也很壞呢。不過奶奶說他是很難受的時候才做出這樣的事的……
最近村子里長出了一大片一大片的蒲公英。一刮風,這些蒲公英就能飄到好遠的地方了呢。我覺得要是它們能飄到那個城市里面,讓哥哥看看就好了呢!
哥哥你要快點回來哦!
愛你的妹妹 Violet
Azure 讀完這封信之后微笑了一下。
“蒲公英嗎……”
題目描述
在鄉下的小路旁種著許多蒲公英,而我們的問題正是與這些蒲公英有關。
為了簡化起見,我們把所有的蒲公英看成一個長度為n的序列 \((a_1,a_2..a_n)\),其中 \(a_i\)為一個正整數,表示第\(i\)棵蒲公英的種類編號。
而每次詢問一個區間\([l,r]\),你需要回答區間里出現次數最多的是哪種蒲公英,如果有若干種蒲公英出現次數相同,則輸出種類編號最小的那個。
注意,你的算法必須是在線的
輸入輸出格式
輸入格式:
第一行兩個整數 \(n\),\(m\) ,表示有\(n\)株蒲公英,\(m\)次詢問。
接下來一行\(n\)個空格分隔的整數 \(a_i\),表示蒲公英的種類
再接下來\(m\)行每行兩個整數 \(l_0,r_0\),我們令上次詢問的結果為 \(x\)(如果這是第一次詢問, 則 \(x=0\))。
令 \(l=(l_0+x-1)\bmod n + 1,r=(r_0+x-1) \bmod n + 1\),如果 \(l>r\),則交換 \(l,r\) 。
最終的詢問區間為\([l,r]\)。
輸出格式:
輸出m 行。每行一個整數,表示每次詢問的結果。
說明
對于 20% 的數據,保證 \(1\le n,m \le 3000\)。
對于 100% 的數據,保證 \(1\le n \le 40000,1\le m \le 50000,1\le a_i \le 10^9\)。
分塊有時候還是蠻考思維噠?
這是一道經典的在線區間求眾數的問題
設分成大小為\(S\)塊
當詢問區間\([l.r]\)時,我們把區間拆成\([l,L)\),\([L,R]\),\((R,r]\)三個區間
其中\(L,R\)為塊的邊界
答案只可能是 \([L,R]\)的眾數以及在區間\([l,L)\)和區間\((R,r]\)出現的數字
我們對任意兩個塊所包含的大區間維護它的眾數和每個數字的出現個數
后者需要一個長為\(n\)的數組存儲
這樣查詢的時候,我們只需要枚舉邊角的每個數字出現個數就行啦,單次復雜度\(O(S)\)
預處理的話,我們需要枚舉塊的左右邊界以及數字集,復雜度\(O(N*T^2)\)
則總復雜度為\(O(MS+N*T^2)\)
考慮塊大小取多少時達到平衡
當\(MS=N*T^2\)時平衡
\(N ≈ M\)且\(S*T=N\)
所以\(S^2=N^3\)
\(S=N^{\frac{2}{3}}\)
總復雜度為\(O(N^{\frac{5}{3}})\)
如果用vector存+二分找似乎更快
Code:
#include <cstdio> #include <cmath> #include <map> using namespace std; const int N=4e4+10; const int T=40; int n,m,r,a[N],b[N],seg[T][T][N],num[T][T],L[T],R[T],pos[N],buct[N]; std::map <int,int > ma; int query(int l,int r) {int mx=0,ans,ll=pos[l]+1,rr=pos[r]-1;if(ll>rr){for(int i=l;i<=r;i++){++buct[a[i]];if(buct[a[i]]>mx||(buct[a[i]]==mx&&a[i]<ans)){mx=buct[a[i]];ans=a[i];}}for(int i=l;i<=r;i++)buct[a[i]]=0;}else{mx=seg[ll][rr][0],ans=num[ll][rr];for(int i=l;i<L[ll];i++){++buct[a[i]];if(buct[a[i]]+seg[ll][rr][a[i]]>mx||(buct[a[i]]+seg[ll][rr][a[i]]==mx&&a[i]<ans)){mx=buct[a[i]]+seg[ll][rr][a[i]];ans=a[i];}}for(int i=R[rr]+1;i<=r;i++){++buct[a[i]];if(buct[a[i]]+seg[ll][rr][a[i]]>mx||(buct[a[i]]+seg[ll][rr][a[i]]==mx&&a[i]<ans)){mx=buct[a[i]]+seg[ll][rr][a[i]];ans=a[i];}}for(int i=l;i<L[ll];i++)buct[a[i]]=0;for(int i=R[rr]+1;i<=r;i++)buct[a[i]]=0;}return ans; } int main() {scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",a+i),ma[a[i]]=1;for(map <int,int>::iterator it=ma.begin();it!=ma.end();it++)it->second=++r;for(int i=1;i<=n;i++)b[ma[a[i]]]=a[i],a[i]=ma[a[i]];int s=pow(n,0.6666667),t;for(t=1;t*s<=n;t++)L[t]=(t-1)*s+1,R[t]=t*s;if(R[t-1]<n) L[t]=R[t-1]+1,R[t]=n;else --t;for(int i=1;i<=t;i++)for(int j=L[i];j<=R[i];j++)pos[j]=i;for(int i=1;i<=t;i++)for(int j=i;j<=t;j++){for(int k=L[i];k<=R[j];k++){++seg[i][j][a[k]];if(seg[i][j][a[k]]>seg[i][j][0]||(seg[i][j][a[k]]==seg[i][j][0]&&a[k]<num[i][j])){num[i][j]=a[k];seg[i][j][0]=seg[i][j][a[k]];}}}int lastans=0;for(int l,r,i=1;i<=m;i++){scanf("%d%d",&l,&r);l=(l+lastans-1)%n+1,r=(r+lastans-1)%n+1;if(l>r) swap(l,r);printf("%d\n",lastans=b[query(l,r)]);}return 0; }2018.8.27
轉載于:https://www.cnblogs.com/butterflydew/p/9545086.html
總結
以上是生活随笔為你收集整理的洛谷 P4168 [Violet]蒲公英 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “全栈2019”Java第十三章:基本数
- 下一篇: 全球光刻机龙头是怎样炼成的