首页 > 其他分享 >AtCoder Regular Contest 141 C Bracket and Permutation

AtCoder Regular Contest 141 C Bracket and Permutation

时间:2023-06-13 22:00:18浏览次数:56  
标签:AtCoder typedef Contest int 141 long 括号 maxn 2i

洛谷传送门

AtCoder 传送门

考虑给出 \(S\),如何求 \(P, Q\)。先考虑 \(P\),那我们肯定想让 \(P\) 的每一项都尽量往前靠。设 \([1, k]\) 为合法括号串,\(S_{k + 1} = \texttt{)}\),那 \(P\) 的前 \(k\) 项依次为 \(1 \sim k\),第 \(k + 1\) 项不能为 \(k + 1\) 了,那找到 \(k + 1\) 之后的第一个左括号,设其位置为 \(p\),那 \(P_{k + 1} = p, P_{k + 2} = k + 1\)。一直如此直到某个时刻,前缀左括号数和右括号数相等,并且下一个字符是左括号,那就回到了一开始的情况,从这个左括号往后填。这样可以求出 \(P\),求 \(Q\) 类似地可以从后往前就变成了求 \(P\)。

考虑画出折线图,那可以发现,\(x = 0\) 上方部分可以依次填不需要改动顺序,\(x = 0\) 下方就先找到从左往右第一个之前没选过的左括号,和第一个之前没选过的右括号配对。

现在考虑原题,给出 \(P, Q\),构造 \(S\)。先暂时不考虑无解情况。发现如果 \(P_{2i - 1} < P_{2i}\),这一段一定在 \(x = 0\) 上方;如果 \(P_{2i - 1} > P_{2i}\),这一段一定在 \(x = 0\) 下方,并且可以确定 \(S_{2i - 1} = \texttt{(}, S_{2i} = \texttt{)}\)。那我们可以确定,折线在 \(x = 0\) 下方部分的 \(S\) 了。这时候我们惊喜地发现,因为求 \(Q\) 的过程是反过来的,所以可以类似地,根据 \(Q_{2i - 1} < Q_{2i}\) 确定折线在 \(x = 0\) 上方部分的 \(S\)。两个合在一起,我们发现 \(S\) 可以被唯一确定!

但是你先别急,还没做完。因为我们发现有很多繁琐的无解情况需要特判。若 \(S\) 还有没被确定的部分,就一定无解;否则可以根据 \(S\) 求出 \(P, Q\),验证是否和题目给出的 \(P, Q\) 一致即可。

时间复杂度是优秀的 \(O(n)\)。

code
// Problem: C - Bracket and Permutation
// Contest: AtCoder - AtCoder Regular Contest 141
// URL: https://atcoder.jp/contests/arc141/tasks/arc141_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 1000100;

int n, a[maxn], b[maxn], c[maxn];
char s[maxn];

void solve() {
	scanf("%d", &n);
	n <<= 1;
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &a[i]);
	}
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &b[i]);
	}
	for (int i = 1; i <= n; i += 2) {
		if (a[i] > a[i + 1]) {
			s[a[i]] = '(';
			s[a[i + 1]] = ')';
		}
	}
	for (int i = 1; i <= n; i += 2) {
		if (b[i] < b[i + 1]) {
			if (s[b[i]] == ')' || s[b[i + 1]] == '(') {
				puts("-1");
				return;
			}
			s[b[i]] = '(';
			s[b[i + 1]] = ')';
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (!s[i]) {
			puts("-1");
			return;
		}
	}
	int k = 0, lst = 1, tot = 0;
	for (int i = 1; i <= n; ++i) {
		k += (s[i] == '(' ? 1 : -1);
		if (!k) {
			if (s[lst] == '(') {
				for (int j = lst; j <= i; ++j) {
					c[++tot] = j;
				}
			} else {
				vector<int> vl, vr;
				for (int j = lst; j <= i; ++j) {
					if (s[j] == '(') {
						vl.pb(j);
					} else {
						vr.pb(j);
					}
				}
				for (int j = 0; j < (i - lst + 1) / 2; ++j) {
					c[++tot] = vl[j];
					c[++tot] = vr[j];
				}
			}
			lst = i + 1;
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (c[i] != a[i]) {
			puts("-1");
			return;
		}
	}
	k = 0;
	lst = n;
	tot = 0;
	for (int i = n; i; --i) {
		k += (s[i] == '(' ? 1 : -1);
		if (!k) {
			if (s[lst] == '(') {
				for (int j = lst; j >= i; --j) {
					c[++tot] = j;
				}
			} else {
				vector<int> vl, vr;
				for (int j = lst; j >= i; --j) {
					if (s[j] == '(') {
						vl.pb(j);
					} else {
						vr.pb(j);
					}
				}
				for (int j = 0; j < (lst - i + 1) / 2; ++j) {
					c[++tot] = vl[j];
					c[++tot] = vr[j];
				}
			}
			lst = i - 1;
		}
	}
	for (int i = 1; i <= n; ++i) {
		if (c[i] != b[i]) {
			puts("-1");
			return;
		}
	}
	printf("%s\n", s + 1);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}


一定要多思考,不能怠惰啊。

标签:AtCoder,typedef,Contest,int,141,long,括号,maxn,2i
From: https://www.cnblogs.com/zltzlt-blog/p/17478813.html

相关文章

  • AtCoder Beginner Contest 273(E)
    AtCoderBeginnerContest273(E)E(链式结构,思维)E题目大意就是原本有一个空的序列,我们后面会进行\(q\)次操作,每次操作我们都需要输出此时的序列的最后数字下面有几种操作\(ADD\)\(x\),代表在这在这个序列的最后面添加一个\(x\)\(DELETE\),代表如果此时的序列存在数字的话,......
  • AtCoder Beginner Contest 265 F Manhattan Cafe
    洛谷传送门AtCoder传送门考虑dp,\(f_{i,j,k}\)表示考虑到第\(i\)维,\(\sum\limits_{x=1}^i|p_x-r_x|=j,\sum\limits_{x=1}^i|q_x-r_x|=k\)的方案数。转移是容易的,枚举\(r_i\)即可,\(f_{i,j,k}=\sum\limits_rf_{i-1,j-|p_i-r|,k-|q_i-r|}......
  • Atcoder Beginner Contest 301
    A-OverallWinner题目大意A和T两人玩游戏,给定一串只由A和T组成的字符串,如果第i个字符是A,则A赢得第i轮的胜利,反之则T赢;当遍历完整个字符串后,谁赢的轮数多谁就是最终赢家,如果一样则谁最先达到该轮数谁赢,输出赢家的名字解题思路签到题不多嗦了神秘代码......
  • AtCoder Beginner Contest 278 ABCDE
    AtCoderBeginnerContest278A-ShiftProblemStatement题意:给你一个长度为n的序列,让你移走前面k个后面补k个0。Solution思路:按照题意模拟即可。#include<bits/stdc++.h>usingnamespacestd;inta[1100];intmain(){ intn,k; cin>>n>>k; k=min(k,n); for(int......
  • UNIQUE VISION Programming Contest 2023 New Year (AtCoder Beginner Contest 287) A
    UNIQUEVISIONProgrammingContest2023NewYear(AtCoderBeginnerContest287)A-MajorityProblemStatement题意:给你n个字符串,字符串是For表示agree,字符串Against表示disagree,让你判断最终是否通过。Solution思路:统计For和Against的数量,比较一下即可。#include......
  • AtCoder Beginner Contest 284 ABCDE
    AtCoderBeginnerContest284A-SequenceofStringsProblemStatement题意:给你n个字符串,让你倒序输出Solve#include<bits/stdc++.h>usingnamespacestd;constintN=20;strings[N];intmain(){ intn; cin>>n; for(inti=1;i<=n;i++) cin>>s......
  • Atcoder-AGC033C
    看到这道题,是个博弈论,没见过树上的,于是想到在数列里的博弈论,又联想到树的特殊形式————链。于是我们来讨论一下链的情况(对于没有硬币的点,我们就视为它被删掉了):讨论链的情况发现若是选择两端的点,顶点数会减一;若是选择中间的点,顶点数会减二。现在我们站在链的角度来思考......
  • AtCoder Beginner Contest 302
    A-Attack题目大意给定两个数a和b,问我们需要进行多少次a-b,才能让a小于等于0解题思路签到题不多嗦了神秘代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=1e6+10;signedmain(){inta,b,c;cin>>a>>b;if(a%b......
  • AtCoder Beginner Contest 305 题解
    https://atcoder.jp/contests/abc305/tasks_printE-ArtGalleryonGraph冷知识:md这题赛时没做出来/cy刚看到题:这是什么题啊,\(K,h\)都\(1e5\)能做吗/fn确实能做。考虑类似SPFA的操作。设\(a_x\)表示\(x\)还可以对距离最多为\(a_x\)的点产生贡献,然后就直接......
  • AtCoder Beginner Contest 258 F Main Street
    洛谷传送门AtCoder传送门发现这题有个远古的WA就来改了(发现走法很多种,不想分类讨论,考虑最短路。设起点编号为\(1\),终点为\(11\)。\(x=Bn\)和\(y=Bn\)把坐标系分成了若干块。考虑过起点作一条平行于\(Ox\)的直线,与左右两条\(x=Bn\)的线有两个交点,给它们编号......