2021-2022-1 ACM集训队每月程序设计竞赛F: max or min
Posted yueshehanjiang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-1 ACM集训队每月程序设计竞赛F: max or min相关的知识,希望对你有一定的参考价值。
F: max or min
题意:
给
你
一
个
n
个
数
的
数
组
和
一
个
k
给你一个n个数的数组和一个k
给你一个n个数的数组和一个k
1
<
=
n
,
k
<
=
1
e
5
,
1 <= n , k <= 1e5 ,
1<=n,k<=1e5,
a
1
,
a
2
,
.
.
.
.
.
.
a
n
a1,a2,......an
a1,a2,......an
1
<
=
a
i
<
=
n
1 <= ai <= n
1<=ai<=n
求
一
个
最
长
区
间
[
l
,
r
]
求一个最长区间[l,r]
求一个最长区间[l,r]
满
足
这
个
区
间
的
最
大
值
−
最
小
值
<
=
k
满足这个区间的最大值-最小值<=k
满足这个区间的最大值−最小值<=k
思路:
假
设
当
前
区
间
为
m
i
d
假设当前区间为mid
假设当前区间为mid
如
果
存
在
长
度
为
m
i
d
的
区
间
满
足
最
大
值
−
最
小
值
<
=
k
如果存在长度为mid的区间满足最大值-最小值<=k
如果存在长度为mid的区间满足最大值−最小值<=k
说
明
m
i
d
可
以
变
大
说明mid可以变大
说明mid可以变大
否
则
m
i
d
变
小
否则mid变小
否则mid变小
因
此
考
虑
二
分
查
找
m
i
d
因此考虑二分查找mid
因此考虑二分查找mid
时
间
复
杂
度
l
o
g
n
时间复杂度logn
时间复杂度logn
查
询
区
间
最
大
值
和
最
小
值
可
以
考
虑
查询区间最大值和最小值可以考虑
查询区间最大值和最小值可以考虑
树
状
数
组
/
s
t
表
/
线
段
树
树状数组/st表/线段树
树状数组/st表/线段树
线
段
树
查
询
n
l
o
g
n
总
时
间
复
杂
度
n
l
o
g
n
l
o
g
n
线段树查询nlogn总时间复杂度nlognlogn
线段树查询nlogn总时间复杂度nlognlogn
s
t
表
查
询
o
1
总
时
间
复
杂
度
n
l
o
g
n
st表查询o1总时间复杂度nlogn
st表查询o1总时间复杂度nlogn
树
状
数
组
与
线
段
树
类
似
树状数组与线段树类似
树状数组与线段树类似
其
实
还
有
个
很
妙
的
做
法
其实还有个很妙的做法
其实还有个很妙的做法
s
e
t
+
双
指
针
动
态
维
护
n
l
o
g
n
set+双指针动态维护 nlogn
set+双指针动态维护nlogn
每
次
假
设
i
这
个
下
标
为
区
间
右
端
点
每次假设i这个下标为区间右端点
每次假设i这个下标为区间右端点
找
到
最
大
的
一
个
左
端
点
找到最大的一个左端点
找到最大的一个左端点
同
时
更
新
答
案
同时更新答案
同时更新答案
方
法
一
方法一
方法一
时间复杂度:
线
段
树
+
二
分
O
n
l
o
g
l
o
g
n
线段树+二分Onloglogn
线段树+二分Onloglogn
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200010;
int n , m , k ;
struct Node
{
int l, r;
int v , minv ; // 区间[l, r]中的最大值和最小值
}tr[N * 4];
int a[N];
void pushup(int u) // 由子节点的信息,来计算父节点的信息
{
tr[u].v = max(tr[u<<1].v,tr[u<<1|1].v);
tr[u].minv = min(tr[u<<1].minv,tr[u<<1|1].minv);
}
void build(int u, int l, int r)
{
if(l == r) tr[u] = {l,r,a[r],a[r]};
else
{
tr[u] = {l, r};
int mid = r + l >> 1 ;
build(u << 1 , l , mid ) , build(u << 1 | 1 , mid + 1 , r);
pushup(u);
}
}
int query(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].v ;
int v = -1e9 ;
int mid = tr[u].l + tr[u].r >> 1 ;
if(l <= mid) v = max(v,query(u << 1 , l ,r));
if(r > mid) v = max(v,query(u << 1 | 1 , l , r));
return v ;
}
int query1(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].minv ;
int v = 1e9 ;
int mid = tr[u].l + tr[u].r >> 1 ;
if(l <= mid) v = min(v,query1(u << 1 , l ,r));
if(r > mid) v = min(v,query1(u << 1 | 1 , l , r));
return v ;
}
bool check(int mid)
{
int x = mid ;
for(int i = 1 ; i + x - 1 <= n ; i ++)
{
if(query(1,i,i+x-1) - query1(1,i,i+x-1) <= k) return true ;
}
return false ;
}
int main()
{
cin >> n >> k ;
for(int i = 1 ; i <= n ; i ++) scanf("%d",&a[i]);
build(1,1,n);
int l = 1 , r = n ;
while(l < r)
{
int mid = r + l + 1 >> 1 ;
if(check(mid)) l = mid ;
else r = mid - 1 ;
}
cout << l << "\\n" ;
return 0;
}
方
法
二
方法二
方法二
时间复杂度:
s
e
t
+
双
指
针
O
n
l
o
g
n
set+双指针Onlogn
set+双指针Onlogn
#include <bits/stdc++.h>
#define sz(x) ((int)(x).size())
using namespace std;
const int N = 1e6 + 10 ;
int n , k ;
int a[N] ;
signed main()
{
cin >> n >> k ;
for(int i = 1 ; i <= n ; i ++) scanf("%d",a + i) ;
int res = 0 ;
multiset<int> q ;
for(int i = 1 , j = 1 ; i <= n ; i ++)
{
q.insert(a[i]) ;
while(q.size() && *--q.end() - *q.begin() > k && j <= n)
{
q.erase(q.find(a[j ++])) ;
}
res = max(res,sz(q)) ;
}
cout << res << "\\n" ;
return 0;
}
方
法
三
方法三
方法三
时间复杂度:
s
t
表
+
二
分
O
n
l
o
g
n
st表+二分Onlogn
st表+二分Onlogn
#include<bits/stdc++.h>
using namespace std;
int a[100005],maxn[100005][30],minn[100005][30];
int n,k;
void st_prework(){
for(int i=1;i<=n;i++)maxn[i][0]=minn[i][0]=a[i];
int t=log(n)/log(2)+1;
for(int j=1;j<t;j++)
for以上是关于2021-2022-1 ACM集训队每月程序设计竞赛F: max or min的主要内容,如果未能解决你的问题,请参考以下文章
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解