题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5357
题意:
给一个只含‘(’‘)’两个字符的字符串,问每个括号出现在几个合法子串中,子串合法的要求为子串内括号匹配
思路:
题目给出的序列未必合法,若不合法,切分成一个个独立的区间处理即可,因为两个独立区间间不可能形成新的合法子串
如上图,把每个独立区间抽象为树的形态,添加虚根是为了在出现()()()这种独立区间时仍能保持树形态,上图树的每个结点对应序列中的一对匹配的括号,观察树可得
ans[i] = ans[fa[i]] + L[i] * R[i]
其中fa[i]为i的父结点,L[i]为i结点的左兄弟个数加一,R[i]为结点的右兄弟个数加一
因为每个结点的ans值与子结点无关,所以实际操作时只需要BFS处理树即可,实现方式为两次遍历,第一次遍历预处理出每个括号的L与R值,以及与之匹配的括号所在位置,第二次遍历直接就可以算出ans数组
最后输出 ∑ans[i]*i%MOD即可,注意这里是求模完再加,答案是一个long long的值,我就是写成了(∑ans[i]*i)%MOD查了很久才找到哪里错……
代码:
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<functional>
#pragma comment(linker, "/STACK:102400000,102400000")//C++
using namespace std;
const double eps = 1e-8;
const long long INF = 0x7FFFFFFFFFFFFFFF;
const int MAXINT = 0x7fffffff;
const int MOD = 1000000007;
const int MAXSIZE = 1000000 + 50;
int fa[MAXSIZE];
int pos[MAXSIZE];
int ans[MAXSIZE];
int l[MAXSIZE];
int r[MAXSIZE];
int son[MAXSIZE];
int stackself[MAXSIZE];
int stackcur = 0;
void s_push(int x){
stackself[++stackcur] = x;
}
void s_pop(){
stackcur--;
}
int s_top(){
return stackself[stackcur];
}
int main(){
int total;
cin>>total;
char str[MAXSIZE];
ans[0] = 0;
while (total--){
scanf("%s",str+1);
int len = strlen(str+1);
memset(ans,0,sizeof(int)*(len+5));
memset(fa,0,sizeof(int)*(len+5));
memset(son,0,sizeof(int)*(len+5));
memset(l,0,sizeof(int)*(len+5));
stackcur = 0;
s_push(0);
int k = 1;
for (int i=1;i<=len;++i){
if (stackcur==1 && str[i] == ')'){
for (int j=k;j<i;++j){
if (str[j] == ')' || l[j]==0) continue;
r[j] = son[fa[j]] - l[j] + 1;
}
k = i;
son[0] = 0;
continue;
}
if (str[i] == ')'){
int t = s_top();
s_pop();
pos[t] = i;
pos[i] = t;
fa[t] = s_top();
l[t] = son[s_top()] + 1;
son[s_top()]++;
}
else{
s_push(i);
}
}
for (int j=k;j<=len;++j){
if (str[j] == ')' || l[j]==0) continue;
r[j] = son[fa[j]] - l[j] + 1;
}
for (int i=1;i<=len;++i){
if (str[i]==')' || l[i] == 0) continue;
ans[i] = (ans[fa[i]] + (long long)(l[i])*r[i]) % MOD;
ans[pos[i]] = ans[i];
}
long long sum = 0;
for (int i=1;i<=len;++i)
sum += (long long)(ans[i])*i % MOD;
cout<<sum<<endl;
}
return 0;
}