Frequent values
题目链接:https://vjudge.net/problem/POJ-3368
思路
我的代码有两个预处理:第一个init: 将数组中的相等的元素,用首项是1,公差是1的等差数列表示,放在cnt[]中 然后用R[]数组,来表示某个元素所在段的下一段的起点 这个初始化,可以把我代码中的cnt[]和R[]打印出来,一看就能明白
预处理init_st:就是对于cnt这个数组,求区间最大值。处理的时候,有可能L所在段是被切断的,所以第一段可能不完整,但是在一段内cnt[]是一个前缀和,所以可以通过上面R[]定位到下一段的开始,就可以用前缀和高出这一段的元素个数,然后l = R[l]就把l移动到下一段的开始,然后直接查ST表就得出了[l,r]区间cnt[]中的最大值
代码
#include <iostream>
#include <algorithm>
#include <cmath>
#include <stdio.h>
#include <cstring>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 1e5+10;
using namespace std;
int N,Q;
int arr[maxn];
int cnt[maxn],R[maxn];
int st[maxn][30];
inline void read(int &x){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
x = s*w;
}
void init_st(){
for(int i = 1;i<=N;i++) st[i][0] = cnt[i];
int len = log(N)/log(2);
for(int j = 1;j<=len;j++){
for(int i = 1;i<=N-(1<<j)+1;i++){
st[i][j] = max(st[i][j-1],st[i + (1<<(j-1))][j-1]);
}
}
}
void init(){
arr[0] = -2e9;
for(int i = 1;i<=N;i++){
if(arr[i] != arr[i-1]) cnt[i] = 1;
else cnt[i] = cnt[i-1] + 1;
}
int last = N+1;
for(int i = N;i>=1;i--){
R[i] = last;
if(cnt[i] == 1) last = i;
}
}
int main(){
while(scanf("%d",&N)){
if(N == 0) break;read(Q);
for(int i = 1;i<=N;i++) read(arr[i]);
init();
init_st();
while(Q--){
int l,r;read(l),read(r);
int ans = cnt[min(R[l]-1,r)] - cnt[l] + 1;
l = R[l];
if(l<=r){
int len = log(r-l+1)/log(2);
ans = max(ans,max(st[l][len],st[r-(1<<len)+1][len]));
}
printf("%d\n",ans);
}
}
return 0;
}
京公网安备 11010502036488号