ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[CSP-S 2021] 回文

2021-10-25 09:31:14  阅读:271  来源: 互联网

标签:ch int 我们 2021 端点 序列 CSP 回文


回文

吐槽:这题的字典序最小是答案字符串的字典序最小。

题目大意

给定一个长为 \(2n\) 的序列,由数字 \(1~n\) 组成,且每个数字有两个。

每次操作要么选择左端点要么选择右端点,选择后将该数字从序列里删除并加入另一个序列的末尾,要求最后得到的序列是一个回文串。

输出一个长为 \(2n\) 的字符串,为每一次的选择,选左端点为 \(L\) ,选右端点为 \(R\) 。

若有多种方案,输出字典序最小的那一个。

分析

手玩一下样例,可以发现以下性质:

  • 每当我们取一个数,我们必定能在序列中间的某个位置找到与这个数相同的数。

  • 由于是回文串,我们可以将其分为两半取,先考虑前一半,发现前一半越先取后一半就要越后取。

于是,我们能够推出一个比较重要的性质。

假设我们取了一个数,在中间某个位置找到了它,又取了另外一个数,同样在中间某个位置找到了和它相同的那个数。这两个对应位置如果不相连,必然可以相信,它们中间的数会在未来某个位置被我们取到,根据上述性质 \(2\) ,我们要在两个后取的数的包裹下取一个先取的数,显然是不合题意的。

所以,我们可以把序列分为两部分,一部分是端点,一部分是已经选的数的映射区间,要保证,该区间必须连续,所以每次选的数必须要在这个区间的两边扩展,也就是说只能选这个区间的两边对应的数。简单的,如果无法进行扩展,说明我们的匹配失败了。

我们可以维护四个指针,然后能选左就选左,否则考虑选右,由于最开始我们没有区间,于是我们进行两次这个操作,第一次最开始选择左端点,第二次最开始选择右端点,若第一次已经成功那么就是最优解,否则进行第二次。
若两次都失败,则无解。

CODE

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w*=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;	
}
int T,n;
int R[N],a[2*N];
int num[N];
char ans[2*N],temp[2*N];
bool flag;
inline void Solve(int x,int y,int A,int B) //记录目前的位置 
{
	int cnt=1;
	while(cnt<n){ //选完为止
		//理论上两边都能选
		//先选小的
		int tx=x;
		if(a[x]==a[B]&&x<=A&&B<=y) B++,x++;
		else if(a[x]==a[A]&&x<A) A--,x++;
		else if(a[y]==a[B]&&B<y) B++,y--;
		else if(a[y]==a[A]&&x<=A&&B<=y) A--,y--;
		else return;
		if(tx!=x) temp[++cnt]='L';
		else temp[++cnt]='R';
	}
	flag=true; //匹配成功 
}
inline void out()
{
	int x=1,y=2*n,tot=0;
	for(register int i=1;i<=n;i++){
		if(temp[i]=='L') R[++tot]=a[x],x++;
		else R[++tot]=a[y],y--;
	}
	for(register int i=n+1;i<=2*n;i++){
		if(R[tot]==a[x]) temp[i]='L',x++;
		else temp[i]='R',y--;
		tot--;
	}
	for(register int i=1;i<=2*n;i++){
		if(ans[i]<temp[i]) return;
		if(temp[i]<ans[i]) break;
	}
	for(register int i=1;i<=2*n;i++) ans[i]=temp[i];
}
inline void update()
{
	
	flag=false;
	int p;
	for(register int i=2;i<=2*n;i++)
		if(a[i]==a[1]) { p=i; break; }
	temp[1]='L',Solve(2,2*n,p-1,p+1);
	if(flag) { out(); return; }
	for(register int i=1;i<=2*n-1;i++)
		if(a[i]==a[2*n]) { p=i; break; }
	temp[1]='R',Solve(1,2*n-1,p-1,p+1); //从两个位置出发做一遍 
	if(flag) { out(); return; }
}
int main()
{
//      freopen("palin.in","r",stdin);
//      freopen("palin.out","w",stdout);
	T=read();
	while(T--){
		ans[1]='Z'; //初始值 
		n=read();
		for(register int i=1;i<=2*n;i++) a[i]=read();
		update();
		if(ans[1]=='Z') printf("-1\n");
		else{
			for(register int i=1;i<=2*n;i++) printf("%c",ans[i]);
			printf("\n");
		}
	}
	return 0;
}

标签:ch,int,我们,2021,端点,序列,CSP,回文
来源: https://www.cnblogs.com/Defoliation-ldlh/p/15456996.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有