hdu 5184 Brackets(卡特兰数)

来源:互联网 发布:java参数传递引用传递 编辑:程序博客网 时间:2024/05/16 18:16

Brackets

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 655    Accepted Submission(s): 169


Problem Description
We give the following inductive definition of a “regular brackets” sequence:
● the empty sequence is a regular brackets sequence,
● if s is a regular brackets sequence, then (s) are regular brackets sequences, and
● if a and b are regular brackets sequences, then ab is a regular brackets sequence.
● no other sequence is a regular brackets sequence

For instance, all of the following character sequences are regular brackets sequences:
(), (()), ()(), ()(())
while the following character sequences are not:
(, ), )(, ((), ((()

Now we want to construct a regular brackets sequence of length n, how many regular brackets sequences we can get when the front several brackets are given already.
 

Input
Multi test cases (about 2000), every case occupies two lines.
The first line contains an integer n.
Then second line contains a string str which indicates the front several brackets.

Please process to the end of file.

[Technical Specification]
1n1000000
str contains only '(' and ')' and length of str is larger than 0 and no more than n.
 

Output
For each case,output answer % 1000000007 in a single line.
 

Sample Input
4()4(6()
 

Sample Output
122
Hint
For the first case the only regular sequence is ()().For the second case regular sequences are (()) and ()().For the third case regular sequences are ()()() and ()(()).
题意:给初始一些括号序列,再给n表示序列的总长度,问一共有多少种括号组成方式

()()和(())都是合法的(()和)(是不合法的

思路:...没接触过卡特兰数,做不出来。

这题其实是裸的卡特兰数,卡特兰数有这么一个模型

电影院一场票5块钱,n个拿5块钱的人和m个拿10块钱的人在排队,售票口一开始无任何钱,要保证让尽可能多的人能够进去,问一共有多少种排列方式

显然,每一个拿5块钱的人后面必须有一个10块钱的跟他对应才能让十块的进场。

答案是C(n+m,n)-C(n+m,n-1)  证明就不说了我也没看懂..感兴趣可以去看维基百科。

然后我们把左括号当成5块钱的人,右括号当成10块钱的人,这个题就是个裸的卡特兰数了。

注意求组合数要求高效,所以我们可以预处理1~1000000的阶乘,然后每次组合数就能O(1)得出来了

除法取模要求逆元,本人不喜欢用扩展欧几里得,这里就用费马小定理求逆元  直接求i的mod-2次方即可

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;#define N 1000050#define mod 1000000007char str[N];long long dp[N];void init(){    dp[1]=1;    for(long long i=2;i<=1000000;i++)        dp[i]=dp[i-1]*i%mod;}long long pow_mod(long long a,long long n){    long long ans=1;    while(n)    {        if(n&1) ans=ans*a%mod;        a=a*a%mod;        n>>=1;    }    return ans;}long long C(long long a,long long b){    if(!b) return 1;    long long ans=dp[a];    ans=ans*pow_mod(dp[a-b],mod-2)%mod;    ans=ans*pow_mod(dp[b],mod-2)%mod;    return ans;}long long solve(long long n){    int len=strlen(str);    if(n&1) return 0;    long long p=0,q=0;    for(int i=0;i<len;i++)    {        if(str[i]=='(') p++;        else q++;        if(p<q) return 0;    }    return (C(n-p-q,n/2-p)-C(n-p-q,n/2-p-1)+mod)%mod;}int main(){    long long n;    init();    while(~scanf("%lld",&n))    {        scanf("%s",str);        long long ans=solve(n);        printf("%lld\n",ans);    }    return 0;}




0 0