CSP 2021 游记 & 题解

题解

Pro1 : 廊桥分配

思路:

Pro2 : 括号序列

思路:

Pro3 : 回文

思路:左侧第一个进队的,序列中另一个它(位置为pl)一定最后一个从左侧出队,这样把整段序列分为A[1 - pl]和B[pl+1 - 2*n],那么,此序列成立,当且仅当每次A、B的头或末有相同的数字。

模拟:

5
4 1 2 4 5 3 1 2 3 5

先拆成左右A、B

A: 4 1 2 4
B: 5 3 2 1 3 5 (注意要反着拆)

接着,我们依次取出:

(4,4) (5,5) (3,3) (1,1) (2,2)

第一个数字是A序列的,就在前面加一个L,否则加一个R
第二个数字插在后面,其他同理

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<iomanip>
#include<cstring>
#include<string>
#define N 500010
using namespace std;
int T, n, a[N << 1], cl = 1, cr = 1;
bool L[N << 1], R[N << 1];

long long read(){
	long long x=0,h=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*h;
}

int pd (int x, int y) {
	if (x == -1 && y == -1)return -1;
	if (x == -1) return 2;
	return 1;
}

int main(){
	T = read();
	while (T --) {
		cl = cr = 1; // 记得恢复状态!!!
		n = read();
		for (int i = 1; i <= n << 1; i ++) a[i] = read();
		
		int pl = 0, pr = 0;
		for (int i = 1; i <= (n << 1); i ++) {
			if (a[i] == a[1] && i != 1) pl = i; 
			if (a[i] == a[n << 1] && i != n << 1) pr = i;
			if(pl && pr) break;
		}
/*
细节一:若给出序列首位相同,则pl=n*2,pr=1。不能写成这样:
                for (int i = 2; i <= (n << 1) - 1; i ++) {
			if (a[i] == a[1]) pl = i;
			if (a[i] == a[n << 1]) pr = i;
			if(pl && pr) break;
		}
*/
		
//		cout<<pl<<"==="<<pr<<endl;
		
		// SOL1
		for (int l1 = 1, r1 = pl, l2 = n << 1, r2 = pl + 1; l1 <= r1 || r2 <= l2; ) {  
                // 细节二:是||不是&&,因为A或B序列可能有一个已经删空了,但另一个还能删。
                // 细节三:因为B序列是反过来的,所以l2=n*2,r2=pl+1。
			if (a[l1] == a[r1] && l1 < r1) { // 细节四:判断顺序应遵从答案字典序最小的原则,故为(l1,r1)(l1,r2)(l2,r1)(l2,r2),这样可以保证字典序最小
				L[cl] = 1; L[n * 2 - cl + 1] = 1;
				l1 ++; r1 --;
			}
			else if (a[l1] == a[r2]) {
				L[cl] = 1; L[n * 2 - cl + 1] = 0;
				l1 ++; r2 ++;
			}
			else if (a[l2] == a[r1]) {
				L[cl] = 0; L[n * 2 - cl + 1] = 1;
				l2 --; r1 --;
			}
			else if (a[l2] == a[r2] && l2 > r2) {
				L[cl] = 0; L[n * 2 - cl + 1] = 0;
				l2 --; r2 ++;
			}
			else {
				cl = -1; break; // 细节五:如果发现无法配对,立即退出
			}
			cl ++;
		}
//		cout<<cl<<endl;
		
		// SOL2
                // 细节六:在复制第二遍的时候,一定要注意该改的改了没,如'L'->'R';'pl'->'pr';'cl'->'cr'
		for (int l1 = 1, r1 = pr, l2 = n << 1, r2 = pr + 1; l1 <= r1 || r2 <= l2; ) {
			if (a[l1] == a[r1] && l1 < r1) {
				R[cr] = 1; R[n * 2 - cr + 1] = 1;
				l1 ++; r1 --;
			}
			else if (a[l1] == a[r2]) {
				R[cr] = 1; R[n * 2 - cr + 1] = 0;
				l1 ++; r2 ++;
			}
			else if (a[l2] == a[r1]) {
				R[cr] = 0; R[n * 2 - cr + 1] = 1;
				l2 --; r1 --;
			}
			else if (a[l2] == a[r2] && l2 > r2) {
				R[cr] = 0; R[n * 2 - cr + 1] = 0;
				l2 --; r2 ++;
			}
			else {
				cr = -1; break;
			}
			cr ++;
		}
//		cout<<cr<<endl;
		
		int tp = pd(cl, cr);
		if (tp == 1) {
			for (int i = 1; i <= 2 * n; i ++) {
				putchar(L[i] == 1 ? 'L':'R');
			}
			putchar('\n');
		}
		else if (tp == 2) {
			for (int i = 1; i <= 2 * n; i ++) {
				putchar(R[i] == 1 ? 'L':'R');
			}
			putchar('\n');
		}
		else {
			printf("-1\n");
		}
	}
	return 0;
}

Pro4 : 交通规划

思路:

游记

posted @ 2021-11-02 00:18  Charisk_FOD  阅读(62)  评论(0)    收藏  举报