[CSP-S 2021] 回文【模拟】

>Link

luogu P7915


>Description

[CSP-S 2021] 回文【模拟】_第1张图片
T ≤ 100 , n ≤ 1 0 5 T\le 100, n \le 10^5 T100,n105


>解题思路

麻掉了TAT 考场被T1卡了就没想后面的题,回来认真看了看没几分钟就想出来了,还是需要调整一下做题的方法,把所有题看了都想一想再开始打TAT(其实还是菜,不然也不会被卡

因为一个数只会出现两次,并且最终数列为回文数列,所以如果我们在前面确定了一个数,另一个数的位置也会确定
手玩一下就会发现,我们拿两个指针 l , r l,r l,r 指当前 a a a 数列的左右端点,操作就是左右端点不断靠近,根据上一行的性质,我们发现在 l , r l,r l,r 中间还有两个指针 l l , r r ll,rr ll,rr [ l l , r r ] [ll,rr] [ll,rr] 中的数的位置是已经根据前面的操作确定了的,且他们的位置组成一个单峰序列。还没操作但确定了位置的数一定是聚在一起的,根据操作规则和回文的性质易证。
如果 l l l r r r 上的数,它另一个对应的数在 [ l l , r r ] [ll,rr] [ll,rr] 的左右边,说明就是可以操作的,对 l , r , l l , r r l,r,ll,rr l,r,ll,rr 这些指针进行移动,注意要记录下 [ l l , r r ] [ll,rr] [ll,rr] 内的位置,便于后续的操作;否则不能达成。为了让操作的字典序最小,我们就尽量用左操作。


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 500010
using namespace std;

int T, n, m, a[2 * N], l, r, ll, rr, pos[2 * N];
char ans[2 * N];

bool solve ()
{
	if (!ll) return 0;
	for (int i = 2; i <= n; i++)
	{
		if (a[l] == a[ll - 1] && l < ll - 1)
		{
			l++, ll--;
			pos[ll] = 2 * n - i + 1;
			ans[i] = 'L';
		}
		else if (a[l] == a[rr + 1] && l < rr + 1)
		{
			l++, rr++;
			pos[rr] = 2 * n - i + 1;
			ans[i] = 'L';
		}
		else if (a[r] == a[ll - 1] && r > ll - 1)
		{
			r--, ll--;
			pos[ll] = 2 * n - i + 1;
			ans[i] = 'R';
		}
		else if (a[r] == a[rr + 1] && r > rr + 1)
		{
			r--, rr++;
			pos[rr] = 2 * n - i + 1;
			ans[i] = 'R';
		}
		else return 0;
	}
	for (int i = n + 1; i <= 2 * n; i++)
	  if (pos[ll] <= pos[rr]) ll++, ans[i] = 'L';
	  else rr--, ans[i] = 'R';
	return 1;
}
void work ()
{
	scanf ("%d", &n);
	for (int i = 1; i <= 2 * n; i++) scanf ("%d", &a[i]);
	
	memset (pos, 0, sizeof (pos));
	ll = rr = 0;
	for (int i = 2; i <= 2 * n; i++)
	  if (a[i] == a[1])
	  {
	  	ll = rr = i;
	  	pos[i] = 2 * n;
		break;
	  }
	l = 2, r = 2 * n;
	ans[1] = 'L';
	if (solve ())
	{
		for (int i = 1; i <= 2 * n; i++)
		  putchar (ans[i]);
		putchar (10);
		return;
	}
	
	memset (pos, 0, sizeof (pos));
	ll = rr = 0;
	for (int i = 1; i < 2 * n; i++)
	  if (a[i] == a[2 * n])
	  {
	  	ll = rr = i;
	  	pos[i] = 2 * n;
		break;
	  }
	l = 1, r = 2 * n - 1;
	ans[1] = 'R';
	if (solve ())
	{
		for (int i = 1; i <= 2 * n; i++)
		  putchar (ans[i]);
		putchar (10);
		return;
	}
	putchar ('-'), putchar ('1'), putchar (10);
}

int main()
{
//	freopen ("check.out", "w", stdout);
	scanf ("%d", &T);
	while (T--)
	  work ();
	return 0;
}

你可能感兴趣的:(贪心;暴力;模拟,图论,c++,算法)