1. 程式人生 > >UVa 11235 Frequent values (RMQ && 區間出現最多次的數的次數)

UVa 11235 Frequent values (RMQ && 區間出現最多次的數的次數)

升序 req display 最大 這一 屬於 分析 size 原來

題意 : 給出一個長度為 n 的不降序序列,並且給出 q 個形如(L, R)的問詢,問你這個區間出現的最多次的數的次數。

分析 : 很自然的想到將區間“縮小”,例如1 1 2 3 3 3就可以變成2 1 3,構造出“數量數組”,這個數組實際上就是已經將原來區間分了塊,但是問詢的區間不可能就是這些“數量數組”構成的"塊",不過先來想想問詢的區間可不可能包含這裏面的某些"塊"?很顯然是有可能的,那麽從這些"塊"中找出最大值顯然就是經典的RMQ問題,用ST可以預處理並解決,但是對於不是這些"塊"的該怎麽辦呢?還是從這些"塊"入手,首先先給這些"塊"升序編號,對於這些"塊"我們可以知道在原來區間當中其左右端點,比如1 1 2 3 3 3,我們可以分成① ② ③三塊,值分別是1、2、3,第一塊的左端點是原區間的1,右端點是2,同理第二塊左右端點都是3,第三塊左右端點是4和5,這樣做便構成了“數量數組”下標和原數組下標的一個映射,對於問詢(L, R)我們能夠知道L屬於那一塊,那麽這一個塊在(L,R)這個區間內貢獻的相同的值的元素個數就是=>L所在的塊的右端點 - L + 1(這裏記作val_L),對於R也是同理可以得到val_R,那麽最後答案就是 ans = max( RMQ(L和R之間包含的完整的塊), max(val_L, val_R))。不過需要註意的是,如果此時L R同在一個塊中的話,那麽答案就是R-L+1了!

技術分享
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int n, q, arr[maxn], dp[maxn][20];
int cnt[maxn], L[maxn], R[maxn], num[maxn], tot;
inline void RMQ_init()
{
    for(int i=0; i<tot; i++) dp[i][0] = cnt[i];
    for(int j=1; (1<<j)<=tot; j++){
        for(int i=0
; i+(1<<j)-1<n; i++){ dp[i][j] = max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]); } } } int RMQ(int L, int R) { if(L > R) return 0; int k = 0; while((1<<(k+1)) <= R-L+1) k++; return max(dp[L][k], dp[R-(1<<k)+1][k]); } int main(void) {
while(~scanf("%d", &n) && n){ scanf("%d", &q); memset(cnt, 0, sizeof(cnt)); memset(L, 0, sizeof(L)); memset(R, 0, sizeof(R)); tot = 0;///表示"塊"的個數 int Last; for(int i=0; i<n; i++){///接下來對原區間的每一個元素進行映射處理 scanf("%d", &arr[i]); if(i==0){ Last = arr[i];///記錄當前“塊”的具體值 L[tot] = i;///當前“塊”的左端點是i } if(arr[i] == Last){///如果元素還是屬於上一個“塊” cnt[tot]++;///“塊”裏面的元素+1 num[i] = tot;///當前下標i對應了tot這個塊 R[tot] = i;///更新右界 }else{ tot++;///有不同於之前的元素出現了,就相當於出現了新的“塊”給其一個編號 cnt[tot]++;///tot“塊”內元素+1 Last = arr[i]; num[i] = tot; L[tot] = R[tot] = i; } } tot++; RMQ_init();///O(nlogn)的預處理 while(q--){ int Left, Right; scanf("%d %d", &Left, &Right); Left--, Right--; if(num[Left] == num[Right]){///如果同屬一個“塊”,則答案就是R - L + 1 printf("%d\n", Right - Left + 1); continue; }else{ int ans = max(RMQ(num[Left]+1, num[Right]-1), max(R[num[Left]]-Left+1, Right-L[num[Right]]+1)); printf("%d\n", ans); } } } return 0; }
View Code

UVa 11235 Frequent values (RMQ && 區間出現最多次的數的次數)