您的位置:首页 > 产品设计 > UI/UE

poj3368 frequent values (快状数组)

2020-02-17 05:08 417 查看


Frequent values
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 15763   Accepted: 5732

Description

You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In addition to that, you are given several queries consisting of indices i and j (1 ≤ i ≤ j ≤ n). For each query, determine the most frequent value among the integers ai , ... , aj.

Input

The input consists of several test cases. Each test case starts with a line containing two integers n and q (1 ≤ n, q ≤ 100000). The next line contains n integers a1 , ... , an (-100000 ≤ ai ≤ 100000, for each i ∈ {1, ..., n}) separated by spaces. You can assume that for each i ∈ {1, ..., n-1}: ai ≤ ai+1. The following q lines contain one query each, consisting of two integers i and j (1 ≤ i ≤ j ≤ n), which indicate the boundary indices for the 
query.

The last test case is followed by a line containing a single 0.

Output

For each query, print one line with one integer: The number of occurrences of the most frequent value within the given range.

Sample Input

10 3
-1 -1 1 1 1 1 3 10 10 10
2 3
1 10
5 10
0

Sample Output

1
4
3


题意 : 给一个由n个元素组成的非严格上升的数组,  q个询问(L,R), 输出位置在L~R的元素重复最多的个数


思路 : 由于是上升序列,所以重复的元素一定是在一起的,显然可以将原数组num
转化g[size],g[t]表示第t个重复元素出现的个数,size表示不同元素的个数。(O(N))

对于每个询问(L,R),首先求出num[L]和num[R]分别属于第几个重复的元素(即对应的g[]下标),方便缩小答案的范围。定义sum[]数组为g[]的前缀和,利用二分查找即可。

找出L,R对应的重复元素的在g[]的次序分别为l,r,考虑到首尾元素可能小于首尾元素重复的个数,就是L,R可能在重复元素的中间,则单独考虑。剩下的就是g[l+1]~g[r-1](注意l==r的情况答案就是R-L+1),也就是问题转化为求g[]在[l+1,r-1]的最大值以及首尾重复的数字个数k1,k2,他们之间的最大值即是答案。静态求数组区间最大值,线段树O(log size)或者平方分割O(sqrt(size))均可;

例如num[] = {-1,-1,1,1,1,1,3,10,10,10},n = 10;可转化为g[]={2,4,1,3},size = 4;sum[]={2,6,7,10};

对于询问(L=2,R=9),num[L]对应g[1],num[R]对应g[4],所以,l=1,r=4;k1 = 1,k2 = 2;而g[]在[2,3]最大为4;

故答案为4,k1,k2中最大值,即ans = 4;


附AC代码之前,向大神们求问此题另一解法是否可行,开始看错题目,没有看到是上升序列,就是{1,2,1,5,3,1,2,3}也是合法的,所以想到了离散化+线段树+莫队算法,先将数组离散化成[1,n]整数,对q个询问区间进行莫队算法,用线段树维护每个数出现的次数,并可logn返回数值区间出现的最多的次数。总觉得这个方法也是可行的,然而不会曼哈顿最小生成树,然后不知道写搓了还是卡了常数,悲伤的TLE了。


poj3368 AC代码,用的平方分割,没有线段树快。

Run ID User Problem Result Memory Time Language Code Length Submit Time
15184614 shnu_boy 3368 Accepted 1084K 1266MS G++ 2063B 2016-02-21 17:29:37

//#include<bits/stdc++.h>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <utility>
using namespace std;

int const maxnum = 0x3f3f3f3f;
int const maxn = 1e5 + 10;
int num[maxn],sum[maxn];
int n,q;

int block,b;//每个block数字个数容量
int s[maxn];//每个block的最大值

void init()
{
//memset(s,0,sizeof(s));
block = (int)ceil(sqrt((double)b));
for(int i = 1 ; i*block <= b ; i ++ )
{
s[i] = -maxnum;
for(int j = (i-1)*block+1 ; j <= block*i ; j ++ )
{
s[i] = s[i] > num[j] ? s[i] : num[j];
}
}
}

int find(int pos)
{
//pos对应的num序数
int high = b,low = 1,mid;
while(low < high)
{
mid = ((high+low)>>1);
if(sum[mid] < pos)low = mid+1;
else if(sum[mid] == pos)high = low = mid;
else high = mid;
}
return low;
}

int Ans(int L,int R)
{
int l=find(L),r=find(R);
if(l == r){
return R-L+1;
}
int f1 = sum[l]-L+1,f2 = R-sum[r-1];
l++;r--;
int ans = f1 > f2 ? f1 : f2;
if(r-l <= block)
{
for(int t = l ; t <= r ; t ++ )
{
if(num[t] > ans)
ans = num[t];
}
}
else
{
f1 = f2 = 0;
for(int t = l ; t <= (l-1)/block*block+block ; t ++ )
{
if(num[t] > f1)
f1 = num[t];
}
for(int t = r ; t >= (r-1)/block*block+1 ; t -- )
{
if(num[t] > f2)
f2 = num[t];
}

if(f2 > f1)f1 = f2;
if(f1 > ans)ans = f1;

for(int t = (l-1)/block+2; t <= (r-1)/block ; t ++ )
{
if(ans < s[t])
ans = s[t];
}
}

return ans;
}

int main()
{
while(cin >> n && n)
{
cin >> q;
b = 0;//block的数量
int k = maxnum;//扫描数字的前一个数字
for(int t = 1 ; t <= n ; t ++ )
{
int g;//扫描的数字
scanf("%d",&g);
if( g - k )
{
b ++;
num[b] = 1;
k = g;
}
else
{
num[b] ++;
}
}

for(int t = 1 ; t <= b ; t ++ )
{
sum[t] = sum[t-1] + num[t];
}

init();

for(int t = 1 ; t <= q ; t ++ )
{
int L,R;
scanf("%d%d",&L,&R);
printf("%d\n",Ans(L,R));
}
}
return 0;
}
  • 点赞
  • 收藏
  • 分享
  • 文章举报
Gach_acmer 发布了1 篇原创文章 · 获赞 0 · 访问量 146 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: