F.小红的括号串
题解
Raney 引理: 对于
,如果
,则其所有循环位移中恰好有一个满足所有的前缀和都是正数。
将括号串中的左括号视为 -1,右括号视为 1,则合法括号串需要满足序列和为 0。
考虑在这个序列中加上一个 -1,再将所有数取反,此时序列满足 Raney 引理的应用条件。
并且因为恰好有一个循环位移合法,所以此时序列的第一位必定为 1(即我们取反前加的 -1)。把这个 1 去掉再取反即为合法括号串。
因此所有满足序列和为 0 的括号串均合法。记左括号数为 ,右括号数为
,当
为偶数时答案为
。
Bonus:尝试解决 P6672 你的生命已如风中残烛。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define M 1000000007
#define N 200000
int i,j,k,n,m,t;
ll jc[N+50],inv[N+50];
string s;
ll ksm(ll a,ll p){ll res=1;while(p){if(p&1){res=res*a%M;}a=a*a%M;p>>=1;}return res;}
ll c(ll n,ll m){if(n<m||n<0||m<0){return 0;}return jc[n]*inv[m]%M*inv[n-m]%M;}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
jc[0]=inv[0]=1;
for(i=1;i<=N;i++)jc[i]=jc[i-1]*i%M;
inv[N]=ksm(jc[N],M-2);
for(i=N-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%M;
cin>>n>>s;
if(n&1){
cout<<0; return 0;
}
for(auto c:s){
if(c=='(')i++;
else if(c==')')j++;
}
cout<<c(n-i-j,n/2-i);
}