题意:
给一非递减数组,求区间[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段最左边的位置是1 Right[cnt]=1;//第cnt段最右边的位置是1 d[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); } } } }