题目链接:https://vjudge.net/problem/CodeForces-785D
做这个题的时候,分析之后,感觉是个组合数学的题目,后来发现利用组合数学中的一个知识来解决。
范德蒙恒等式:
题目大意:给你一串字符串(只包含字符'('和')'),求有多少个子串满足:长度是偶数,且左半边只有'(' 右半边只有')',比如"((()))"是一个满足条件的字符串。
解题思路:先记录每个字符左边有多少个'(',右边有多少个')',包含当前字符本身;然后从左往右遍历字符串,如果当前字符是'(',左边(包含本身)有a个'(',右边有b个')',那么满足条件的子字符串就增加了这个很好想,但是下面就不知道怎么做
AC代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include <stack> #include <queue> #include <vector> #include <string> #define cla(a, sum) memset(a, sum, sizeof(a)) #define rap(i, m, n) for(i=m; i<=n; i++) #define rep(i, m, n) for(i=m; i>=n; i--) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll, ll> P; const int Inf = 0x3f3f3f3f; const double eps = 1e-8; const int maxn = 2e5+5; const int mod = 1e9+7; char a[maxn]; int l[maxn],r[maxn]; ll fa[maxn],fc[maxn],ans; ll quick(ll a,ll b,ll p)//快速幂取模 a^b%p { ll ans=1; while(b) { if(b&1) ans=ans*a%p; a=a*a%p; b>>=1; } return ans; } ll C(int n,int m)//费马小定理 { return fa[n]%mod*fc[n-m]%mod*fc[m]%mod; } void init() { fa[0]=fc[0]=1; for(int i=1;i<=200000;i++) { fa[i]=(fa[i-1]*i)%mod; fc[i]=quick(fa[i],mod-2,mod); } } int main() { init(); scanf("%s",a+1); int i,j,k; int cnt=strlen(a+1); l[0]=0;r[cnt+1]=0; rap(i,1,cnt){ if(a[i]=='('){ l[i]=l[i-1]+1; } else l[i]=l[i-1]; } rep(i,cnt,1){ if(a[i]==')'){ r[i]=r[i+1]+1; } else r[i]=r[i+1]; } ans=0; rap(i,1,cnt) { if(a[i]=='(') ans=(ans+C(l[i]+r[i]-1,l[i]))%mod; // cout<<l[i]+r[i]-1<<" "<<l[i]<<endl; // cout<<C(l[i]+r[i]-1,l[i])<<endl; } printf("%lld",ans); return 0; }