2021牛客暑期多校训练营2 K.Stack(构造,拓扑排序)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营2 K.Stack(构造,拓扑排序)相关的知识,希望对你有一定的参考价值。

LINK


已知 b i b_i bi b j b_j bj,若 b i + ( j − i ) < b j b_i+(j-i)<b_j bi+(ji)<bj肯定无解,因为每个元素都入栈仍无法满足存在 b j b_j bj个元素

所以可以发现,在相邻的 b i , b j b_i,b_j bi,bj之间的元素都加进去比较好

如果在 b j b_j bj处发现多了,可以构造一个 a j a_j aj弹出适量元素,但是少了就直接无解了.

于是为了方便,我们构造 b i + 1 = b i + 1 b_{i+1}=b_i+1 bi+1=bi+1

初始设一个栈,栈中存放的是没有被弹出去的 a a a元素下标

所以每次加入新元素 a i a_i ai时就把 i i i入栈

若此处 b i b_i bi没有限制,只需要让 i − 1 i-1 i1 i i i连一条边,表示 a i − 1 < a i a_{i-1}<a_i ai1<ai

若此处 b i b_i bi有限制,检查一下栈中的元素是否大于 b i b_i bi

若小于说明无解,因为加入新元素只会弹栈

若大于等于有解,先计算出需要弹出 z z z个元素,此时栈顶元素为 s [ t o p ] s[top] s[top],最后一个被弹出栈的元素为 s [ t o p + 1 ] s[top+1] s[top+1]

说明 a i > a s [ t o p ] & & a i < a s [ t o p + 1 ] a_i>a_{s[top]}\\&\\&a_i<a_{s[top+1]} ai>as[top]&&ai<as[top+1]

然后由小的一方向大的一方连边即可

最后连完是个 D A G \\rm DAG DAG,跑一遍拓扑排序即可构造一组合法解

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int n,k,b[maxn],ans[maxn],in[maxn],s[maxn],top;
vector<int>vec[maxn];
void add(int l,int r){ vec[l].push_back( r );  in[r]++; }
void tuopu()
{
	queue<int>q;
	for(int i=1;i<=n;i++)
		if( !in[i] )	q.push( i );
	int siz = 0;
	while( !q.empty() )
	{
		int u = q.front(); q.pop();
		ans[u] = ++siz;
		for(auto v:vec[u] )
			if( --in[v]==0 )	q.push( v );
	}
	for(int i=1;i<=n;i++)
		printf("%d%c",ans[i],i==n?'\\n':' ');
}
signed main()
{
	cin >> n >> k;
	for(int i=1;i<=k;i++)
	{
		int p,x; cin >> p >> x;
		b[p] = x;
	}
	for(int i=1;i<=n;i++)
	{
		s[++top] = i;
		if( b[i] && top<b[i] ) { cout << -1; return 0; }
		if( i==1 )	continue; 
		if( b[i] && top>b[i] )//有限制,弹栈 
		{
			top = b[i]-1;//s[top]小于i,而s[top+1]大于i 
			add( i,s[top+1] );
			if( top )	add( s[top],i );
			s[++top] = i;
		}
		else	add( i-1,i );//i-1小于i 
	}
	tuopu();
}

以上是关于2021牛客暑期多校训练营2 K.Stack(构造,拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章

2021牛客暑期多校训练营2

2021牛客暑期多校训练营6,签到题CFHI

2021牛客暑期多校训练营4,签到题CFIJ

2021牛客暑期多校训练营 2

2021牛客暑期多校训练营2,签到题CDFKI

2021牛客暑期多校训练营2.I Penguins BFS广搜 简单