Dyd's Blog

He who has a strong enough why can bear almost any how.

luoguP7915 [CSP-S 2021] 回文

一直死想 dp ,结果是分讨 + 贪心

回文

思路

拿到感觉是 dp ,然后尝试把 $a$ 或者 $b$ 的状态压缩表示出来,一直没法,以为是自己没有找出关键信息,然后一瞟题解,第一句话:把第一步取 $L$ 和第一步取 $R$ 分类讨论……马上就开始打贪心

发现就是给 $a$ 分配一个单峰的下标,且保证对于 $a_i = a_j$ , $i$ 的下标和 $j$ 的下标和为 $2n + 1$ ;那么当第一个取的确定了后,这个峰(最大值)就定了,用两个指针维护从小到大,两个指针维护从大到小,贪心尽可能取 $L$ 即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <bits/stdc++.h>
const int N = 5e5 + 100;
int n;
int a[N << 1], b[N], c[N << 1];
char ans[N << 1];
bool work(int l, int r, int bl, int br)
{
for (int i = 2; i <= n; ++i)
{
if (l < bl && c[l] == bl)
{
ans[i] = 'L', ans[(n << 1) - i + 1] = 'L';
++l, --bl;
}
else if (l < br && c[l] == br)
{
ans[i] = 'L', ans[(n << 1) - i + 1] = 'R';
++l, ++br;
}
else if (r > bl && c[r] == bl)
{
ans[i] = 'R', ans[(n << 1) - i + 1] = 'L';
--r, --bl;
}
else if (r > br && c[r] == br)
{
ans[i] = 'R', ans[(n << 1) - i + 1] = 'R';
--r, ++br;
}
else return false;
}
return true;
}
bool solve()
{
scanf("%d", &n);
for (int i = 1; i <= (n << 1); ++i) scanf("%d", &a[i]), b[a[i]] = i;
for (int i = 1; i <= (n << 1); ++i) if (b[a[i]] != i)
{
c[i] = b[a[i]];
c[b[a[i]]] = i;
}
ans[1] = 'L', ans[n << 1] = 'L';
if (work(2, n << 1, c[1] - 1, c[1] + 1)) return true;
ans[1] = 'R', ans[n << 1] = 'L';
if (work(1, (n << 1) - 1, c[n << 1] - 1, c[n << 1] + 1)) return true;
return false;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
if (solve())
{
ans[(n << 1) + 1] = '\0';
puts(ans + 1);
}
else puts("-1");
return 0;
}