[CSP-S 2021] 回文 题解

题目传送门

题目大意

给定正整数 \(n\) 和整数序列 \(a_1,a_2,\dots,a_{2n}\),在这 \(2n\) 个数中,\(1, 2,\dots,n\) 分别各出现恰好 \(2\) 次。现在进行 \(2n\) 次操作,目标是创建一个长度同样为 \(2n\) 的序列 \(b_1, b_2, \dots, b_{2 n}\),初始时 \(b\) 为空序列,每次可以进行以下两种操作之一:
将序列 \(a\) 的开头元素加到 \(b\) 的末尾,并从 \(a\) 中移除。
将序列 \(a\) 的末尾元素加到 \(b\) 的末尾,并从 \(a\) 中移除。
我们的目的是让 \(b\) 成为一个回文数列。请你判断该目的是否能达成,如果可以,请输出字典序最小的操作方案(其中第一个操作输出 L,第二个输出 R),否则输出 -1

题目解析

用样例一的第一组数据来说明做法。
\(n=3,a=\{4,1,2,4,5,3,1,2,3,5\}\)
考虑第一个先选择操作 \(1\)(其实先选择操作 \(2\) 是一样的,当然我们优先选择操作 \(1\)),也就是把 \(4\)\(b\) 序列后面。
此时我们发现这时我们需要保证在最后让序列 \(a\) 只剩下一个数字 \(4\)
也就是说序列 \(a\) 会被分成两半:\(\{1,2\}\)\(\{5,3,1,2,3,5\}\)
这时我们如果继续取,那么就必须要在里面两端有相同的数字这样在最后取的时候才能构成回文串。当然我们优先从左边取。如果左右都不满足就代表这样是无解的,需要尝试另一种方法。
最后注意一下序列不能为空。

代码采用双端队列的方法来实现。

#include<cstdio>
#define db double
#define gc getchar
#define pc putchar
#define U unsigned
#define ll long long
#define ld long double
#define ull unsigned long long
#define Tp template<typename _T>
#define Me(a,b) memset(a,b,sizeof(a))
Tp _T mabs(_T a){ return a>0?a:-a; }
Tp _T mmax(_T a,_T b){ return a>b?a:b; }
Tp _T mmin(_T a,_T b){ return a<b?a:b; }
Tp void mswap(_T &a,_T &b){ _T tmp=a; a=b; b=tmp; return; }
Tp void print(_T x){ if(x<0) pc('-'),x=-x; if(x>9) print(x/10); pc((x%10)+48); return; }
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LL_INF (0x7fffffffffffffff)
#define maxn 1000039
#define maxm
#define MOD
#define Type int
#ifndef ONLINE_JUDGE
//#define debug
#endif
using namespace std;
Type read(){
	char c=gc(); Type s=0; int flag=0;
	while((c<'0'||c>'9')&&c!='-') c=gc(); if(c=='-') c=gc(),flag=1;
	while('0'<=c&&c<='9'){ s=(s<<1)+(s<<3)+(c^48); c=gc(); }
	if(flag) return -s; return s;
}
int n,nn,a[maxn],b[maxn],ans[maxn];//0l1r
int s1[maxn],s2[maxn],top1,top2,bot1,bot2,p;
int solve(){
	int i;
	for(i=2;i<=n;i++){
		if(top1-1>=bot1&&s1[top1]==s1[bot1]){ ans[i]=0; bot1++; top1--; }
		else if(top1>=bot1&&top2>=bot2&&s1[top1]==s2[bot2]){ ans[i]=0; bot2++; top1--; }
		else if(top2-1>=bot2&&s2[top2]==s2[bot2]){ ans[i]=1; bot2++; top2--; }
		else if(top1>=bot1&&top2>=bot2&&s2[top2]==s1[bot1]){ ans[i]=1; bot1++; top2--; }
		else return 0;
	} return 1;
}
int check1(){
	p=1; ans[1]=0; int i,tmp; top1=top2=0; bot1=bot2=1;
	for(i=2;i<=nn;i++) if(a[i]==a[1]) tmp=i;
	for(i=tmp-1;i>1;i--) s1[++top1]=a[i];
	for(i=tmp+1;i<=nn;i++) s2[++top2]=a[i];
	return solve();
}
int check2(){
	p=1; ans[1]=1; int i,tmp; top1=top2=0; bot1=bot2=1;
	for(i=1;i<nn;i++) if(a[i]==a[nn]) tmp=i;
	for(i=tmp-1;i>=1;i--) s1[++top1]=a[i];
	for(i=tmp+1;i<nn;i++) s2[++top2]=a[i];
	top1=tmp-1; top2=nn-tmp-1;
	return solve();
}
void printans(){
	int pl=1,pr=nn,i;
	for(i=1;i<=n;i++) if(!ans[i]) b[i]=a[pl++]; else b[i]=a[pr--];
	for(i=n+1;i<=nn;i++)
		if(a[pl]==b[nn-i+1]) ans[i]=0,pl++;
		else ans[i]=1,pr--;
	for(i=1;i<=nn;i++) if(ans[i]) pc('R'); else pc('L');
	pc('\n'); return;
}
void work(){
	n=read(); nn=n<<1; int i; for(i=1;i<=nn;i++) a[i]=read();
	if(check1()) printans();
	else if(check2()) printans();
	else puts("-1"); return;
}
int main(){
	//freopen("palin2.in","r",stdin);
	//freopen("1.out","w",stdout);
	int T=read(); while(T--) work(); return 0;
}
posted @ 2021-12-19 16:30  jiangtaizhe001  阅读(248)  评论(0编辑  收藏  举报