鏈接:
題意:
給出一個長度為 \(2n\) 的序列 \(a\),其中 \(1\sim n\) 每個數出現了 2 次。有 L,R
兩種操作分別是將 \(a\) 的開頭或末尾元素加入到初始為空的序列 \(b\) 里,目標是讓 \(b\) 成為一個回文串。
需要判斷無解或求出字典序最小的方案。
\(T(T\leq100)\) 組數據,對於每組數據 \(n\leq5\times10^5\)。\(\sum n\leq5\times10^5\)。
分析:
首先對於 \(a\) 串,一定存在一個分界點使得左邊的元素是通過 L
操作彈出的,右邊的元素是通過 R
操作彈出的,顯然 \(b\) 的末尾就在這個分界點的兩邊,顯然 \(b\) 的末尾一定是 \(a\) 的開頭或結尾,這里先假設是開頭。
那么找到這個分界點,也就是與 \(a_1\) 相同的位置。發現序列被分成了兩段,左邊一段是從左往右通過 L
操作彈出的,右邊一段是從右往左通過 R
操作彈出的,那么我們把這兩段拉出來,這里有個細節就是分界點要分在左邊一段,因為要求字典序最小。
假設與 \(a_1\) 相等的地方是 \(i\),\(i\) 的下一個位置是 \(j\),大概就是:
變成了兩個隊列,隊首在 \(b\) 的前面,隊尾在 \(b\) 的后面,那么只要隊首和隊尾能配對,就貪心選擇字典序小的並加入到 \(b\) 里就可以了。
然后如果 \(b\) 的末尾是 \(a\) 的末尾,就重新找分界點再做一遍就行了。
另外,可能會存在 \(a\) 的開頭等於 \(a\) 的末尾的情況,此時除非原始串就是回文串,否則是無解的,特判一下就行了。
算法:
找到分界點,維護兩個雙端隊列,貪心選擇即可。
代碼:
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define in read()
inline int read(){
int p=0,f=1;
char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){p=p*10+c-'0';c=getchar();}
return p*f;
}
const int N=5e5+5;
int T,n,a[N<<1];
int flag,s,e;
int A[N<<1],ai,an;
int B[N<<1],bi,bn;
int ans[N<<1];
signed main(){
freopen("palin.in","r",stdin);
freopen("palin.out","w",stdout);
T=in;
while(T--){
flag=1;n=in;
for(int i=1;i<=(n<<1);i++)a[i]=in;
for(int i=1;i<=n;i++)
if(a[i]!=a[(n<<1)-i+1])flag=0;
for(int i=2;i<(n<<1);i++){
if(a[i]==a[1])s=i;
if(a[i]==a[(n<<1)])e=i;
}
if(a[1]==a[(n<<1)]){
if(flag){for(int i=1;i<=(n<<1);i++)putchar('L');puts("");}
else puts("-1");
continue;
}
for(int i=1;i<=s;i++)A[i]=a[i];an=s;bn=(n<<1)-s;
for(int i=(n<<1);i>=s+1;i--)B[(n<<1)-i+1]=a[i];
ai=1,bi=1,flag=0;
for(int i=1;i<=n;i++){
if(ai<an&&A[ai]==A[an])
ans[i]=ans[(n<<1)-i+1]='L',ai++,an--;
else if(ai<=an&&bi<=bn&&A[ai]==B[bn])
ans[i]='L',ans[(n<<1)-i+1]='R',ai++,bn--;
else if(bi<bn&&B[bi]==B[bn])
ans[i]=ans[(n<<1)-i+1]='R',bi++,bn--;
else if(ai<=an&&bi<=bn&&B[bi]==A[an])
ans[i]='R',ans[(n<<1)-i+1]='L',bi++,an--;
else flag=1;
}
if(!flag){
for(int i=1;i<=(n<<1);i++)
cout<<(char)ans[i];
puts("");
}
else{
s=e;
for(int i=1;i<=s;i++)A[i]=a[i];an=s;bn=(n<<1)-s;
for(int i=(n<<1);i>=s+1;i--)B[(n<<1)-i+1]=a[i];
ai=1,bi=1,flag=0;
for(int i=1;i<=n;i++){
if(ai<an&&A[ai]==A[an])
ans[i]=ans[(n<<1)-i+1]='L',ai++,an--;
else if(ai<=an&&bi<=bn&&A[ai]==B[bn])
ans[i]='L',ans[(n<<1)-i+1]='R',ai++,bn--;
else if(bi<bn&&B[bi]==B[bn])
ans[i]=ans[(n<<1)-i+1]='R',bi++,bn--;
else if(ai<=an&&bi<=bn&&B[bi]==A[an])
ans[i]='R',ans[(n<<1)-i+1]='L',bi++,an--;
else flag=1;
}
if(!flag){
for(int i=1;i<=(n<<1);i++)
cout<<(char)ans[i];
puts("");
}
else puts("-1");
}
}
return 0;
}
題外話:
沒想到會這么簡單,失策了