UVa Problem 10157 Expressions (括号表达式)

来源:互联网 发布:ao史密斯壁挂炉 知乎 编辑:程序博客网 时间:2024/05/22 15:32
// Expressions (括号表达式)// PC/UVa IDs: 110604/10157, Popularity: C, Success rate: average Level: 2// Verdict: Accepted// Submission Date: 2011-06-03// UVa Run Time: 0.668s//// 版权所有(C)2011,邱秋。metaphysis # yeah dot net//// 如何得到相应的递推关系?翻看了 Catalan 数的推导过程得到了一些启发。首先,括号的数目必须是// 偶数才可能得到合法的表达式,当 n 为奇数时,不能得到任何深度的正确表达式,同时若深度超过 n// 个括号所能得到的合法表达式的最大深度时,结果也将是 0 。所有深度为 1 的表示式都只有 1 种,假// 设 T(m,d) 表示括号对数为 m (n = 2 * m),深度不超过 d 的合法括号表达式的总数,则有://// T(0,d) = 1//// 对于其他情况,假设 E 是一个深度为 d ,括号对数为 m 的合法表达式,则表达式 E 的最左边的括号// l 一定和某个右括号 r 配对,他们合在一起把表达式划分为两个合法的括号表达式,在 l 和 r 之间的// 部分以及 r 右边的部分,即://// E = (X)Y//// 假设左边部分有 k 对括号,则右边部分有 n - k - 1 对括号,因为 l 和 r 已经用了一对括号,则括号// 表达式 X 的深度最大为 d - 1 ,括号表达式 Y 的深度最大为 d 。则括号对数为 m,深度为 d 的合法// 表达式数量为 T(m,d) - T(m,d - 1)。//// T(m,d) = T(0,d - 1) * T(m - 1,d) + T(1,d - 1) * T(m - 2,d) + …… + T(k,// d - 1) * T(m - k - 1,d),0 <= k <= m - 1。//// 看起来像是 Catalan 数的二维版本。//// 用于 How Many Pieces of Land? 问题的大数类在这个问题上,显然效率不够高,于是我改进了一下,以// 10000为基数,数位改用模10000的值,用无符号整数来保存数位。#include <iostream>#include <vector>#include <algorithm>#include <iomanip>using namespace std;#define MAXM151#define MAXD151class integer{friend ostream & operator<<(ostream &, const integer &);public:integer() { };integer(unsigned int a){while (a){digits.push_back(a % base);a /= base;}};~integer() { };integer operator+(integer);integer operator-(integer);integer operator*(integer);private:void zero_justify(void);// 表示大数的结构。数位按模 10000 从低位到高位每 4 位为一组,作为一个 int 型数存放。vector < unsigned int > digits;static unsigned int const base = 10000;static unsigned int const length = 4;};// 重载输出符号 <<。ostream& operator<<(ostream& os, const integer& n){os << n.digits[n.digits.size() - 1];for (int i = n.digits.size() - 2; i >= 0; i--)os << setw(n.length) << setfill('0') << n.digits[i];return os;}// 移除大数运算产生的前导 0。void integer::zero_justify(void){for (int i = digits.size() - 1; i >= 1; i--){if (digits[i] == 0)digits.erase(digits.begin() + i);elsebreak;}}// 加法运算。integer integer::operator+(integer b){integer c;c.digits.resize(max(digits.size(), b.digits.size()) + 1);int carry = 0;// 进位。int marker = 0;// 为两数添加前导 0,以使得数位相同,便于计算。while (digits.size() < c.digits.size())digits.push_back(0);while (b.digits.size() < c.digits.size())b.digits.push_back(0);// 逐位相加。while (marker < c.digits.size()){int t = digits[marker] + b.digits[marker] + carry;carry = t / base;c.digits[marker] = t % base;marker++;}c.zero_justify();return c;}// 减法。integer integer::operator-(integer b){integer c;int borrow = 0;// 借位。int marker = 0;// 计数器。// 为减数添加前导0,便于计算。while (b.digits.size() < digits.size())b.digits.push_back(0);// 从低位开始逐位相减,不够的向高位借位。while (marker < digits.size()){int v = digits[marker] - borrow - b.digits[marker];if (v < 0){v += base;borrow = 1;}elseborrow = 0;c.digits.push_back(v % base);marker++;}c.zero_justify();return c;}// 乘法。integer integer::operator*(integer b){integer c;c.digits.resize(digits.size() + b.digits.size());fill(c.digits.begin(), c.digits.end(), 0);for (int i = 0; i < b.digits.size(); i++)for (int j = 0; j < digits.size(); j++){c.digits[i + j] += digits[j] * b.digits[i];c.digits[i + j + 1] += c.digits[i + j] / base;c.digits[i + j] %= base;}c.zero_justify();return c;}integer result[MAXM][MAXD];void init(){for (int m = 0; m < MAXM; m++)for (int d = 0; d < MAXD; d++)result[m][d] = integer(0);for (int d = 0; d < MAXD; d++)result[0][d] = integer(1);for (int m = 1; m < MAXM; m++)for (int d = 1; d < MAXD; d++)for (int k = 0; k <= m - 1; k++)result[m][d] =result[m][d] + result[k][d -1] * result[m - k - 1][d];}int main(int ac, char *av[]){int n, d;init();while (cin >> n >> d)cout << (result[n / 2][d] - result[n / 2][d - 1]) << endl;return 0;}


原创粉丝点击