解题思路:简单RMQ,因为序列不递减,所以这题变得十分简单。先从询问开始研究,要找[l,r]内出现最多的次数,其实可以把这个区间内每个数出现的次数压缩成一个数,比如[1,1,3,3,3,5]就压缩成[2,3,1],这样的话就可以在一开始就进行初始化,把每个数压缩成次数,然后记录每个数出现的第一个位置和最后一个位置,压缩的过程需要用到hash,将这个数映射到某个下标,留到后面自有妙用,具体过程见代码。
上面的过程有个问题,如果区间的开始和结束的那个数所在的连续区间被切断,比如1,1,3,3,3,5,然后让我们询问【2,3】,那1被切断了,3被切断了,上面的方法似乎就不靠谱了,怎么办?把前后拿出来单独计算就好,计算时与这个数所在的区间头区间尾比较找出有多少个在询问的区间内就好。然后取区间头、区间中、区间尾的最大值即可ac。
10 7
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
1 2
3 6
7 7
8 10
5 5
1 2 3 4 5
1 1
5 5
1 3
2 4
1 5
#include <stdio.h> #include <string.h> #include <map> #include <math.h> using namespace std; #define MAX 110000 #define max(a,b) (a)>(b)?(a):(b) map<int ,int> mmap; int n,m,arr[MAX],tot,ans; struct node { int v,beg,end,cnt; }brr[MAX*2]; struct RMQ { int dp[MAX][18]; void Create(); int Query(int l,int r); }rmq; void RMQ::Create() { int i,j; for (i = 1; i <= tot; ++i) dp[i][0] = brr[i].cnt; for (j = 1; (1<<j) <= n; ++j) for (i = 1; i + (1<<j) - 1 <= n; ++i) dp[i][j] = max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int RMQ::Query(int l, int r){ int k = (int)(log(r-l+1.0)/log(2.0)); return max(dp[l][k],dp[r-(1<<k)+1][k]); } int GetHash(int x,int in) { //if (x < 0) return x + 100001; //else return x; if (mmap.find(x) == mmap.end()) { mmap[x] = ++tot; brr[tot].v = x; brr[tot].beg = in; brr[tot].cnt = 0; brr[tot-1].end = in - 1; } return mmap[x]; } int main() { int i,j,k,ta,tb,tc,a,b; while (scanf("%d",&n),n) { scanf("%d",&m); tot = 0,mmap.clear(); for (i = 1; i <= n; ++i){ scanf("%d",&arr[i]); k = GetHash(arr[i],i); brr[k].cnt++; } brr[tot].end = n; rmq.Create(); for (i = 1; i <= m; ++i) { scanf("%d%d",&a,&b); if (arr[a] != arr[b]) { j = GetHash(arr[a],i); ta = brr[j].end - a + 1; //获取前面一段的长度,可不进行查询 k = GetHash(arr[b],i); tb = b - brr[k].beg + 1; //获取后面一段的长度,可不进行查询 ans = max(ta, tb); if (brr[j].end + 1 != brr[k].beg) { //中间还有一些区间,必须查询 tc = rmq.Query(j + 1, k - 1); ans = max(tc, ans); } } else ans = b - a + 1; printf("%d\n",ans); } } }
本文ZeroClock原创,但可以转载,因为我们是兄弟。