牛客2021暑假多校10Train Wreck(出栈顺序,建树,优先队列维护)

Posted 小哈里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客2021暑假多校10Train Wreck(出栈顺序,建树,优先队列维护)相关的知识,希望对你有一定的参考价值。

F Train Wreck

题意:

  • 给出长为2n的括号序列,()分别表示放入站台和拿出,以及n辆火车的颜色。
  • 求构造一个放入序列,满足不存在同一时刻站台内的颜色序列相同

思路:

  • 将栈操作视为树,要求转化为给每一个节点染色,使得从根到每一个节点的链所构
    成的颜色序列两两不同
    。注意到两个都在第i 层的节点,如果它们的父亲不同,则从根
    到它们父亲的链所构成的颜色序列不同,这使得从根到它们的链所构成的颜色序列一定
    不同。(因为删去序列最后一项后得到的序列不同)
  • 因此,条件可以转化为每个点的k个儿子颜色互不相同。对于一个节点,假设其有k 个儿子,我们选取剩余火车数最多的k 个颜色对应上去即可
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;

vector<int>G[maxn]; 
int fa[maxn], tot=1;
int a[maxn], ans[maxn];

int main(){
	int n;  string s;  cin>>n>>s;
	int p = 1;
	for(char ch : s){//建树
		if(ch=='('){
			G[p].push_back(++tot);
			fa[tot] = p;
			p = tot;
		}else{
			p = fa[p];
		}
	}
	for(int i = 1; i <= n; i++){
		int x;  cin>>x;  a[x]++;
	}

	priority_queue<pair<int,int> >q;
	for(int i = 1; i <= n; i++)q.push({a[i],i});
	for(int i = 1; i <= tot; i++){ //枚举每个点
		vector<pair<int,int> >vc;  //备个份
		for(int j = 0; j < G[i].size(); j++){//每个点的k个儿子颜色互不相同
			auto p = q.top(); q.pop();
			vc.push_back(p);
			ans[G[i][j]] = p.second;//剩余火车数最多的k个颜色对应上去即可
			if(p.first==0){
				cout<<"NO\\n";  return 0;
			}
		}
		for(auto p : vc){
			p.first--;  q.push(p);
		}
	}
	cout<<"YES\\n";
	for(int i = 2; i <= n+1; i++)
		cout<<ans[i]<<" ";
	return 0;
}


  • 对于序列,每次放入会产生一个新的序列,我们用 [序列长度(链的长度), 序列最后一个元素放入时刻(即父亲)] 表示当前序列的状态,如果前面出现过这个序列,那就把新时刻加入末位,否则新建序列。
  • 对于颜色,每次从当前剩余最多的开始取,每种颜色取一个,取出后按照顺序填入序列即可,可以用优先队列维护当前每种颜色的个数。
//比赛
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;

map<int,int>ma;
map<pair<int,int>,int>mp;
vector<int>vc[maxn];
int ans[maxn];

int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n; string s;  cin>>n>>s;
	for(int i = 1; i <= n; i++){
		int x;  cin>>x;  ma[x]++;
	}

	stack<int>stk;
	stk.push(0);
	int t = 0, y = 0;
	for(char ch : s){
		if(ch=='('){
			pair<int,int>p = make_pair(stk.size(), stk.top());
			if(!mp[p])mp[p]=++t;
			vc[mp[p]].push_back(++y);
			stk.push(y);
		}else{
			stk.pop();
		}
	}

	priority_queue<pair<int,int>>q;
	for(auto i: ma)q.push({i.second, i.first});
	for(int i = 1; i <= n; i++){
		queue<pair<int,int> >nq;
		for(int x : vc[i]){
			if(q.empty()){
				cout<<"NO\\n"; return 0; //颜色不够了
			}
			auto p = q.top();  q.pop();
			if(p.first-1>0)nq.push({p.first-1,p.second});
			ans[x] = p.second;
		}
		while(!nq.empty())q.push(nq.front()),nq.pop();
	}
	cout<<"YES\\n";
	for(int i = 1; i <= n; i++)cout<<ans[i]<<" ";
	return 0;
}

以上是关于牛客2021暑假多校10Train Wreck(出栈顺序,建树,优先队列维护)的主要内容,如果未能解决你的问题,请参考以下文章

2021牛客暑期多校训练营10 F.Train Wreck(栈,并查集,优先队列,贪心)

牛客2018暑假多校第三场A PACM Team(01背包+纪录路径)

2020牛客暑假多校第一场 J题 Easy Integration

暴力sg入门--(牛客暑假多校A-Alice and Bob)

2021牛客暑期多校训练营 2

2021牛客暑期多校训练营10,签到题FH