uva 10157Expressions

来源:互联网 发布:淘宝同行恶意刷退款率 编辑:程序博客网 时间:2024/05/18 03:52

原题:
Let X be the set of correctly built parenthesis expressions. The elements of X are strings consisting only of the characters ‘(’ and ‘)’. The set X is defined as follows:
• an empty string belongs to X
• if A belongs to X, then (A) belongs to X
• if both A and B belong to X, then the concatenation AB belongs to X.
For example, the following strings are correctly built parenthesis expressions (and therefore belong to the set X):

()(())()
(()(()))
The expressions below are not correctly built parenthesis expressions (and are thus not in X):

(()))(()
())(()

Let E be a correctly built parenthesis expression (therefore E is a string belonging to X).
The length of E is the number of single parenthesis (characters) in E.
The depth D(E) of E is defined as follows:

这里写图片描述

For example, the length of “()(())()” is 8, and its depth is 2. What is the number of correctly built parenthesis expressions of length n and depth d, for given positive integers n and d?

Write a program which
• reads two integers n and d
• computes the number of correctly built parenthesis expressions of length n and depth d;

Input

Input consists of lines of pairs of two integers - n and d, at most one pair on line, 2 ≤ n ≤ 300, 1 ≤ d ≤ 150.
The number of lines in the input file is at most 20, the input may contain empty lines, which you don’t need to consider.

Output
For every pair of integers in the input write single integer on one line - the number of correctly built parenthesis expressions of length n and depth d.
Note: There are exactly three correctly built parenthesis expressions of length 6 and depth 2:
(())()
()(())
(()())

Sample Input
6 2
300 150

Sample Output
3
1

中文

给你两个数n和d,表示括号括号个数(单只)和深度,根据上面公式。现在问你满足n和d的括号排列方式有多少种?

#include<bits/stdc++.h>using namespace std;const int maxn=100;/*精度位数*//*(必选)类与基础功能定义,用法类似于unsigned(非负)*/class bign{    friend istream& operator>>(istream&,bign&);/*输入运算符友元*/    friend ostream& operator<<(ostream&,const bign&);/*输出运算符友元*/    friend bign operator+(const bign&,const bign&);/*加号运算符友元*/    friend bign operator*(const bign&,const bign&);/*乘号运算符友元*/    friend bign operator*(const bign&,int);/*高精度乘以低精度乘法友元*/    friend bign operator-(const bign&,const bign&);/*减号运算符友元*/    friend bign operator/(const bign&,const bign&);/*除法运算符友元*/    friend bign operator%(const bign&,const bign&);/*模运算符友元*/    friend bool operator<(const bign&,const bign&);/*逻辑小于符友元*/    friend bool operator>(const bign&,const bign&);/*逻辑大于符友元*/    friend bool operator<=(const bign&,const bign&);/*逻辑小于等于符友元*/    friend bool operator>=(const bign&,const bign&);/*逻辑大于等于符友元*/    friend bool operator==(const bign&,const bign&);/*逻辑等符友元*/    friend bool operator!=(const bign&,const bign&);/*逻辑不等符友元*/private:    int len,s[maxn];public:    bign(){memset(s,0,sizeof(s));len=1;}    bign operator=(const char* num)    {        int i=0,ol;        ol=len=strlen(num);        while(num[i++]=='0'&&len>1)        len--;        memset(s,0,sizeof(s));        for(i=0;i<len;i++)        s[i]=num[ol-i-1]-'0';        return *this;    }    bign operator=(int num)    {        char s[maxn];        sprintf(s,"%d",num);        *this=s;        return *this;    }    bign(int num){*this=num;}    bign(const char* num){*this=num;}    string str() const    {        int i;        string res="";        for(i=0;i<len;i++)res=char(s[i]+'0')+res;        if(res=="")res="0";        return res;    }};/*(可选)基本逻辑运算符重载*/bool operator<(const bign& a,const bign& b){    int i;    if(a.len!=b.len)return a.len<b.len;    for(i=a.len-1;i>=0;i--)        if(a.s[i]!=b.s[i])    return a.s[i]<b.s[i];    return false;}bool operator>(const bign& a,const bign& b){return b<a;}bool operator<=(const bign& a,const bign& b){return !(a>b);}bool operator>=(const bign& a,const bign& b){return !(a<b);}bool operator!=(const bign& a,const bign& b){return a<b||a>b;}bool operator==(const bign& a,const bign& b){return !(a<b||a>b);}/*(可选)加法运算符重载*/bign operator+(const bign& a,const bign& b){    int i,max=(a.len>b.len?a.len:b.len),t,c;    bign sum;    sum.len=0;    for(i=0,c=0;c||i<max;i++)    {        t=c;        if(i<a.len)t+=a.s[i];        if(i<b.len)t+=b.s[i];        sum.s[sum.len++]=t%10;        c=t/10;    }    return sum;}/*(可选)乘法运算符重载(高精度乘高精度)*/bign operator*(const bign& a,const bign& b){    int i,j;    bign res;    for(i=0;i<a.len;i++)    {        for(j=0;j<b.len;j++)        {            res.s[i+j]+=(a.s[i]*b.s[j]);            res.s[i+j+1]+=res.s[i+j]/10;            res.s[i+j]%=10;        }    }    res.len=a.len+b.len;    while(res.s[res.len-1]==0&&res.len>1)res.len--;    if(res.s[res.len])res.len++;    return res;}/*高精度乘以低精度(注意:必须是bign*int顺序不能颠倒,要么会与高精度乘高精度发生冲突*/bign operator*(const bign& a,int b){    int i,t,c=0;    bign res;    for(i=0;i<a.len;i++)    {        t=a.s[i]*b+c;        res.s[i]=t%10;        c=t/10;    }    res.len=a.len;    while(c!=0)    {        res.s[i++]=c%10;        c/=10;        res.len++;    }    return res;}/*(可选)减法运算符重载*/bign operator-(const bign& a,const bign& b){    bign res;    int i,len=(a.len>b.len)?a.len:b.len;    for(i=0;i<len;i++)    {        res.s[i]+=a.s[i]-b.s[i];        if(res.s[i]<0)        {            res.s[i]+=10;            res.s[i+1]--;        }    }    while(res.s[len-1]==0&&len>1)len--;    res.len=len;    return res;}/*(可选)除法运算符重载(注意:减法和乘法运算和>=运算符必选)*/bign operator/(const bign& a,const bign& b){    int i,len=a.len;    bign res,f;    for(i=len-1;i>=0;i--)    {        f=f*10;        f.s[0]=a.s[i];        while(f>=b)        {            f=f-b;            res.s[i]++;        }    }    while(res.s[len-1]==0&&len>1)len--;    res.len=len;    return res;}/*(可选)模运算符重载(注意:减法和乘法运算和>=运算符必选)*/bign operator%(const bign& a,const bign& b){    int i,len=a.len;    bign res,f;    for(i=len-1;i>=0;i--)    {        f=f*10;        f.s[0]=a.s[i];        while(f>=b)        {            f=f-b;            res.s[i]++;        }    }    return f;}/*(可选)X等运算符重载(注意:X法必选)*/bign& operator+=(bign& a,const bign& b){    a=a+b;    return a;}bign& operator-=(bign& a,const bign& b){    a=a-b;    return a;}bign& operator*=(bign& a,const bign& b){    a=a*b;    return a;}bign& operator/=(bign& a,const bign& b){    a=a/b;    return a;}/*可选前缀++/--与后缀++/--(注意:加法必选)*/bign& operator++(bign& a){    a=a+1;    return a;}bign& operator++(bign& a,int){    bign t=a;    a=a+1;    return t;}bign& operator--(bign& a){    a=a-1;    return a;}bign& operator--(bign& a,int){    bign t=a;    a=a-1;    return t;}istream& operator>>(istream &in,bign& x){    string s;    in>>s;    x=s.c_str();    return in;}ostream& operator<<(ostream &out,const bign& x){    out<<x.str();    return out;}bign f[151][151];int main(){    ios::sync_with_stdio(false);    for(int i=0;i<=150;i++)    {        for(int j=0;j<=150;j++)            f[i][j]=0;    }    for(int i=0;i<=150;i++)        f[0][i]=1;    for(int i=1;i<=150;i++)    {        for(int j=1;j<=150;j++)        {            for(int k=0;k<i;k++)            {                f[i][j]+=(f[k][j-1] * f[i-k-1][j]);            }        }    }    int n,d;    while(cin>>n>>d)        cout<<f[n/2][d]-f[n/2][d-1]<<endl;    return 0;}

解答:

类似卡特兰数的思想,首先设置状态
f[i][j]表示i对括号形成深度不超过j的个数,注意不要表示成i对括号形成深度为j的个数!

构造形式写成 ( A ) B的形式,其中A是括号数为i,深度不超过d-1的组成个数。B是括号数为n-i-1,深度不超过d的组成个数。两个个数相乘,用卡特兰数的计数方法

f[n][d]=n1i=0f[i][d1]f[ni1][d]

要用到高精度,时间会比较长~

原创粉丝点击