题意
有一个长度为n的数组k,然后有2个长度为n-1的数组b和c
b[i]=min(k[i],k[i+1]),c[i]=max(k[i],k[i+1]);
然后把b,c按照一样的方法打乱得到b1,c1
现在给你b1,c1,让你构造出一个数组,在经过上述操作后能得到b1,c1
题解
考虑题目中给的例子1
5 4 5 3 5 6 7 4 6
我们从上往下看,分为4组(4,6),(5,7),(3,4),(5,6)
(4,6)表示的意思是什么呢?在某一个位置j,min(k[j],k[j+1])=4,max(k[j],k[i+1])=6
那么在j和j+1这个位置,要么是(4,6),要么是(6,4),显然2者只能选其一
那么我们就可以把每一列转化为1条无向边,然后把所有边连起来
这个不就是欧拉路径嘛
但是有一点值得注意的就是这个值的范围比较大,所以我们需要把这些值紧凑一下,用一个map就好;
代码
#include<bits/stdc++.h> using namespace std; const int N=2*1e5+100; multiset<int> to[N]; int len[N]; int road[N],k; void dfs(int x){ for(auto a=to[x].begin();a!=to[x].end();a=to[x].begin()){//auto类型为C++11标准,可进行自动类型推断 int u=*a; to[x].erase(a); to[u].erase(to[u].find(x));//删边 dfs(u);//递归 } road[k++]=x;//往答案队列里插入答案 } int n; int x[N],y[N]; bool flag; map<int,int> m; int p[2*N]; int cnt; int main(){ int a,b; flag=true; scanf("%d",&n); for(int i=1;i<n;i++)cin>>x[i]; for(int i=1;i<n;i++)cin>>y[i]; for(int i=1;i<n;i++){ if(m.count(x[i])==0){ p[cnt]=x[i]; m[x[i]]=cnt++; } if(m.count(y[i])==0){ p[cnt]=y[i]; m[y[i]]=cnt++; } a=m[x[i]]; b=m[y[i]]; if(x[i]>y[i])flag=false; len[a]++,len[b]++; to[a].insert(b); to[b].insert(a); } int s=-1,e=-1;//起点与终点 if(!flag){ cout<<-1<<endl; return 0; } for(int i=0;i<cnt;i++) if(len[i]%2==1){ if(s==-1)s=i; else if(e==-1)e=i; else { cout<<-1<<endl; return 0; } }//判断每个点的度数 if(s==-1)s=0; dfs(s);//开始递归 if(k==n)for(k=k-1;k>=0;k--) printf("%d ",p[road[k]]);//倒序输出答案 else cout<<-1<<endl; return 0; }