http://hihocoder.com/contest/challenge20/problem/2
给一串括号,求有多少个子串合法
dp[i]表示以i为结尾的方案数,i位置显然只能是右括号啦
那么 dp[i]=dp[i-1]+1;
递推累计所有dp[i]就好
int main( ) { scanf("%s",ss+1); int n=strlen(ss+1); int i; for (i=1; i<=n; i++) { if (ss[i]=='(') s.push( i); else { if (!s.empty()) { int tmp=s.top(); s.pop(); p[i]=tmp; } } if (!p[i])continue; dp[i]+=dp[p[i]-1]+1; ans+=dp[i]; } printf("%lld\n",ans); return 0; }
然后就是分治法做这个,把问题不断小化。
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <cstdio> #include <algorithm> #include <iostream> #include <queue> #include <set> #include <stack> #include <vector> #define inf 0x7fffffff #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 using namespace std; const int maxn = 1234567; long long ans; char ss[maxn]; int p[maxn]; void findans(int l,int r) { if (l+1==r) return ; int st=l+1; long long tmp=0; while(st<r) { int p2=p[st]; if (p2) { tmp++; findans(st,p2); st=p2+1; } else { ans+=tmp*(tmp+1)/2; tmp=0; st++; } } ans+=tmp*(tmp+1)/2; } struct node { char x; int y; node() {} node(char a,int b) { x=a,y=b; } }; stack<node> s; int main( ) { scanf("%s",ss+1); int n=strlen(ss+1); int i; for (i=1; i<=n; i++) { if (ss[i]=='(') s.push(node(ss[i],i)); else { if (!s.empty()) { node tmp=s.top(); s.pop(); p[tmp.y]=i; p[i]=tmp.y; } } } p[0]=n+1; p[n+1]=0; ss[0]='('; ss[n+1]=')'; ans=0; findans(0,n+1); printf("%lld\n",ans); return 0; }