首页 > 其他分享 >[EER1]单调栈

[EER1]单调栈

时间:2022-12-14 21:59:57浏览次数:54  
标签:pre 弹掉 int 1000001 EER1 edge 单调

链接:https://www.luogu.com.cn/problem/P6198

题目描述:给定一个长为\(n\)数列\(S\),求一个字典序最小的排列,使得将这个排列依次放入单调栈中序列中元素的个数与\(S\)一一对应。

题解:介绍一个拓扑排序的做法。

假如我们先不考虑\(S_{i}!=1\)的情况,先考虑一下假如我们将一个排列放入一个单调栈会有什么性质,我们发现有:

\(1\).若\(S_{i-1}<S_{i}\),那么肯定有\(S_{i}=S_{i-1}+1\),因为最多只能增加一个数,那么我们就可以知道\(p_{i-1}<p_{i}\)。

\(2\).若\(S_{i-1}>=S_{i}\),则在这个单调栈中第\(S_{i}\)个元素以及后面的元素全都会被\(pop\)掉,那么我们就可以得到两个关系式:\(p_{d_{S_{i}}}>p_{i}\),\(p_{d_{S_{i}}-1}<p_{i}\)。

若我们记\(t_{i}\)表示我们目前可以得到的最大的小于\(p_{i}\)的\(p\)序列的元素对应的下标,那么我们就可以把原问题转化为偏序问题。

我们可以发现:

\(1\).当\(i\)始终在单调栈时,根据上面的分析,则有\(t_{i}=pre_{i}\)(\(pre_{i}\)表示\(i\)在单调栈的前驱)

\(2\).当\(i\)被\(j\)弹掉时,根据上面的分析\(t_{i}=pre_{i}\)或\(j\),那么由于我们是要取最大的,则

假如\(i\)是被\(j\)弹掉中最小的,则\(t_{i}=j\)

假如\(i\)不是被\(j\)弹掉中最小的,则\(t_{i}=pre_{i}\),因为\(pre_{i}\)被\(j\)弹掉,则\(pre_{i}\)是比\(j\)大的。

则我们给每一个点连一条\((t_{i},i)\)的边,则原问题转化为,按照拓扑排序遍历一个有向图,令\(dfn_{i}\)是\(i\)号节点是\(dfn_{i}\)个被遍历的,最小化\(dfn_{i}\)的字典序。

我们发现,最小化\(dfn_{i}\)的字典序等同于遍历时尽量使\(1\)靠前,在\(1\)尽量靠前的情况下再使\(2\)尽量靠前......我们发现这个问题就是[\(HNOI2015\)]菜肴制作,所以我们只要求出在反图跑最大的的字典序的反序就可以了。

再考虑可以为\(-1\)的情况,这种情况可以令\(S_{i}=S_{i-1}+1\),这样可以保证有解,然后你会发现这样有一定是最优的,具体我不会证。

复杂度\(O(nlogn)\)

#include<iostream>
#include<algorithm> 
#include<queue>
#define int long long
using namespace std;
struct node
{
	int v,nxt;
};
node edge[2000001];
int head[1000001],d[1000001],top,len,length,in[1000001],S[1000001],n,p[1000001],rk[1000001];
int que[1000001];
void add(int x,int y)
{
	edge[++len].v=y;
	edge[len].nxt=head[x];
	head[x]=len;
	return;
}
priority_queue<int>q;
void top_sort()
{
	int tp;
	for (int i=1;i<=n;++i)
		if (in[i]==0)
			q.push(i);
	while (!q.empty())
	{
		tp=q.top();
		d[++length]=tp;
		q.pop();
		for (int i=head[tp];i>0;i=edge[i].nxt)
		{
			in[edge[i].v]--;
			if (in[edge[i].v]==0)
				q.push(edge[i].v);
		}
	}
	return;
}
signed main()
{
	cin>>n;
	for (int i=1;i<=n;++i)
		cin>>S[i];
	for (int i=1;i<=n;++i)
		if (S[i]==-1)
			S[i]=S[i-1]+1;
	for (int i=1;i<=n;++i)
	{
		if (S[i-1]<S[i])
		{
			p[i]=i-1;
			que[++top]=i;
		}
		else
		{
			p[i]=que[S[i]-1];
			if (S[i]<=top)
				p[que[S[i]]]=i; 
			top=S[i]-1;
			que[++top]=i;
		}
	}
	for (int i=1;i<=n;++i)
		if (p[i]!=0)
		{
			add(i,p[i]);
			in[p[i]]++;
		}
	top_sort();
	for (int i=1;i<=n/2;++i)
		swap(d[i],d[n-i+1]);
	for (int i=1;i<=n;++i)
		rk[d[i]]=i;
	for (int i=1;i<=n;++i)
		cout<<rk[i]<<' ';
	cout<<endl;
	return 0;
}

标签:pre,弹掉,int,1000001,EER1,edge,单调
From: https://www.cnblogs.com/zhouhuanyi/p/16983688.html

相关文章

  • 决策单调性优化
    数学推导比较多。但是充斥着对称美。单调队列/斜率优化,都是决策单调性优化。这篇主要说四边形不等式优化。还没写完。基本定义四边形不等式:对于二元函数\(w_{x,y}\),......
  • 代码随想录训练营第六十天 | 单调栈
    今天是代码随想录训练营的第六十天,是最后一天,也代表这一刷结束 84.柱状图中最大的矩形classSolution{publicintlargestRectangleArea(int[]heights){......
  • 代码随想录训练营第五十八章|单调栈
    今天是训练营第五十八天,是最后一天单调栈的开始  739.每日温度 classSolution{publicint[]dailyTemperatures(int[]temperatures){intn......
  • 代码随想录训练营第五十九天| 单调栈
     今天是第五十九天,有经典的接雨水问题 ●  503.下一个更大元素II classSolution{publicint[]nextGreaterElements(int[]nums){if(nums==......
  • 单调栈与单调队列
    单调栈是栈中数据具有单调性的一种数据结构,用来求以某个值为最值的最大区间等问题模板(c++):intn,in;intstack[1010];inttop;func(){for(int......
  • 八. 栈和单调栈
    普通栈:​​剑指Offer09.用两个栈实现队列​​classCQueue:def__init__(self):self.A,self.B=[],[]defappendTail(self,value:int)->None:......
  • 5.3.1 (2) 函数的单调性(含参函数)
    \({\color{Red}{欢迎到学科网下载资料学习}}\)[【基础过关系列】高二数学同步精品讲义与分层练习(人教A版2019)](https://www.zxxk.com/docpack/2875423.html)\({\col......
  • 5.3.1 (1) 函数的单调性
    \({\color{Red}{欢迎到学科网下载资料学习}}\)[【基础过关系列】高二数学同步精品讲义与分层练习(人教A版2019)](https://www.zxxk.com/docpack/2875423.html)\({\col......
  • leetcode 1687. 从仓库到码头运输箱子 动态规划 + 单调队列
    你有一辆货运卡车,你需要用这一辆车把一些箱子从仓库运送到码头。这辆卡车每次运输有 箱子数目的限制 和总重量的限制 。给你一个箱子数组 boxes 和三个整数portsCo......
  • 单调栈
    单调栈单调栈简单来说是在栈的先进后出基础之上额外添加一个特性:从栈顶到栈底的元素是严格递增(or递减)具体进栈过程如下:对于单调递增栈,若当前进栈元素为e,从栈顶开始遍历......