题目描述
题目链接
Tips: 这题求的是最短的字典序最小的括号序列,而不是字典序最小的括号序列,被坑了
题解
前置知识
为了解决本题,你应该要会
- 栈求括号匹配问题
- 后缀排序(求后缀排名)
思路
代码
#include<iostream>
#include<cstdio>
#include<stack>
#include<vector>
using namespace std;
int n,rk[2000005],sa[1000005];
int a[2000005],b[2000005],c[2000005],d[2000005],e[2000005];
bool kuo[2000005];
int hao[1000005];
stack<int>s;
vector<int>g;
void SA(int x) {
for(int i=0; i<=n; i++)a[i]=b[i]=c[i]=d[i]=e[i]=0;
for(int i=1; i<=n; i++)a[rk[i]]++,b[rk[i+x]]++;
for(int i=1; i<=n; i++)a[i]+=a[i-1],b[i]+=b[i-1];
for(int i=1; i<=n; i++)c[b[rk[i+x]]--]=i;
for(int i=n; i>=1; i--)d[a[rk[c[i]]]--]=c[i];
int id=0;
for(int i=1; i<=n; i++)e[d[i]]=(rk[d[i]]==rk[d[i-1]]&&rk[d[i]+x]==rk[d[i-1]+x]?e[d[i-1]]:++id);
for(int i=1; i<=n; i++)rk[i]=e[i];
if(id==n)return;
SA(x<<1);
}
int main() {
// freopen("bracket10.in","r",stdin);
// freopen("test.out","w",stdout);
char ch;
while(++n) {
ch=getchar();
if(ch==' ')cout<<n;
if(ch!='('&&ch!=')')break;
kuo[n]=(ch==')');
}
n--;
for(int i=n+1; i<=n+n; i++)kuo[i]=kuo[i-n];
n=n+n;
for(int i=1; i<=n; i++)a[kuo[i]]=1;
a[1]+=a[0];
for(int i=1; i<=n; i++)rk[i]=a[kuo[i]];
SA(1);
n=n/2;
for(int i=1; i<=n; i++) {
if(kuo[i]) {
if(!s.empty())s.pop();
else {
g.push_back(i);
hao[i]=1;
}
} else s.push(i);
}
int cnt=g.size(),st=s.size(),b=g[cnt-1],fin=n,en=1;
if(cnt>=st)b=(st==0?0:g[st-1]);
if(st>cnt)en+=(st-cnt);
while(!s.empty()){
hao[s.top()]=1;
if(s.size()==en)fin=s.top();
s.pop();
}
int id=0,l=0,r=0;
rk[0]=0x3f3f3f3f;
for(int i=1;i<=b;i++)if(hao[i]==0)kuo[i]?r++:l++;
for(int i=b+1; i<=fin; i++){
if(l==r)if(rk[i]<rk[id])id=i;
if(hao[i]==0)kuo[i]?r++:l++;
}
for(int i=1; i<=cnt-st; i++)printf("(");
for(int i=1; i<=n; i++)printf("%c",(kuo[i+id-1]?')':'('));
for(int i=1; i<=st-cnt; i++)printf(")");
return 0;
}
//))))(()(((
//)(())(
//((()))))(()(
//))))(()((())))()(