1. 程式人生 > >[UVA](11235)Frequent values ---- RMQ+思維

[UVA](11235)Frequent values ---- RMQ+思維

題目傳送門

做法: 白書上的經典題。說一下自己的理解:

  • 首先,題目中給的是不下降序列,也就是說相同的元素會在某一區間內。
  • 我們把相同的元素歸為一塊,把整個序列分塊!
  • cnt[塊號] 用來記錄塊中相同元素的個數
  • val[塊號] 用來記錄塊中元素的值
  • num[pos] 用來記錄當前的下標所對應的元素屬於哪個塊
  • left[塊號] 用來記錄這一塊的左端點
  • right[塊號] 用來記錄這一塊的右端點
  • 我們可以醬紫轉換這個為題
  • query[l,r] = ans 為一下三個部分的最大值:
  • 1. l與l下標所屬塊的右端點的差值+1
  • 2. r與r下標所屬塊的左端點的差值+1
  • 3.[l+1,r-1] 這段區間內,塊的最大值

AC程式碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define IO          ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x)       push_back(x)
#define sz(x)       (int)(x).size()
#define sc(x)       scanf("%d",&x)
#define abs(x) ((x)<0 ? -(x) : x) #define all(x) x.begin(),x.end() #define mk(x,y) make_pair(x,y) #define fin freopen("in.txt","r",stdin) #define fout freopen("out.txt","w",stdout) using namespace std; typedef long long ll; typedef pair<int,int> PII; const int mod =
1e9+7; const double PI = 4*atan(1.0); const int maxm = 1e6; const int maxn = 1e5+5; const int INF = 0x3f3f3f3f; const ll LINF = 1ll<<62; int mx[maxn][35]; int a[maxn],n,q,block; int cnt[maxn],val[maxn],num[maxn]; int lef[maxn],rgt[maxn]; void init(int ok) { for(int i=1;i<=block;i++) mx[i][0] = cnt[i]; for(int j=1;(1<<j)<=block;j++) { for(int i=1;i+(1<<j)-1<=block;i++) { if(ok) mx[i][j] = max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]); } } } int query(int l,int r) { int k = 0; while(1<<(k+1)<=r-l+1) k++; return max(mx[l][k],mx[r-(1<<k)+1][k]); } int main() { // fin; while(~scanf("%d %d",&n,&q) && n) { block = 1; memset(cnt,0,sizeof(cnt)); memset(val,0,sizeof(val)); sc(a[1]); cnt[block]++; //統計當前塊的元素個數 val[block] = a[1]; //記錄當前塊的元素值 lef[block] = 0; //記錄當前塊的左端點 num[1] = block; //記錄當前位置所屬的塊號 for(int i=2;i<=n;i++) { sc(a[i]); if(a[i] == a[i-1]){ cnt[block]++; num[i] = block; }else{ rgt[block] = i-1; block++; val[block] = a[i]; cnt[block] = 1; lef[block] = i; num[i] = block; } } init(1); while(q--) { int l,r; sc(l);sc(r); if(num[l] == num[r]) printf("%d\n",r-l+1); else{ int ans = -1; if(num[l]+1<=num[r]-1) ans = query(num[l]+1,num[r]-1); ans = max(ans,max(rgt[num[l]]-l+1,r-lef[num[r]]+1)); printf("%d\n",ans); } } } return 0; }