P7915 回文
2023-10-18 19:42:47 # OI # Problem

CSP 2021 T3

题面

题目描述

给定正整数 nn 和整数序列 a1,a2,,a2na_1, a_2, \ldots, a_{2 n},在这 2n2 n 个数中,1,2,,n1, 2, \ldots, n 分别各出现恰好 22 次。现在进行 2n2 n 次操作,目标是创建一个长度同样为 2n2 n 的序列 b1,b2,,b2nb_1, b_2, \ldots, b_{2 n},初始时 bb 为空序列,每次可以进行以下两种操作之一:

  1. 将序列 aa 的开头元素加到 bb 的末尾,并从 aa 中移除。
  2. 将序列 aa 的末尾元素加到 bb 的末尾,并从 aa 中移除。

我们的目的是让 bb 成为一个回文数列,即令其满足对所有 1in1 \le i \le n,有 bi=b2n+1ib_i = b_{2 n + 1 - i}。请你判断该目的是否能达成,如果可以,请输出字典序最小的操作方案,具体在【输出格式】中说明。

输入格式

每个测试点包含多组测试数据。

输入的第一行,包含一个整数 TT,表示测试数据的组数。对于每组测试数据:

第一行,包含一个正整数 nn
第二行,包含 2n2 n 个用空格隔开的整数 a1,a2,,a2na_1, a_2, \ldots, a_{2 n}

输出格式

对每组测试数据输出一行答案。

如果无法生成出回文数列,输出一行 ‐1,否则输出一行一个长度为 2n2 n 的、由字符 LR 构成的字符串(不含空格),其中 L 表示移除开头元素的操作 1,R 表示操作 2。

你需要输出所有方案对应的字符串中字典序最小的一个。

字典序的比较规则如下:长度均为 2n2 n 的字符串 s12ns_{1 \sim 2 n}t12nt_{1 \sim 2 n} 字典序小,当且仅当存在下标 1k2n1 \le k \le 2 n 使得对于每个 1i<k1 \le i < ksi=tis_i = t_isk<tks_k < t_k

样例 #1

样例输入 #1

2
5
4 1 2 4 5 3 1 2 3 5
3
3 2 1 2 1 3

样例输出 #1

LRRLLRRRRL
-1

样例 #2

样例输入 #2

见附件中的 palin/palin2.in

样例输出 #2

见附件中的 palin/palin2.ans

提示

【样例解释 #1】

在第一组数据中,生成的的 bb 数列是 [4,5,3,1,2,2,1,3,5,4][4, 5, 3, 1, 2, 2, 1, 3, 5, 4],可以看出这是一个回文数列。

另一种可能的操作方案是 LRRLLRRRRR,但比答案方案的字典序要大。

【数据范围】

n\sum n 表示所有 TT 组测试数据中 nn 的和。

对所有测试点保证 1T1001 \le T \le 1001n,n5×1051 \le n, \sum n \le 5 \times {10}^5

测试点编号 TT \le nn \le n\sum n \le 特殊性质
171 \sim 7 1010 1010 5050
8108 \sim 10 100100 2020 10001000
111211 \sim 12 100100 100100 10001000
131513 \sim 15 100100 10001000 2500025000
161716 \sim 17 11 5×1055 \times {10}^5 5×1055 \times {10}^5
182018 \sim 20 100100 5×1055 \times {10}^5 5×1055 \times {10}^5
212521 \sim 25 100100 5×1055 \times {10}^5 5×1055 \times {10}^5

特殊性质:如果我们每次删除 aa 中两个相邻且相等的数,存在一种方式将序列删空(例如 a=[1,2,2,1]a = [1, 2, 2, 1])。

【hack 数据提供】
@潜在了H2O下面

思路

假设先选左边,那么我们找到序列中和最左边这个数相同的数的位置 xx,那么就分为了 1x11\sim{x-1}xlenx\sim{len} 这两端区间,xx 一定是最后弹出的。

我们分别维护两个双端队列:1x11\to{x-1}lenxlen\to{x},设为 aabb

那么我们就要找是否有某对 队头和队尾相等

  • 假如是 aa 的队头和队尾相同,那么一定对应着对称的两次 LL
  • 假如是 bb 的队头和队尾相同,那么一定对应着两次对称的 RR
  • 假如是 aa 的队头和 bb 的队尾相同,那么假如弹出 aa 队头是第 ii 个数,那么弹出 bb 队尾就是倒数第 ii 个数。
  • 假如 bb 的队头和 aa 的队尾相同,那么假如弹出 bb 队头是第 ii 个数,那么弹出 aa 队尾就是倒数第 ii 个数。
  • 假如都不符合,那么就找不到一种合法的情况。

先选右边也是同理。

分别维护两个字符串,表示从队头出还是从队尾出,注意队尾出的操作是倒序,要进行一次翻转。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;

int a[N];
int n;

// struct Mydeque
// {
//     int l, r;
//     int z[N << 1];
//     Mydeque()
//     {
//         memset(z, 0, sizeof(z));
//         l = r = N;
//     }
//     int back()
//     {
//         return z[r];
//     }
//     int front()
//     {
//         return z[l + 1];
//     }
//     void push_back(int x)
//     {
//         z[++r] = x;
//     }
//     void push_front(int x)
//     {
//         z[l--] = x;
//     }
//     void pop_back()
//     {
//         if(!empty()) r--;
//     }
//     void pop_front()
//     {
//         if(!empty()) l++;
//     }
//     void clear()
//     {
//         memset(z, 0, sizeof(z));
//         l = r = N;
//     }
//     bool empty()
//     {
//         return r == l;
//     }
//     int size()
//     {
//         return r - l;
//     }
// }q1, q2;

inline int read()
{
    int x = 0, y = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') y = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + c - '0';
        c = getchar();
    }
    return x * y;
}

string solve()
{
    string res, res1, res2;
    deque<int> q1;
    deque<int> q2;
    q1.push_back(a[1]);
    bool bj = false;
    for(int i = 2; i <= 2 * n; i++)
    {
        if(a[i] == a[1]) bj = true;
        if(!bj) q1.push_back(a[i]);
        else q2.push_front(a[i]);
    }
    bj = false;
    for(int i = 1; i <= n; i++)
    {
        int a1 = 0, a2 = 0, b1 = 0, b2 = 0;
        if(!q1.empty())
        {
            a1 = q1.front();
            a2 = q1.back();
        }
        if(!q2.empty())
        {
            b1 = q2.front();
            b2 = q2.back();
        }
        if((int)q1.size() != 1 && a1 == a2 && a1)
        {
            res1 += 'L';
            res2 += 'L';
            q1.pop_front();
            q1.pop_back();
        }
        else if(a1 == b2 && a1)
        {
            res1 += 'L';
            res2 += 'R';
            q1.pop_front();
            q2.pop_back();
        }
        else if(a2 == b1 && a2)
        {
            res1 += 'R';
            res2 += 'L';
            q1.pop_back();
            q2.pop_front();
        }
        else if((int)q2.size() != 1 && b1 == b2 && b1)
        {
            res1 += 'R';
            res2 += 'R';
            q2.pop_front();
            q2.pop_back();
        }
        else
        {
            bj = true;
            break;
        }
    }
    if(!bj)
    {
        reverse(res2.begin(), res2.end());
        return res1 + res2;
    }
    res1.clear();
    res2.clear();
    q1.clear();
    q2.clear();
    q2.push_back(a[n * 2]);
    bj = false;
    for(int i = 2 * n - 1; i >= 1; i--)
    {
        if(a[i] == a[n * 2]) bj = true;
        if(!bj) q2.push_back(a[i]);
        else q1.push_front(a[i]);
    }
    for(int i = 1; i <= n; i++)
    {
        int a1 = 0, a2 = 0, b1 = 0, b2 = 0;
        if(!q1.empty())
        {
            a1 = q1.front();
            a2 = q1.back();
        }
        if(!q2.empty())
        {
            b1 = q2.front();
            b2 = q2.back();
        }
        if((int)q1.size() != 1 && a1 == a2 && a1)
        {
            res1 += 'L';
            res2 += 'L';
            q1.pop_front();
            q1.pop_back();
        }
        else if(a1 == b2 && a1)
        {
            res1 += 'L';
            res2 += 'R';
            q1.pop_front();
            q2.pop_back();
        }
        else if(a2 == b1 && a2)
        {
            res1 += 'R';
            res2 += 'L';
            q1.pop_back();
            q2.pop_front();
        }
        else if((int)q2.size() != 1 && b1 == b2 && b1)
        {
            res1 += 'R';
            res2 += 'R';
            q2.pop_front();
            q2.pop_back();
        }
        else return "NO";
    }
    reverse(res2.begin(), res2.end());
    return res1 + res2;
}

int main()
{
    // freopen("E:\\下载\\P7915_17.in", "r", stdin);
    // freopen("E:\\下载\\P7915_17.ans", "w", stdout);
    int t;
    scanf("%d", &t);
    while(t--)
    {
        n = read();
        for(int i = 1; i <= 2 * n; i++)
        {
            a[i] = read();
        }
        string ans = solve();
        if(ans == "NO")
            puts("-1");
        else
        {
            ans[ans.size() - 1] = 'L';
            cout << ans << endl;
        }
    }
    return 0;
}