2019.12.9--2019.12.15 第四周 前向距离之和的解法及单调栈基础

题目:

给定一个序列a_1,a_2,…,a_n。其中a_1是最大的数,没有其他数与它相等
对于从第二个数开始的每个数a_i,请找到位置在a_i之前且比a_i大的。位置上距离a_i最近的的数a_j.i-j为a_i的前向距离
对于给定的序列,输出所有数的前向距离之和。
输入格式:
第一行包括一个整数n,表示序列长度
第二行包括n个正整数,为给定的序列
输出格式:
输出一个整数,表示序列中所有数的前向距离之和。
样例输入
8
9 1 3 5 2 7 6 3
输出
14
数据规模:
1<=n<=100000

解法

1.暴力

简单粗暴,依次查找来寻找比a[i]大的值,此处不再赘述。

2. 并查集

既然要寻找比a[i]大的值,那么让每一个被查询的值都比上一个被查询的值大,就可以节省很多时间了。恰好查询时前面的都被查询过,每个a[i]前面的 j 都已知,则可以使用每一个被查询数作为跳板,直接跳向它前面比它大的值。
具体操作使用并查集算法,以bf数组储存该数前面的大值的下标

代码:

#include<stdio.h>
typedef long long ll;
int main()
{
	int i,j,n;
	ll sum=0,a[1001],bf[1001];//bigger front
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%lld",&a[i]);
	}
	for(i=1;i<n;i++)
	{
		bf[i]=i-1;
		while(a[i]>=a[bf[i]])//a[bf[i]]为查询的项前的大值,bf[i]为它的下标。 
		{
			bf[i]=bf[bf[i]];//bf[i]的值为a[bf[i]]前的大值的下标 
		}
		sum=sum+i-bf[i];
	}
	printf("%lld",sum);
	return 0;
} 

3. 单调栈

接下来就是本题常规做法单调栈啦。

单调栈特性

(1)栈中数据单调,可递增可递减
(2) 后进先出特性:越靠近栈底的元素越早进栈,可以意会为摞起来的一串数据。
(3)只可对栈顶的数操作

举例:

将{10,20,50,4,3,90}存入某单调递增栈中:

  1. 栈为空,存入10,此时栈中{10}
  2. 20>10,符合条件,存入20,此时{10,20}
  3. 50>20,符合条件,存入50,此时{10.20,50}
  4. 4<50,不断使栈顶元素出栈,直至符合条件,存入4,此时{4}
  5. 3<50,原理同上,{3}
  6. 90>3,符合条件,存入90,此时{3,90}

本题代码

#include<stack>
#include<iostream>
#include<cstdio>

using namespace std;
typedef long long ll;
int main()
{
	stack<int>s;
	ll sum=0;
	int n,i,a[100001],in[100001];//in[i]用于储存a[i]前面的大值的下标,作用类似于上面的bf
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
		if(i==0)	s.push(i);//栈为空,一定压入i值
		else
		{
			while(a[i]>a[s.top()])
			{
				s.pop();
			}
			in[i]=s.top();
			s.push(i);
			if(a[i]==a[in[i]])	in[i]=in[in[i]];//两值相等情况须特殊考虑
			sum+=(i-in[i]);
		}	
	}
	printf("%lld",sum);
	return 0;
}

具体操作

  1. 最大值一定为a[0],故将0压入栈中
  2. 当栈顶值小于a[i]时,去除栈顶,直至新的栈顶大于a[i],再压入i,以保障栈中单调
  3. 这样,每当a[i]即将被压入栈时,栈顶的值即为a[i]前的大值的数组下标
  4. 用一个数组in存储每个a[i]前的大值的数组下标
  5. 排除特殊情况两值相等的干扰,(如{9,2,2,2,2},{9,2 ,1,2,1})以相同的数为跳板,找寻比它大的数,原理类似上文并查集做法

单调栈链接知识

基本用法

头文件 #include< stack >
库函数:
(1)empty
语法: bool empty();
如当前堆栈为空,empty() 函数 返回 true 否则返回false.


(2)pop
语法: void pop();
pop() 函数移除堆栈中最顶层元素。


(3)push
Syntax: void push( const TYPE &val );
push() 函数将 val 值压栈,使其成为栈顶的第一个元素。如:

stack<int> s;
for( int i=0; i < 10; i++ )
  s.push(i);

(4)size
语法: size_type size();
size() 函数返当前堆栈中的元素数目。如:

stack<int> s;
for( int i=0; i < 10; i++ )
  s.push(i);
cout << "This stack has a size of " << s.size() << endl;

(5)top
语法: TYPE &top();
top() 函数返回对栈顶元素的引用. 举例,如下代码显现和清空一个堆栈。

while( !s.empty() ) {
  cout << s.top() << " ";
  s.pop();
}

例题

有待补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值