【テンプレート】RMQ
基准时间限制:1 秒 空间限制:131072 KB
收藏
关注
给出一个有N个数的序列,编号0 - N - 1。进行Q次查询,查询编号i至j的所有数中,最大的数是多少。
例如: 1 7 6 3 1。i = 1, j = 3,对应的数为7 6 3,最大的数为7。(该问题也被称为RMQ问题)
Input
第1行:1个数N,表示序列的长度。(2 <= N <= 10000) 第2 - N + 1行:每行1个数,对应序列中的元素。(0 <= S[i] <= 10^9) 第N + 2行:1个数Q,表示查询的数量。(2 <= Q <= 10000) 第N + 3 - N + Q + 2行:每行2个数,对应查询的起始编号i和结束编号j。(0 <= i <= j <= N - 1)
Output
共Q行,对应每一个查询区间的最大值。
Input示例
5 1 7 6 3 1 3 0 1 1 3 3 4
Output示例
7 7 3
模板题(最大):
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int M = 1e5; //n序列长度 //q次询问 int n,q; //s是存放当前点的数值 //log预处理最多跳2的v次方(使得跳2^(v+1)超出范围,跳2^(v-1)次方之后两段的长度不够n) int s[M],log[M]; //f存放区间最大值 int f[M][15]; int main() { //输入数据 scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&s[i]); //预处理log数组(log以2为底i的对数) for(int i=2;i<=n;i++) log[i]=log[i>>1]+1; //自己往右跳一步就是自己 for(int i=1;i<=n;i++) f[i][0]=s[i]; for(int i=1,k=1;i<=log[n];i++,k*=2) {//j+k-1是当前模拟到的左区间的右端点的长度下标 for(int j=1;j+k-1<=n;j++) { f[j][i]=max(f[j][i-1],f[j+k][i-1]); } } //几组数据 scanf("%d",&q); //跳的2的几次方 int len; //左右端点 int a,b; //记录答案 int ans; for(int i=1;i<=q;i++) { scanf("%d%d",&a,&b); a++,b++;//因为题目中数据是从0开始的,而我写的是从1开始的 //+1的原因是因为右端点坐标减去左端点坐标得到的数不是该区间点的个数,可以自己画个图意会一下... len=log[b-a+1]; //减区间分为两段后,在其中找出的最大值就是该区间的最大值 //1<<len就是2^len (减去2^len之后在图上多减去了一个点,将这个点加上,即为第二段的开始起点) ans=max(f[a][len],f[b-(1<<len)+1][len]); printf("%d\n",ans); } return 0; }
-
- 120通过
- 224提交
- 题目提供者ws_ly
- 标签云端
- 难度普及/提高-
- 时空限制1s / 128MB
题目背景
无
题目描述
为了检测生产流水线上总共N件产品的质量,我们首先给每一件产品打一个分数A表示其品质,然后统计前M件产品中质量最差的产品的分值Q[m] = min{A1, A2, ... Am},以及第2至第M + 1件的Q[m + 1], Q[m + 2] ... 最后统计第N - M + 1至第N件的Q[n]。根据Q再做进一步评估。
请你尽快求出Q序列。
输入输出格式
输入格式:
输入共两行。
第一行共两个数N、M,由空格隔开。含义如前述。
第二行共N个数,表示N件产品的质量。
输出格式:
输出共N - M + 1行。
第1至N - M + 1行每行一个数,第i行的数Q[i + M - 1]。含义如前述。
输入输出样例
输入样例#1:
10 4 16 5 6 9 5 13 14 20 8 12
输出样例#1:
5 5 5 5 5 8 8
说明
[数据范围]
30%的数据,N <= 1000
100%的数据,N <= 100000
100%的数据,M <= N, A <= 1 000 000
模板题(最小):
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int M = 1000010; int n,m; int a[M];//保存数 int f[M][21];//f[i][j]表示第i个数向后 2的j次方 个数取得的最小值 int main() { cin>>n>>m; for(int i=1;i<=n;++i) cin>>a[i]; for(int i=1;i<=n;++i) f[i][0]=a[i]; for(int j=1;j<=20;++j) for(int i=1;i<=n;++i) if(i+(1<<j)-1<=n) f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);//RMQ初始化 int i,j; for(int x=1;x<=n-m+1;++x) { i=x,j=x+m-1; int k=log(j-i+1)/log(2); cout<<min(f[i][k],f[j-(1<<k)+1][k])<<endl; } return 0; }
cogs495. 窗口
★☆ 输入文件:window.in
输出文件:window.out
简单对比
时间限制:2 s 内存限制:256 MB
【问题描述】
给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
Window position | Min value | Max value |
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5]3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7 ] | 3 | 7 |
你的任务是找出窗口在各位置时的max value,min value.
输入格式:
- 第一行n,k,第二行为长度为n的数组
输出格式:
- 第一行每个位置的min value,第二行每个位置的max value
样例
- window.in
- 8 3
- 1 3 -1 -3 5 3 6 7
window.out
-1 -3 -3 -3 3 3
3 3 5 5 6 7
数据范围:
- 20%:n≤500; 50%:n≤100000;
- 100%:n≤1000000;
思路:
1)RMQ求最小+最大值
2)单调队列(是真心的不会。。。)
坑点:
写RMQ的时候要预处理到2的20次方,不然会WA
上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int M = 1000010; int n,k,x,y; int a[M];//保存数 int f1[M][21];//f[i][j]表示第i个数向后 2的j次方 个数取得的最小值 int f2[M][21],Maxx[M];//最大值 int main() { freopen("window.in","r",stdin); freopen("window.out","w",stdout); ios::sync_with_stdio(false); cin>>n>>k; for(int i=1;i<=n;++i) cin>>a[i]; for(int i=1;i<=n;++i) f1[i][0]=f2[i][0]=a[i]; for(int j=1;j<=20;++j) for(int i=1;i<=n;++i) if(i+(1<<j)-1<=n) f1[i][j]=min(f1[i][j-1],f1[i+(1<<(j-1))][j-1]),//RMQ初始化 f2[i][j]=max(f2[i][j-1],f2[i+(1<<(j-1))][j-1]); for(int i=1;i<=n-k+1;++i) { x=i,y=i+k-1; int k=log(y-x+1)/log(2); cout<<min(f1[x][k],f1[y-(1<<k)+1][k])<<" "; Maxx[i]=max(f2[x][k],f2[y-(1<<k)+1][k]); } cout<<endl; for(int i=1;i<=n-k+1;++i) cout<<Maxx[i]<<" "; return 0; }
End.