这一题好神啊,看了半天题解还是不会做。
设a[i]表示以i开头的合法括号序列的个数,b[i]表示以i结尾的合法括号序列的个数,a只考虑左括号,B反之。
设up[i]表示包括i的极小匹配序列的左端且up[i]!=i;
记match[i]表示i括号匹配的位置。
那么ans[i]=ans[match[i]]=ans[up[i]]+a[i]*b[match[i]];
ab怎么求呢?
a[i]=a[match[i]+1]+1,b[i]=b[match[i]-1]+1;
至于up,当遇到一个右括号时,弹出栈顶的左括号,这是vis,此时栈顶的元素便是up;
至此问题便完美解决了。代码好丑。WA了许许多多次。%%__debug大神。
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<stack>
using namespace std;
const int MAXN=1e6+20;
const int zqf=1000000007;
stack<int> st;
int vis[MAXN],a[MAXN],b[MAXN],up[MAXN],t;
long long ans[MAXN];
int len;
string s;
void clear(int *t,int k)
{
for(int i=0;i<len+10;i++)t[i]=k;
}
void clearL(long long *t)
{
for(int i=0;i<len+10;i++)t[i]=0;
}
void init()
{
clearL(ans);
clear(a,0);
clear(b,0);
clear(vis,-1);
clear(up,-1);
while(!st.empty())st.pop();
}
void make_vis()
{
int p=0;
for(int i=0;i<s.size();i++)
{
if(s[i]=='(')
{st.push(i);p=i;break;}
}p++;
while(p<=s.size()-1)
{
if(s[p]=='(')st.push(p);
else
{
int k=st.empty()?0:st.top();
if(st.empty())
{p++;continue;}
vis[p]=k;
vis[k]=p;
if(!st.empty())st.pop();
up[p]=up[vis[p]]=st.empty()?-1:st.top();
}
p++;
}
}
void Read(int& x)
{
x=0;
char c;int flag=0;
while(c=getchar())
{
if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
else if(flag)break;
}
}
int main()
{
freopen("rand.out", "r", stdin);
freopen("w.out", "w", stdout);
Read(t);
while(t--)
{
char ss[MAXN]={};
scanf("%s",ss);
string sss(ss);
s=sss;
len=s.size();
init();
long long loe=0;
make_vis();
for(int i=0;i<s.size();i++)
if(s[i]==')'&&vis[i]!=-1)
b[i]=b[vis[i]-1]+1;
for(int j=s.size()-1;j>=0;j--)
if(s[j]=='('&&vis[j]!=-1)
a[j]=a[vis[j]+1]+1;
for(int i=0;i<s.size();i++)
{
if(up[i]!=-1&&!ans[i]&&vis[i]!=-1)
ans[i]=ans[vis[i]]=ans[up[i]]+(long long)a[i]*b[vis[i]];
else if(up[i]==-1&&!ans[i]&&vis[i]!=-1)
ans[i]=ans[vis[i]]=(long long)a[i]*b[vis[i]];
}
for(int i=0;i<s.size();i++)
{
loe=(loe+ans[i]*(i+1)%zqf);
}
printf("%I64d\n",loe);
}
}