题解 Bracket

题目描述

题目链接
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;
}
//))))(()(((
//)(())(
//((()))))(()(
//))))(()((())))()(

猜你喜欢

转载自www.cnblogs.com/ezlmr/p/13167993.html