[CSP-S模拟测试]:array(单调栈)

题目描述

  在放完棋子之后,$dirty$又开始了新的游戏。
  现在他拥有一个长为$n$的数组$A$,他定义第$i$个位置的分值为$i−k+1$,其中$k$需要满足:
  对于任意满足$k\leqslant j\leqslant i$的$j$,有$A[k]\leqslant A[j]\leqslant A[i]$。当对于第$i$个数,有多个$k$满足条件时,取能获得较大分值的$k$。
  现在,$dirty$想要知道$A$数组中分值最大的位置对应的分值为多少。


输入格式

第一行一个整数$n$,表示$A$数组的长度。
第二行$n$个整数,第$i$个数表示$A[i]$的值。


输出格式

输出一行一个整数,表示$A$数组中分值最大的位置对应的分值。


样例

样例输入:

8
8 6 1 7 9 2 3 8

样例输出:

3


数据范围与提示

注意由于$n$的范围较大,本题可能需要使用更快的读入方法。

对于$10\%$的数据,$n\leqslant 10^3$;
对于$40\%$的数据,$n\leqslant 3\times 10^5$;
对于另外$20\%$的数据为随机数据,且$n\leqslant 10^6$;
对于$100\%$的数据,$1\leqslant n\leqslant 10^7$;$1\leqslant A[i]\leqslant 10^9$。


题解

先来解释一下题意,对于区间$[k,i]$,我们只用保证中间的所有元素都大于等于$A[k]$,比小于等于$A[i]$即可,而不用关注其内部大小关系。

分值越大意味着$k$越小。

接下来说一下我考场上的思路,发现对于每一个$i$其最小的$k$位于其前面最后一个比它大的数之间最小的数,也就是如下图$\downarrow$

那么我们可以用单调栈维护第一个比它大的,然后用线段树查询区间最小值的位置即可,然后它就$\downarrow$

这个思路最傻的地方在于为何不用单调栈在维护一个最小值……

时间复杂度:$\Theta(n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

$60\%$算法:

#include<bits/stdc++.h>
#define int int_least32_t
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
const int L=1<<20|1;
char buffer[L],*S,*T;
#define inline  __attribute__((optimize("-O3")))
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
int n;
int a[10000010];
int ans;
int trmin[40000010],pmin[40000010];
int sta[10000010],top;
inline int read(){
	int ss(0);char bb(getchar());
	while(bb<48||bb>57)bb=getchar();
	while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar();
	return ss;
}
inline void pushup(int x)
{
	if(trmin[L(x)]<=trmin[R(x)])
	{
		trmin[x]=trmin[L(x)];
		pmin[x]=pmin[L(x)];
	}
	else
	{
		trmin[x]=trmin[R(x)];
		pmin[x]=pmin[R(x)];
	}
}
inline void build(int x,int l,int r)
{
	if(l==r){trmin[x]=a[l];pmin[x]=l;return;}
	int mid=(l+r)>>1;
	build(L(x),l,mid);
	build(R(x),mid+1,r);
	pushup(x);
}
inline pair<int,int> askmin(int x,int l,int r,int L,int R)
{
	if(r<L||R<l)return make_pair(-0x3f3f3f3f,0x3f3f3f3f);
	if(L<=l&&r<=R)return make_pair(pmin[x],trmin[x]);
	int mid=(l+r)>>1;
	pair<int,int> lft=askmin(L(x),l,mid,L,R);
	pair<int,int> rht=askmin(R(x),mid+1,r,L,R);
	return lft.second<=rht.second?lft:rht;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)a[i]=read();
	a[n+1]=0x3f3f3f3f;
	build(1,1,n+1);
	for(int i=1;i<=n;i++)
	{
		while(top&&a[sta[top]]<=a[i])top--;
		int flag=sta[top]+1;
		sta[++top]=i;
		if(i-flag<ans)continue;
		pair<int,int> minn=askmin(1,1,n+1,flag,i);
		ans=max(ans,i-minn.first+1);
	}
	printf("%d",ans);
	return 0;
}

$100\%$算法:

#include<bits/stdc++.h>
using namespace std;
int n;
int a[10000001],sta[10000001],maxn[10000001];
int ans;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		while(sta[0]&&a[i]<a[sta[sta[0]]])
		{
			if(a[maxn[sta[0]-1]]<=a[maxn[sta[0]]])maxn[sta[0]-1]=maxn[sta[0]];
			ans=max(ans,maxn[sta[0]]-sta[sta[0]]+1);
			maxn[sta[0]--]=0;
		}
		sta[++sta[0]]=i;
		maxn[sta[0]]=i;
	}
	while(sta[0])
	{
		if(a[maxn[sta[0]-1]]<=a[maxn[sta[0]]])maxn[sta[0]-1]=maxn[sta[0]];
		ans=max(ans,maxn[sta[0]]-sta[sta[0]]+1);
		maxn[sta[0]--]=0;
	}
	printf("%d",ans);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11660785.html

时间: 2024-10-20 16:06:30

[CSP-S模拟测试]:array(单调栈)的相关文章

【11.2晚校内测试】【装桶模拟】【单调栈】

真的是fo了,晚上还来一次测试...... mister[问题描述] 不久前 Mister 从太空中探测到一个奇怪的信号,他开始研究这个信号. 经过一些变换后,这个信号变成了长度为 n 的排列或者它的循环移位.对于进一步的研究 Mister 需要一些数据分析,这就是为什么他决定选择这个排列的循环移位,它有最小的可 能偏差.我们把排列的偏差定义为 求一个可能偏差最小的排列 p 的循环移位. 让我们表示 k(0≤k < n)的循环移位排列 p 的变化需要达到这种转变,例如: k = 0: 变成 p1

Educational Codeforces Round 23 D. Imbalanced Array(单调栈)

题目链接:Educational Codeforces Round 23 D. Imbalanced Array 题意: 给你n个数,定义一个区间的不平衡因子为该区间最大值-最小值. 然后问你这n个数所有的区间的不平衡因子和 题解: 对每一个数算贡献,a[i]的贡献为 当a[i]为最大值时的 a[i]*(i-l+1)*(r-i+1) - 当a[i]为最小值时的a[i]*(i-l+1)*(r-i+1). 计算a[i]的l和r时,用单调栈维护.具体看代码,模拟一下就知道了. 然后把所有的贡献加起来.

模拟初级计算器 单调栈实现

题意:求解一串不出现数学公式只含'+','-','*','/', '(' , ')'的计算表达式,输出结果: 其中'/'是带小数的除法.并且输入的数值位double型,若是输入的运算符有误,或者出现除0错误,则直接输出intput error. 输入时除数值之间不能出现空格外,其他地方均能有空格.并且3(...)看成为3*(); 0.5也可以输入为.5; 注意:代码中目前没有加入识别是减号还是符号的处理:所以只能处理非负整数之间的运算: 实现细节:以运算符的优先级来设置一个优先级(数学意义)递减

【BZOJ】3016: [Usaco2012 Nov]Clumsy Cows 贪心 单调栈

Description Bessie the cow is trying to type a balanced string of parentheses into her new laptop, but she is sufficiently clumsy (due to her large hooves) that she keeps mis-typing characters. Please help her by computing the minimum number of chara

csp-s模拟测试50(9.22)「施工(单调栈优化DP)」&#183;「蔬菜(二维莫队???)」&#183;「联盟(树上直径)」

改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调栈 可以想象到最优情况一定是将两端高于中间的一段平原填成一段平的坑,不然如果坑内存在高度差那么我们即使只将一部分抬升也肯定没有用处,并且如果中间的坑已经高于了两端,再向上升也肯定不优,然后就中间的坑可以很很小,也可以很长,对于这个模型我们首先想到n^2*h的DP 设当前表示的f[i]表示当前到了i节

1821 最优集合(单调栈+模拟)

1821 最优集合 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 一个集合S的优美值定义为:最大的x,满足对于任意i∈[1,x],都存在一个S的子集S',使得S'中元素之和为i. 给定n个集合,对于每一次询问,指定一个集合S1和一个集合S2,以及一个数k,要求选择一个S2的子集S3(|S3|<=k),使得S1∪S3的优美值最大. (集合元素可以重复) Input 第一行一个数n,(n<=1000) 接下来n行,每行描述一个集合: 第一个数m,表示集合大小,

Imbalanced Array CodeForces - 817D (思维+单调栈)

You are given an array a consisting of n elements. The imbalance value of some subsegment of this array is the difference between the maximum and minimum element from this segment. The imbalance value of the array is the sum of imbalance valuesof all

[CF442C] Artem and Array (贪心+单调栈优化)

题目链接:http://codeforces.com/problemset/problem/442/C 题目大意:一个数列,有n个元素.你可以做n-2次操作,每次操作去除一个数字,并且得到这个数字两边相邻的数最小的分数.问你最多得到多少分. 将高度绘图,去除V的情况. 用单调栈优化,每个元素进栈一次,出栈一次.线性时间. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include

【单调栈维护连续区间】2019.1.18模拟赛T2 浇花

这道题是一道单调栈的题 1 题目描述 2 JDFZ在餐厅门前种了一排nn棵花,每棵花都有一个高度.浇花大爷会枚举所有的区间,然后从区间中找出一个高度最矮的花进行浇水.由于浇花大爷浇完水之后就精疲力竭了,所以请你帮助他计算每棵花都被浇了几次水. 3 4 输入格式 5 第一行一个整数nn. 第二行nn个整数,分别表示每棵花的高度. 6 7 输出格式 8 一行nn个整数用空格隔开,分别表示每棵花被浇了几次水. 9 10 样例一 11 input 12 3 13 1 3 5 14 output 15 3