arc141C - Bracket and Permutation
半年没写题解了,写一篇来冒个泡
题目大意
给出长2n的排列p和q,求长2n的括号序列S(左右括号分别n个,不要求合法),使得在所有将S带编号重排得到合法括号序的编号排列中,p是字典序最小的排列,q是字典序最大的排列
题解
很神仙的题,完全没有思路,题解也没说人话
把S写成折线,一部分在y=0上,一部分在y=0下
观察可得,在求字典序最小的p时,在y=0上的对应一段连续编号,在y=0下的对应 最近的左括号,最近的右括号,次近的左括号,次近的右括号…… 这样的序列
(原理可以模拟,把左右括号分别排序,若sum>0则取两者位置最前的,否则取左括号,因为sum一直>=0所以每次都会取最小的,即按顺序取)
这样可以按左右左右的顺序得到在y=0下的所有括号(在y=0上的求不出来)
同理,用q可以求出在y=0上的所有括号,二者拼起来就是答案
具体实现,就是找p[i]>p[i+1]和q[i]<q[i+1]的,分别设为左右括号,没填完就-1,最后check一下
(因为对于p来说,在y=0下的一定是先取后面的左括号,再取前面的右括号,故p[i]>p[i+1],q同理)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;
int n,i,j,k,l,sum;
int p[400001],q[400001];
int P[400001],Q[400001];
int a[400001],A[200001],B[200001];
void Exit()
{
printf("-1\n");
exit(0);
}
void check1()
{
i=j=1,l=0;sum=0;
while (i<=n || j<=n)
{
if (!sum)
{
if (i<=n)
P[++l]=A[i++],++sum;
else
Exit();
}
else
{
if (i<=n)
{
if (j<=n)
{
if (A[i]<B[j])
P[++l]=A[i++],++sum;
else
P[++l]=B[j++],--sum;
}
else
P[++l]=A[i++],++sum;
}
else
P[++l]=B[j++],--sum;
}
}
fo(i,1,n*2) if (p[i]!=P[i]) Exit();
}
void check2()
{
i=j=n,l=0;sum=0;
while (i || j)
{
if (!sum)
{
if (i)
Q[++l]=A[i--],++sum;
else
Exit();
}
else
{
if (i)
{
if (j)
{
if (A[i]>B[j])
Q[++l]=A[i--],++sum;
else
Q[++l]=B[j--],--sum;
}
else
Q[++l]=A[i--],++sum;
}
else
Q[++l]=B[j--],--sum;
}
}
fo(i,1,n*2) if (q[i]!=Q[i]) Exit();
}
int main()
{
#ifdef file
freopen("arc141C.in","r",stdin);
#endif
scanf("%d",&n);
fo(i,1,n*2) scanf("%d",&p[i]);
fo(i,1,n*2) scanf("%d",&q[i]);
for (i=1; i<=n*2; i+=2) if (p[i]>p[i+1]) a[p[i]]=1,a[p[i+1]]=-1;
for (i=1; i<=n*2; i+=2) if (q[i]<q[i+1]) a[q[i]]=1,a[q[i+1]]=-1;
fo(i,1,n*2) if (!a[i]) Exit();
k=l=0;
fo(i,1,n*2) if (a[i]==1) A[++k]=i; else B[++l]=i;
check1();
check2();
fo(i,1,n*2)
printf((a[i]==1)?"(":")");
printf("\n");
fclose(stdin);
fclose(stdout);
return 0;
}