UVA题目10157 - Expressions(DP+高精度)

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:
D(E) =



0 if E is empty
D(A) + 1 if E = (A), and A is in X
max(D(A), D(B)) if E = AB, and A, B are in X
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的种类有多种,

分成两部分,dp[i][j]表示i对,深度最多为j的有多少种,把括号分为两部分,一部分深度不超过j,一部分不超过j-1

转移方程dp[i][j]=dp[k][j-1]*dp[i-k-1][j]+dp[i][j];

深度的话就减一下就好了dp[n/2][m]-dp[n/2][m-1];

ac代码

16453524 10157 Expressions Accepted C++ 4.216 2015-11-18 07:47:56
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int M=155;
const int N=105;
struct bign {
    int len, sex;
    int s[N];

    bign() {
        this -> len = 1;
        this -> sex = 0;
        memset(s, 0, sizeof(s));
    }

    bign operator = (const char *number) {
        int begin = 0;
        len = 0;
        sex = 1;
        if (number[begin] == '-') {
            sex = -1;
            begin++;
        }
        else if (number[begin] == '+')
            begin++;

        for (int j = begin; number[j]; j++)
            s[len++] = number[j] - '0';
    }

    bign operator = (int number) {
        char string[N];
        sprintf(string, "%d", number);
        *this = string;
        return *this;
    }

    bign (int number) {*this = number;}
    bign (const char* number) {*this = number;}

    bign change(bign cur) {
        bign now;
        now = cur;
        for (int i = 0; i < cur.len; i++)
            now.s[i] = cur.s[cur.len - i - 1];
        return now;
    }

    void delZore() {    // 删除前导0.
        bign now = change(*this);
        while (now.s[now.len - 1] == 0 && now.len > 1) {
            now.len--;
        }
        *this = change(now);
    }

    void put() {    // 输出数值。
        delZore();
        if (sex < 0 && (len != 1 || s[0] != 0))
            cout << "-";
        for (int i = 0; i < len; i++)
            cout << s[i];
    }

    bign operator + (const bign &cur){
        bign sum, a, b;
        sum.len = 0;
        a = a.change(*this);
        b = b.change(cur);

        for (int i = 0, g = 0; g || i < a.len || i < b.len; i++){
            int x = g;
            if (i < a.len) x += a.s[i];
            if (i < b.len) x += b.s[i];
            sum.s[sum.len++] = x % 10;
            g = x / 10;
        }
        return sum.change(sum);
    }

    bign operator * (const bign &cur){
        bign sum, a, b;
        sum.len = 0;
        a = a.change(*this);
        b = b.change(cur);

        for (int i = 0; i < a.len; i++){
            int g = 0;

            for (int j = 0; j < b.len; j++){
                int x = a.s[i] * b.s[j] + g + sum.s[i + j];
                sum.s[i + j] = x % 10;
                g = x / 10;
            }
            sum.len = i + b.len;

            while (g){
                sum.s[sum.len++] = g % 10;
                g = g / 10;
            }
        }
        return sum.change(sum);
    }

    bign operator - (const bign &cur) {
        bign sum, a, b;
        sum.len = len;
        a = a.change(*this);
        b = b.change(cur);

        for (int i = 0; i < b.len; i++) {
            sum.s[i] = a.s[i] - b.s[i] + sum.s[i];
            if (sum.s[i] < 0) {
                sum.s[i] += 10;
                sum.s[i + 1]--;
            }
        }
        for (int i = b.len; i < a.len; i++) {
            sum.s[i] += a.s[i];
            if (sum.s[i] < 0) {
                sum.s[i] += 10;
                sum.s[i + 1]--;
            }
        }
        return sum.change(sum);
    }
};
bign dp[M][M];
void DP()
{
    int i,j,k;
    for(i=0;i<=150;i++)
        dp[0][i]=1;
    for(i=1;i<=150;i++)
    {
        for(j=1;j<=150;j++)
        {
            for(k=0;k<i;k++)
            {
                dp[i][j]=dp[k][j-1]*dp[i-k-1][j]+dp[i][j];
            }
        }
    }
}
int main()
{
    int n,m;
    DP();
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        bign sum=dp[n/2][m]-dp[n/2][m-1];
        sum.put();
        printf("\n");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值