POI2020+ R3 Nawiasowania

First Post:

Last Update:

Word Count:
492

Read Time:
2 min

Page View: loading...

被普及但是国家集训队选手都不会的题暴打了。

题意

给定长度为 的排列 ,要求构造合法括号序列 使得 同样合法。

思路

构造要满足两个同时合法,感觉非常困难,不妨考虑强制使得其中一个合法然后让另一个 自求多福 尽可能最优。

不妨从前往后构造,因为我们要给构造另一个序列尽可能多的自由度,所以试着往一个前缀里加东西。如果这样,要很好地使第一个序列合法,我们的修改就得是右括号变成左括号。

首先令 ,然后考虑 我们可以随意替换其中一个变成左括号。这样每次我们加入两个右括号,然后再替换出一个左括号,显然我们第一个序列就合法了。

然后第二个序列想要构造得比较好,那么就得把左括号尽可能地往左放,于是我们维护一个堆存所有的右括号的 ,然后选一个最小的替换成左括号,这样就可以得到一个尽可能优的第二个序列了。

什么,你要我证明这个东西足够优?对不起,咕咕咕。

最后判无解并输出。

CODE

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
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000010,FSIZE=1<<26;
int n,a[N],sum;
bool ans[N];
priority_queue<int> h;
char BuF[FSIZE],*InF=BuF;
template<typename T>void read(T &x){
for(;*InF<33;++InF);
for(x=0;*InF>32;x=x*10+(*InF++^48));
}
void no(){printf("NIE");exit(0);}
int main(){
fread(BuF,1,FSIZE,stdin);
read(n);
for(int i=1;i<=n;++i) read(a[i]);
h.push(-a[1]);
for(int i=1;i<=n;){
ans[-h.top()]=1;
h.pop();
h.push(-a[++i]);
h.push(-a[++i]);
}
for(int i=1;i<=n;++i)
if((sum+=ans[i]*2-1)<0) no();
if(sum) no();
for(int i=1;i<=n;++i) putchar(ans[i]?'(':')');
return(0);
}