F题:Train Wreck
题目大意
solution
先举个例子,若输入
4
()(())()
1 2 4 4
将火车标号1234,并将所有入栈出栈后序列的可能情况列出。
有四种->[1],[2],[2,3],[4]
要使得序列唯一,则将上列情况类似字典树构建后,对每一个节点进行染色,但不允许一个节点的子节点染上相同的颜色(这样就会存在相同序列)。
如图
则我们可以维护一个优先队列,存放两个变量,该颜色的剩余数量和颜色的数值。
对访问到的每个节点的子节点进行染色,优先染上数量多的颜色。若颜色种类不足,而子节点还有未染色的,就说明必定有重复序列出现,此时无解。
否则将每次染色的节点的颜色记录,最后输出答案即可。
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+7;
priority_queue<pair<int,int> > q;
int d[N],top,ans[N];
vector<int> ve[N];
void solve(int x){
vector<pair<int ,int> > tmp;
for(int i=0;i<ve[x].size();i++){
if(q.empty()){//没有其他颜色可染
printf("NO\n");
exit(0);
}
ans[ve[x][i]]=q.top().second;//记录答案
tmp.push_back({q.top().first-1,q.top().second});
q.pop();
}
for(int i=0;i<tmp.size();i++)//将该轮染色结束后剩余颜色的数据再次放入队列进行下一次染色
q.push(tmp[i]);
}
int main()
{
int n;
cin>>n;
string s;
cin>>s;
for(int i=1;i<=n;++i){
int x;
scanf("%d",&x);
++d[x];
}
for(int i=1;i<=n;++i)
if(d[i]){
q.push({d[i],i});
d[i]=0;
}
int tot=0;
for(int i=0;i<s.length();i++){
if(s[i]=='('){
ve[top].push_back(++tot);
++top;
ve[top].clear();
}else{
solve(top);
top--;
}
}
solve(top);
printf("YES\n");
for(int i=1;i<=n;++i)
printf("%d ",ans[i]);
}
//参考了逆十字的代码https://ac.nowcoder.com/acm/contest/view-submission?submissionId=48569378