poj 3368
2016-07-21 18:09
253 查看
Frequent values
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
Sample Output
Source
Ulm Local 2007
题目连接:http://poj.org/problem?id=3368
解法(网上也有其他解法,但是似乎要设好几个数组,感觉挺麻烦也挺难理解的,以下是我的解法)
ac代码
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int a[1000005],b[1000005];
int f[1000005][20];
int q,n,h,t,r,p,y,s,i,j;
void rmq_init() //建立: dp(i,j) = min{dp(i,j-1),dp(i+2^(j-1),j-1) O(nlogn)
{
for(int i=1; i<=n; i++)
f[i][0] = a[i];
int k=floor(log((double)n)/log(2.0)); //C/C++取整函数ceil()大,floor()小
for(int j=1; j<=k; j++)
for(int i=n; i>=1; i--)
{
if(i+(1<<(j-1))<=n) //f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
int rmq(int i,int j) //查询:返回区间[i,j]的最小值 O(1)
{
int k = floor(log((double)(j-i+1))/log(2.0));
return max(f[i][k],f[j-(1<<k)+1][k]);
} //这两部分函数都是st表的套路,不详细说明
int main()
{
while(scanf("%d",&n)!=EOF&&n!=0)
{
scanf("%d",&q);
for(int i=1; i<=n; i++)
scanf("%d",&b[i]); //b【n】存储输入数组
a[1]=1;
for(i=2; i<=n; i++)
{
if(b[i]==b[i-1])
a[i]=a[i-1]+1;
else
a[i]=1;
} //a【n】用记录相同数字出现的次数 例 -1 -1 1 1 2 2 对应1 2 1 2 1 2
rmq_init();
for(int i=1; i<=q; i++)
{
scanf("%d%d",&h,&t);
for(j=h,y=0; j<=t; j++) //现在的问题就在于对它分割数组的位置的讨论,其实只要就是头和尾
{
if(a[j]!=1)
y++; //例如如果h和t截出的数组对应的a是 3 4 1 2 3 1 2
else y记录开头不合适的部分(3、4)y=2
break;
}
if(a[t]-a[h]!=t-h) // 同理要对后尾不合适的部分进行计数 这个情况有点多
{
if(a[t]==1)
{
s=0;
p=rmq(h+y,t-s); //去掉头和尾不合适的数后,就可以通过rmq找到最大值 在拿头尾计数和最大值比较 输出最后的最大值
r=max(p,y);
printf("%d\n",max(r,s));
}
else if(a[t]!=1)
{
if(a[t]+y==t-h+1)
printf("%d\n",max(a[t],y));
else
{
s=a[t];
p=rmq(h+y,t-s);
r=max(p,y);
printf("%d\n",max(r,s));
}
}
}
else
printf("%d\n",t-h+1);
}
}
return 0;
}
Frequent values
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 13771 | Accepted: 5045 |
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
Source
Ulm Local 2007
题目连接:http://poj.org/problem?id=3368
解法(网上也有其他解法,但是似乎要设好几个数组,感觉挺麻烦也挺难理解的,以下是我的解法)
ac代码
#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int a[1000005],b[1000005];
int f[1000005][20];
int q,n,h,t,r,p,y,s,i,j;
void rmq_init() //建立: dp(i,j) = min{dp(i,j-1),dp(i+2^(j-1),j-1) O(nlogn)
{
for(int i=1; i<=n; i++)
f[i][0] = a[i];
int k=floor(log((double)n)/log(2.0)); //C/C++取整函数ceil()大,floor()小
for(int j=1; j<=k; j++)
for(int i=n; i>=1; i--)
{
if(i+(1<<(j-1))<=n) //f(i,j) = min{f(i,j-1),f(i+2^(j-1),j-1)
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
int rmq(int i,int j) //查询:返回区间[i,j]的最小值 O(1)
{
int k = floor(log((double)(j-i+1))/log(2.0));
return max(f[i][k],f[j-(1<<k)+1][k]);
} //这两部分函数都是st表的套路,不详细说明
int main()
{
while(scanf("%d",&n)!=EOF&&n!=0)
{
scanf("%d",&q);
for(int i=1; i<=n; i++)
scanf("%d",&b[i]); //b【n】存储输入数组
a[1]=1;
for(i=2; i<=n; i++)
{
if(b[i]==b[i-1])
a[i]=a[i-1]+1;
else
a[i]=1;
} //a【n】用记录相同数字出现的次数 例 -1 -1 1 1 2 2 对应1 2 1 2 1 2
rmq_init();
for(int i=1; i<=q; i++)
{
scanf("%d%d",&h,&t);
for(j=h,y=0; j<=t; j++) //现在的问题就在于对它分割数组的位置的讨论,其实只要就是头和尾
{
if(a[j]!=1)
y++; //例如如果h和t截出的数组对应的a是 3 4 1 2 3 1 2
else y记录开头不合适的部分(3、4)y=2
break;
}
if(a[t]-a[h]!=t-h) // 同理要对后尾不合适的部分进行计数 这个情况有点多
{
if(a[t]==1)
{
s=0;
p=rmq(h+y,t-s); //去掉头和尾不合适的数后,就可以通过rmq找到最大值 在拿头尾计数和最大值比较 输出最后的最大值
r=max(p,y);
printf("%d\n",max(r,s));
}
else if(a[t]!=1)
{
if(a[t]+y==t-h+1)
printf("%d\n",max(a[t],y));
else
{
s=a[t];
p=rmq(h+y,t-s);
r=max(p,y);
printf("%d\n",max(r,s));
}
}
}
else
printf("%d\n",t-h+1);
}
}
return 0;
}
相关文章推荐
- [Effective JavaScript 笔记]第62条:在异步序列中使用嵌套或命名的回调函数
- opencv腐蚀与膨胀
- PAT乙级1001. 害死人不偿命的(3n+1)猜想 (15) C++
- CodeForces 612A The Text Splitting
- mssql存储过程--动态拼装create
- 1001. 害死人不偿命的(3n+1)猜想
- Android 4.4Eclipse项目中使用RecyclerView
- TOJ 2789.Monthly Expense(二分经典题目)
- [置顶] * **ACM集训day11
- CodeForces 611A New Year and Days
- adb logcat指令参数详解
- 单机PC手动更改windows update 地址
- [Go语言]我的第二个Go语言程序
- 转义
- Error:Unable to start the daemon process: could not reserve enough space for object hea
- java web使用Cookie进行会话管理
- Xcode创建可视化的XML文件(无需写代码)
- Bag of words模型概述
- linux 常用命令 用法总结
- (2)Spring框架