牛客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