title: 蓝桥模拟_第十题_晚会节目单
categories:
频繁的查询区间最值对于遍历来说开销非常大,所以产生了一种区间最值查询这种算法,本文只讲ST+RMQ,ST是稀疏矩阵的意思,这种方法要求数据必须是静态的不能变化的。
有一个一位数组(长度为n),频繁的查询[s,e]区间的最值。
定义一个二维数组ST(大小[n,lgn])。ST[i][j]
表示的是从i开始(包括i)向后2j个元素区间的最值,即区间[i,i+2j-1]的最值,那么很明显ST[i][0]=a[i]
(因为[i,i]只有一个值)。现在我们开始推导递推式,[i,i+2j-1]可以按照中间分为两个大小为2(j-1)的区间[i,i+2(j-1)-1]和[i+2(j-1),i+2j-1],那么[i,i+2j-1]的最值为这两个区间再求最值,即[i,i+2j-1]=min/max([i,i+2(j-1)-1],[i+2(j-1),i+2j-1])也就是:
ST[i][j]=min/max(ST[i][j-1],ST[i+2^j][j-1])
那么就可以发现第j列某个元素值的计算只跟它前一列的某两个值有关,并且刚刚我们已经算好了第一列,由第一列可以计算第二列,由第二列可以计算第三列……那么要算到哪一列呢?ST[i][j]
表示的区间是[i,i+2j-1]很明显i+2j-1<=n-1(n个元素,下标0~n-1)所以就有了建ST的模板:
void cal(int a[],int n)
{
for(int i=0;i<=n-1;i++)
ST[i][0]=a[i];
for(int j=1;(1<<(j))<=n;j++)
{
for(int i=0;i+(1<
说了半天有了这个表该怎么用呢?假如我们要计算区间[s,e]的最值该怎么算呢?我们能够利用的是ST[此处可为任意数][此处必须为2的幂]
如果我们能够找到一个k,使得区间[s,e]变成[s,s+2k-1]和`[s+2^k][e]`,我们就可以利用表了,但是你会发现第二个区间没法表示,我们只能表示长度为2的幂的区间。于是聪明人就会发现用e减去2的幂不就行了!于是将[s,e]变成[s,s+2k-1]和[e-2^k+1,e],这样区间[s][e]
的最值就可以变为min/max(ST[s][k],ST[e-2^K+1][e])
但是可能有人又会提出疑问了,如果这两个集合没有交集怎么办?比如[2,6]分为[2,3]和[5,6] (k=1),这样得到话明显不对啊!所以我们需要找一个比较大的k值,[s,s+2k-1]必须包含在`[s][e]`里面,也就是s+2k-1<=e 解得
k < = l o g 2 ( e − s + 1 ) , 令 k = l o g 2 ( e − s + 1 ) k<=log_2(e-s+1),令k=log_2(e-s+1) k<=log2(e−s+1),令k=log2(e−s+1)
并且(int)k去除了k的小数部分,也就是说0<=k-(int)k<1,所以k-1<(int)k<=k,代入原式:
2 k − 1 − 1 < 2 ( i n t ) k − 1 < = 2 k − 1 将 k = l o g 2 ( e − s + 1 ) 代 入 得 2^{k-1}-1<2^{(int)k}-1<=2^k-1将k=log_2(e-s+1)代入得 2k−1−1<2(int)k−1<=2k−1将k=log2(e−s+1)代入得
( e − s ) / 2 − 1 / 2 < 2 ( i n t ) k − 1 , 此 处 2 ( i n t ) k − 1 是 整 数 , 所 以 ( e − s ) / 2 = < 2 ( i n t ) k − 1 (e-s)/2-1/2<2^{(int)k}-1,此处2^{(int)k}-1是整数,所以(e-s)/2=<2^{(int)k}-1 (e−s)/2−1/2<2(int)k−1,此处2(int)k−1是整数,所以(e−s)/2=<2(int)k−1
所 以 s + 2 ( i n t ) k − 1 > = s + ( e − s ) / 2 = ( e + s ) / 2 ( 中 点 ) 且 e − 2 k + 1 < = e − ( e + s ) / 2 = ( e + s ) / 2 ( 中 点 ) 所以s+2^{(int)k}-1>=s+(e-s)/2=(e+s)/2(中点)且e-2^k+1<=e-(e+s)/2=(e+s)/2(中点) 所以s+2(int)k−1>=s+(e−s)/2=(e+s)/2(中点)且e−2k+1<=e−(e+s)/2=(e+s)/2(中点)
所以当k=(int)(log2(e-s+1))时,ST[s][k],ST[e-2^K+1][e]
表示的区间一定有交集。所以要求[s,e]区间最值只需要计算min/max(ST[s][k],ST[e-2^K+1][e]),k=(int)(log2(e-s+1))
小明要组织一台晚会,总共准备了 n 个节目。然后晚会的时间有限,他只能最终选择其中的 m 个节目。
这 n 个节目是按照小明设想的顺序给定的,顺序不能改变。
小明发现,观众对于晚会的喜欢程度与前几个节目的好看程度有非常大的关系,他希望选出的第一个节目尽可能好看,在此前提下希望第二个节目尽可能好看,依次类推。
小明给每个节目定义了一个好看值,请你帮助小明选择出 m 个节目,满足他的要求。
输入的第一行包含两个整数 n, m ,表示节目的数量和要选择的数量。
第二行包含 n 个整数,依次为每个节目的好看值。
输出一行包含 m 个整数,为选出的节目的好看值。
5 3
3 1 2 5 4
3 5 4
选择了第1, 4, 5个节目。
对于 30% 的评测用例,1 <= n <= 20;
对于 60% 的评测用例,1 <= n <= 100;
对于所有评测用例,1 <= n <= 100000,0 <= 节目的好看值 <= 100000。
ST+RMQ
#include
#include
#include
#include
#include
#include
#define PP(a,b) cout<>n>>m;
_for(i,0,n-1)
{
cin>>a[i];
st[i][0]=a[i];
}
cal(a,n);
int s=0,k=m;
while(k!=0)
{
int z=query(s,n-1-k+1);
cout<