半年沒寫題解了,寫一篇來冒個泡
題目大意
給出長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;
}