首页 > 其他分享 >Blocks(单调栈)

Blocks(单调栈)

时间:2024-02-22 11:25:06浏览次数:34  
标签:Blocks int sum stk 区间 top 单调

题目链接

  • 因为可以操作无限次,所以相当于只要一个区间中的所有数相加的平均值大于k即成立
  • 首先,我们需要通过前缀和维护,可以在加的时候减去一个k,这样只用判断\(i>j且sum[i]-sum[j]>0\)则在[j+1,i]区间中存在满足题目的连续序列

image

  • 如图用红线指的是存入的<0并且单调递减的前缀和sum,以确定左区间,注意,第一个数要存0即top=1时stack[1]=0以便如果出现图中这种情况ans=n-0为最大值;

  • 如图蓝线为右n边界与左边界匹配过程,我们要从n开始倒序循环,以求ans做大值

  • 需要注意的是,在找左区间及单调递减区间的过程中,如果出现\(sum[i]==sum[j]且i<j\)那么我们取左边的,因为这样与右区间匹配时才尽可能大

    AC代码
    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    const int N=1000005;
    int n,m,a[N],p,sum[N],stk[N];
    int get(int k)
    {
    //	stack <int> stk;
    	memset(stk,0,sizeof(stk));
    	int top=1;
    	int ans=0;
    	for(int i=1;i<=n;i++)
    	{
    	sum[i]=sum[i-1]+a[i]-k;
    	if(sum[i]<sum[stk[top]])stk[++top]=i;//cout<<i<<endl;
    	}
    	int num=0,len=0,c=0;
    	for(int i=n;i>=1;i--)
    	{
    		while(top&&sum[stk[top]]<=sum[i])
    		{
    			c=stk[top];
    			top--;
    			//stk.pop();
    		}
    		if(sum[c]<=sum[i])ans=max(ans,abs(i-c));
    	}
    	return ans;
    }
    signed main()
    {
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    	int k;
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%lld",&k);
    		memset(sum,0,sizeof(sum));
    		cout<<get(k)<<" ";
    	}
    	return 0;
    }
    /*
    10 5
    10 1 2 4 5 2 6 9 3 1
    5 6 7
    */
    

标签:Blocks,int,sum,stk,区间,top,单调
From: https://www.cnblogs.com/wlesq/p/18026863

相关文章

  • blocks 单调栈、单调队列题解
    blocks题解:1、题面:2、分析:题意大概就是说,找一段最长的区间,并且这段区间的平均值>=k,那么我们可以对他的每一个值减去k,最终求和>=0即可。那我们需要对每个可能的左端点和右端点进行考虑,并以此让他们进行配对,看他们之间的区间和是否非负。那么我们先定住一个右端点,再依次考虑......
  • Blocks—单调栈
    思路:题目意思是求平均数>=k的最长序列先求出a[i]-k的前缀和就是求sum[i]-sum[j]>=0的最大i-j当j<=k<=isum[j]<=sum[k]j<=k<=isum[j]<=sum[k]更新i的时候,k就不如j优所以处理出来一个单调上升的数组(stak),那答案就在里面选倒序更新,单调栈一直减减就好因为如果用stak[top]更新了i,因......
  • [洛谷P3503][POI2010][BZOI2086]Blocks
    先看数据范围,n≤1e7,k≤1e9,暴力显然行不通,只能考虑单调栈;首先题目中说每一个数都要大于k,那么我们可以在初始化时就将每一个数都减去k,将问题转化为从正数中取出数加到负数里;然后维护一个前缀和,来判断一个区间是否符合要求;显然,当sum[j]-sum[i]≥0时,区间[i+1,j]符合题意,......
  • Blocks(单调栈)
    题干中说每次选择一个大于k的数,还要选他左右两个数其中之一加上一,最后问你最长的每个数不小于K的子序列。这些都是障眼法,其实就是问你最长的平均值大于或等于K的最长子序列,这样就明朗了。接下来就是找子序列的问题,因为要求的是区间最大平均值,所以不能再以单个数的值为依据来决......
  • [BZOJ1047][HAOI2007][AcWing1091]理想的正方形(单调队列)
    此题的数据相当大,暴力的显然过不了,即使是O(abn)的算法也会超时,所以只能考虑O(ablogn)或O(ab)的算法。50分暴力#include<bits/stdc++.h>usingnamespacestd;intn,a,b,m[1001][1001];intdx(intx,inty){ intmaxn=0,minn=0x7fffffff; for(inti=x;i<=x+n-1;++i){ for(in......
  • 单调队列、单调栈
    单调栈什么是单调栈单调栈是指一个栈内部的元素具有严格单调性的一种数据结构,分为单调递增栈和单调递减栈。单调栈的性质1.满足栈底到栈顶的元素具有严格单调性。2.满足栈的先进后出特性,越靠近栈顶的元素越先出栈元素进栈过程对于一个单调递减栈来说,若当前进栈的元素为a,如果a......
  • blocks——题解
    题目描述解析对于这道题,他要求大于k的数进行操作,所以直接让每个数减k,然后用前缀和维护一下与0比较就可以了,因为一段区间和的平均值大于k的话,那么这就是一个合法区间,即为操作后的这个区间和大于0,我们可以用一个单调递减栈去维护,先把比0小的推入栈中,因为要求最大区间,所以边界......
  • 学习笔记#5:单调队列优化&斜率优化
    学习笔记#5:单调队列优化&斜率优化单调队列首先要搞懂什么是单调队列。单调队列是一种求区间最值问题的一种方式,与其他RSQ问题的求解方法不同的是,它更善于解决滑动窗口式的RSQ问题,一般来说,假设我们要维护最大值,则需维护一个单调递减的队列,这样队首最大,每次取队首即可。而当......
  • 单调性优化
    【单调栈】柱状图最大矩形:首先我们有一个最简单的方法:\(O(n^3)\)枚举左右端点,然后再求中间的最小值,最后乘起来得到这段矩形组成的最大面积。求最小值,我们考虑到ST表,我们可以用它优化到\(O(n^2)\)。接下来我们考虑转换枚举思路:我们发现,一个矩形的大小,由它的左右端点,和它中间......
  • P1886-单调队列【黄】
    一道普普通通的模版题,让我想起了此前做过的绿题P1725,于是运用相同的知识轻松切掉本题Code#include<iostream>#include<cstring>#include<string>#include<cstdio>#include<cstdlib>#include<algorithm>#include<stack>#include<queue>#include......