[UVA 11235] Frequent values

图片加载可能有点慢,请跳过题面先看题解,谢谢
1196604-20171018141342990-586414863.png
1196604-20171018141347115-1334650986.png

可以注意到一点,数列非降,也就是说,对于一个数而言,它存在的范围是一个区间,这样就很好写了
记这几个东西:

  1. \(num[i]\)\(i\) 点的数值离散化后的编号;
  2. \(sum[i]\)\(i\) 点的的数值出现的次数;
  3. \(l[i]\)\(i\) 点的数值出现的最左端;
  4. \(r[i]\)\(i\) 点的数值出现的最右端;

然后这不就是一个 \(RMQ\) 问题嘛。。。
对于一个询问,
如果 \(num[R]=num[L]\),则答案为:\(R-L+1\)
否则答案为:\(max(max(r[L]-L+1,R-l[R]+1),max(sum[k])),k\ \epsilon \ [num[l]+1,num[r]-1]\)
$
$

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define il inline
#define RG register
using namespace std;
il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while( ( ch<'0' || ch>'9' ) && ch!='-' ) ch=getchar();
  if( ch=='-' ) q=-1,ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; }

int n,q,cnt,Log[100010];
int a[100010],l[100010],r[100010];
int sum[100010],num[100010],Max[100010][20];

il void LOG(){ for(int i=1;i<=100000;i++) Log[i]=(int)(log(i)/log(2)); }

il void init(){
   q=gi(),cnt=0,a[0]=200000,a[n+1]=200000;
   for(int i=1;i<=n;i++){ a[i]=gi(); 
      if(a[i]!=a[i-1]) cnt++,sum[cnt]=0;
      num[i]=cnt,sum[cnt]++;
   }
   for(int i=1;i<=n;i++) 
      if(a[i]!=a[i-1]) l[i]=i;
      else l[i]=l[i-1];
   for(int i=n;i;i--) 
      if(a[i]!=a[i+1]) r[i]=i;
      else r[i]=r[i+1];
}

il void pre(){
   for(int i=1;i<=cnt;i++) Max[i][0]=sum[i];
   for(int j=1;j<=Log[cnt];j++)
      for(int i=1;i+(1<<j)<=cnt;i++)
         Max[i][j]=max(Max[i][j-1],Max[i+(1<<j-1)][j-1]);
}

il int RMQ(int l,int r){
   if(l>r) return 0;
   int x=Log[r-l+1]; 
   return max(Max[l][x],Max[r-(1<<x)+1][x]);
}

il void work(){
   pre();
   while(q--){
      int L=gi(),R=gi(),ret=0;
      if(num[L]==num[R]) ret=R-L+1;
      else ret=max(max(r[L]-L+1,R-l[R]+1),RMQ(num[L]+1,num[R]-1));
      printf("%d\n",ret);
   }
}

int main(){ LOG(); while(scanf("%d",&n)&&n){ init(); work(); } return 0; }

转载于:https://www.cnblogs.com/Hero-of-someone/p/7686564.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值