题意:
给一非递减数组,求区间[L,R]中出现次数最多的值所出现的次数。
蓝书P198有详细分析。
题解:
游程编码:(a,b)表示有b个连续的a。
比如-1,1,1,2,2,2,4可以这样表示:
(-1,1),(1,2),(2,3),(4,1)。需要用一些的数组记录!具体看代码注释。
然后求一个区间最大的b就可以了,区间两边需要单独处理。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>using namespace std;const int maxn = 200000+1111;int dmax[maxn][20];
int a[maxn];//原始数据
int Left[maxn],Right[maxn],num[maxn],d[maxn];void initmax(int n,int d[])
{for(int i=1;i<=n;i++)dmax[i][0] = d[i];for(int j=1;(1<<j)<=n;j++)for(int i=1;i+(1<<j)-1<=n;i++)dmax[i][j]=max(dmax[i][j-1],dmax[i+(1<<(j-1))][j-1]);
}int getmax(int l,int r)
{int k=0;while(1<<(k+1)<=r-l+1)k++;return max(dmax[l][k],dmax[r+1-(1<<k)][k]);
}int main()
{int n,q;while(cin>>n&&n){memset(d,0,sizeof d);cin>>q;cin>>a[1];int cnt=1;//不同值的种数Left[cnt]=1;//第cnt段最左边的位置是1Right[cnt]=1;//第cnt段最右边的位置是1d[cnt]=1;//第cnt段有1个元素num[1]=cnt;//第1个元素是属于第cnt段for(int i=2;i<=n;i++){scanf("%d",a+i);if(a[i]==a[i-1])///一段连续的{num[i]=cnt;Right[cnt]=i;d[cnt]++;}else///出现新的{num[i]=++cnt;Right[cnt]=Left[cnt]=i;d[cnt]=1;}}initmax(n,d);while(q--){int l,r;scanf("%d%d",&l,&r);int numl=num[l],numr=num[r];if(numl==numr)printf("%d\n",r-l+1);else{int q = Right[num[l]]-l+1;///左边连续有几个int w = r - Left[num[r]]+1;///右边连续有几个int e=0;if(numr-numl>1)e=getmax(numl+1,numr-1);///中间最多的有多少个int ans=max(e,max(q,w));printf("%d\n",ans);}}}
}