【51nod 1791】 合法括号子段
2017-08-11 21:09
441 查看
有一个括号序列,现在要计算一下它有多少非空子段是合法括号序列。
合法括号序列的定义是:
1.空序列是合法括号序列。
2.如果S是合法括号序列,那么(S)是合法括号序列。
3.如果A和B都是合法括号序列,那么AB是合法括号序列。
第一行有一个整数T(1<=T<=1100000),表示测试数据的数量。
接下来T行,每一行都有一个括号序列,是一个由'('和')'组成的非空串。
所有输入的括号序列的总长度不超过1100000。
设左括号为-1,右括号为+1,求得一个前缀和数组\(f\)。
那么正确的括号序列必然是以-1开头,0结尾,且中间的数都小于等于零。
知道了这个,此题还需要链表+RMQ操作
首先对于每一个前缀建一个链表\(nxt[f[i]]\)。
假设我们以i为括号序列起点,那么它右边的前缀都得\(-f[i-1]\),那么下一个为0的位置是\(nex[f[i-1]]\),我们已经预处理它的位置
直接RMQ查询即可。诶,这样好像也会超时,最坏情况下也是\(O(n^2)\)的,因为我们会沿着链表跳很多次。。。
那么就倒着做吧,我们记录好以nex[i]为结尾的的答案,以后直接累加即可,至此,时间复杂度降为\(O(nlogn)\)
合法括号序列的定义是:
1.空序列是合法括号序列。
2.如果S是合法括号序列,那么(S)是合法括号序列。
3.如果A和B都是合法括号序列,那么AB是合法括号序列。
Input
多组测试数据。第一行有一个整数T(1<=T<=1100000),表示测试数据的数量。
接下来T行,每一行都有一个括号序列,是一个由'('和')'组成的非空串。
所有输入的括号序列的总长度不超过1100000。
Output
输出T行,每一行对应一个测试数据的答案。Input示例
5 ( () ()() (() (())
Output示例
20 1 3 1 2
题解
对于判断括号序列的合法性,有一种很简洁的方法:设左括号为-1,右括号为+1,求得一个前缀和数组\(f\)。
那么正确的括号序列必然是以-1开头,0结尾,且中间的数都小于等于零。
知道了这个,此题还需要链表+RMQ操作
首先对于每一个前缀建一个链表\(nxt[f[i]]\)。
假设我们以i为括号序列起点,那么它右边的前缀都得\(-f[i-1]\),那么下一个为0的位置是\(nex[f[i-1]]\),我们已经预处理它的位置
直接RMQ查询即可。诶,这样好像也会超时,最坏情况下也是\(O(n^2)\)的,因为我们会沿着链表跳很多次。。。
那么就倒着做吧,我们记录好以nex[i]为结尾的的答案,以后直接累加即可,至此,时间复杂度降为\(O(nlogn)\)
参考代码
#include <map> #include <queue> #include <cmath> #include <cstdio> #include <complex> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define ll long long #define inf 1000000000 #define PI acos(-1) #define REP(i,x,n) for(ll i=x;i<=n;i++) #define DEP(i,n,x) for(ll i=n;i>=x;i--) #define mem(a,x) memset(a,x,sizeof(a)) using namespace std; ll read(){ ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void Out(ll a){ if(a<0) putchar('-'),a=-a; if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=1100000+10; char a ; int f ; map<int,int> fa; map<int,int>vis; int nxt ; int dp [20]; void RMQ_init(int n){ for(int i=1;i<=n;i++) dp[i][0]=f[i]; for(int j=1;(1<<j)<=n;j++){ for(int i=1;i+(1<<j)-1<=n;i++){ dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int RMQ(int L,int R){ int k=0; while((1<<(k+1))<=R-L+1) k++; return max(dp[L][k],dp[R-(1<<k)+1][k]); } int main() { int T=read(); while(T--){ scanf("%s",a+1); f[0]=0;int n=strlen(a+1); for(int i=1;i<=n;i++){ if(a[i]=='(') f[i]=f[i-1]-1; else f[i]=f[i-1]+1; } fa.clear();vis.clear();RMQ_init(n); ll ans=0; for(int i=n;i>=0;i--){ if(!fa[f[i]]) fa[f[i]]=-1; nxt[i]=fa[f[i]]; fa[f[i]]=i; } vis[-1]=0; for(int i=n;i>=1;i--){ if(a[i]=='('){ if(nxt[i-1]==-1) vis[i-1]=0; else{ if(RMQ(i,nxt[i-1])<=f[i-1]) vis[i-1]+=vis[nxt[i-1]]+1; else vis[i-1]=0; } ans+=vis[i-1]; } } printf("%lld\n",ans); } return 0; }
相关文章推荐
- 51 Nod 1791 合法括号子段【分治+字符串】
- 51 nod 合法括号子段 (单调栈)
- 51Nod-1791-合法括号子段
- 51nod 1791 合法括号子段
- 51nod-1791-合法括号子段
- 51nod 1791 合法括号子段(DP)
- 【51Nod1791】合法括号子段
- 合法括号子段 51Nod - 1791 (栈+dp)
- 51nod 1791 合法括号子段(模拟)
- 51NOD 1791 合法括号子段
- 51nod 1791 合法括号子段
- 51Nod 1791 合法括号子段(栈+乱搞)
- 合法括号子段 51Nod - 1791 **
- 51nod 1791 合法括号子段 (dp)
- 51nod 1791 合法括号子段 DP
- 1791 合法括号子段
- 51nod 1791 合法括号子段 (队列)
- 51 nod 1275 连续子段的差异(单调队列)
- 最大子段和(51Nod 1049)、最小正子段和(51Nod 1065)、总结(最小子段和、最大子段和、最小正子段和)
- 51 NOD 1315 合法整数集(思维 + 模拟)