[CF1152E]Neko and Flashback Solution

本文深入探讨了一种基于序列重构的算法,旨在通过已知的派生序列重建原始序列。算法首先定义了两个辅助序列bbb和ccc,分别由原始序列aaa中相邻元素的最小值和最大值构成。随后,通过对bbb和ccc进行排列得到b′b′和c′c′,并以此为基础,逆向求解可能的aaa序列。文章详细解释了算法原理,包括如何检测解的存在性和唯一性,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:
有一个原始序列aaa,现在构造一些序列:

  • 构造长度为n−1n-1n1bbb序列,满足b[i]=min⁡(a[i],a[i+1])b[i]=\min(a[i],a[i+1])b[i]=min(a[i],a[i+1])
  • 构造长度为n−1n-1n1ccc序列,满足c[i]=max⁡(a[i],a[i+1])c[i]=\max(a[i],a[i+1])c[i]=max(a[i],a[i+1])
  • 构造长度为n−1n-1n1的排列ppp
  • 构造长度为n−1n-1n1b′b'b序列,满足b′[i]=b[p[i]]b'[i]=b[p[i]]b[i]=b[p[i]]
  • 构造长度为n−1n-1n1c′c'c序列,满足c′[i]=c[p[i]]c'[i]=c[p[i]]c[i]=c[p[i]]

给出b′b'b序列和c′c'c序列,求出任意一个满足条件的aaa序列。如果没有满足的aaa序列,输出−1-11
显而易见只要有一个iii满足b′[i]>c′[i]b'[i]>c'[i]b[i]>c[i],那么就是无解的。
考虑到只有这两种情况:

  • a[i]=b[i],a[i+1]=c[i]a[i]=b[i],a[i+1]=c[i]a[i]=b[i],a[i+1]=c[i]
  • a[i]=c[i],a[i+1]=b[i]a[i]=c[i],a[i+1]=b[i]a[i]=c[i],a[i+1]=b[i]

所以就可以将每对b′[i]b'[i]b[i]c′[i]c'[i]c[i]连上边。
然后对于建出来的一张图检测它是否存在欧拉路就可以了。
code:code:code:

#include <bits/stdc++.h>
using std::cin;
using std::cout;
#define regi register int
int n;
int a[1000001];
int b[1000001];
int in[1000001];
int Dis[1000001],Dn;
int head[2000001],tot=1;
int vis[2000001];
int ans[10000001],Tot;
struct edge{
	int to;
	int nxt;
}e[5000001];
inline void add(int x,int y){
	e[++tot]={y,head[x]};
	head[x]=tot;
}
void dfs(int x){
	for(regi &i=head[x];i;i=e[i].nxt){
		if(vis[i])
		  continue;
		regi y=e[i].to;
		vis[i]=vis[i^1]=1;
		dfs(y);
	}
	ans[++Tot]=x;
}
main(){
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
  cin>>n;
  for(regi i=1;i<=n-1;++i){
    cin>>a[i];
    Dis[i]=a[i];
  }
  for(regi i=1;i<=n-1;++i){
    cin>>b[i];
    Dis[n+i-1]=b[i];
	}
	for(regi i=1;i<=n;++i){
		if(a[i]>b[i])
		  return std::cout<<-1,0;
	}
  std::sort(Dis+1,Dis+2*n-1);
  Dn=std::unique(Dis+1,Dis+2*n-1)-Dis-1;
  for(regi i=1,l,mid,r;i<n;++i){
    l=1,r=Dn;
    while(l<r){
    	mid=l+r+1>>1;
    	if(Dis[mid]<=a[i])
    	  l=mid;
    	else
    	  r=mid-1;
    }
    a[i]=l;
    l=1,r=Dn;
    while(l<r){
    	mid=l+r+1>>1;
    	if(Dis[mid]<=b[i])
    	  l=mid;
    	else
    	  r=mid-1;
    }
    b[i]=l;
  }
  for(regi i=1;i<n;++i){
  	add(a[i],b[i]);
  	add(b[i],a[i]);
  	in[a[i]]++;
  	in[b[i]]++; 
	}
	int flag=0;
	for(regi i=1;i<=Dn;++i)
	  flag+=(in[i]&1);
	if(flag!=0&&flag!=2)
		return std::cout<<-1,0;
	flag=0;
	for(regi i=1;i<=Dn;++i)
	  if(in[i]&1){
		   dfs(i);
		   flag=1;
		   break;
		 }
  if(!flag)
	  dfs(1);
  if(Tot!=n)
    return std::cout<<-1,0;
  for(regi i=1;i<=n;++i)
    cout<<Dis[ans[i]]<<" ";
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值