Easy Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 643 Accepted Submission(s): 185
Problem Description
soda has a string containing only two characters – ‘(’ and ‘)’. For every character in the string, soda wants to know the number of valid substrings which contain that character.
Note:
An empty string is valid. If S is valid, (S) is valid. If U,V are valid, UV is valid.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
A string s consisting of ‘(’ or ‘)’ (1≤|s|≤106).
Output
For each test case, output an integer m=∑i=1|s|(i⋅ansi mod 1000000007), where ansi is the number of valid substrings which contain i-th character.
Sample Input
2
()()
((()))
Sample Output
20
42
Hint
For the second case, ans={1,2,3,3,2,1}, then m=1⋅1+2⋅2+3⋅3+4⋅3+5⋅2+6⋅1=42
其覆盖方案分为两种类型:
例子:”…()(…()()()…)()…” (根据合法序列是否覆盖了“包括了它的最小的括号对”进行分类)
第一部分:倘若它的合法序列覆盖了整个括号对,那么这一部分的方案数等于括号对的总方案数
第二部分:倘若它的合法序列在括号对内,那么这种合法序列一定覆盖了其两边有与其“同级别"(即互不包含)的括号对,设左边有a个,右边有b个,则这一部分的方案数为 (a + 1) * (b + 1)
合并在一起就求出了每个位置的方案数
做法:计算出第 i 个括号的匹配括号位置 match[i],包含它的括号对的左括号位置 pre[i],以及:
对于左括号,其右边的“同级别”的括号个数(包括自己)forward[i] = forward[match[i]+1] + 1
对于右括号,其左边的“同级别”的括号个数(包括自己)backward[i] = backward[match[i]-1] + 1
其中,match[i] 和 pre[i] 可以对序列用栈扫一遍求出,具体做法是:遇到左括号压进栈,遇到右括号就弹栈,之前的栈顶元素与当前元素相互 match,现在的栈顶元素成为当前元素及其 match 的 pre。
最后,ans[i] = ans[match[i]] = ans[pre[i]] + forward[i] * backward[match[i]]
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000100;
const int maxm=1010;
const int MOD=1000000007;
const int INF=0x3f3f3f3f;
char s[maxn];
int N;
int match[maxn],pre[maxn],R[maxn],L[maxn];
LL ans[maxn];
int st[maxn];
void solve(){
for(int i=1;i<=N;i++){
s[i]=(s[i]==')');
}
memset(match,0,sizeof(int)*(N+2));
memset(pre,0,sizeof(int)*(N+2));
memset(L,0,sizeof(int)*(N+2));
memset(R,0,sizeof(int)*(N+2));
int top=0;
for(int i=1;i<=N;i++){
if(s[i]==0){
st[++top]=i;
} else if(top){
match[st[top]]=i;
match[i]=st[top];
--top;
if(top){
pre[match[i]]=st[top];
}
}
}
for(int i=N;i>0;i--){
if(s[i]==0&&match[i]){
R[i]=R[match[i]+1]+1;
}
}
for(int i=1;i<=N;i++){
if(s[i]==1&&match[i]){
L[i]=L[match[i]-1]+1;
}
}
memset(ans,0,sizeof(LL)*(N+2));
LL res=0;
for(int i=1;i<=N;i++){
if(s[i]==0&&match[i]){
ans[i]=ans[match[i]]=(ans[pre[i]]+1LL*R[i]*L[match[i]]%MOD)%MOD;
}
res+=1LL*i*ans[i]%MOD;
}
printf("%I64d\n",res);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%s",s+1);
N=strlen(s+1);
solve();
}
return 0;
}