Uva 10157 - Expressions 解题报告(递推)
来源:互联网 发布:塔吊基础计算软件 编辑:程序博客网 时间:2024/06/06 00:25
Problem A: EXPRESSIONS
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.
()(())()
(()(()))
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:
ì 0 if E is empty
D(E)= í 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?
Task
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 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 data
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.
Example
Input data Output data
6 2 3
300 150 1
There are exactly three correctly built parenthesis expressions of length 6 and depth 2:
(())()
()(())
(()())
解题报告:挺艰难的一题。
首先,我们分析一下题意:求指定长度和深度的括号序列的种数。看到括号序列,最先想到的就是之前《训练指南》上串并联网络那题。这题也可以很方便的划分为树形。指定整个串有个虚根,连接表示为兄弟关系,嵌套表示为父子关系。那么这题就可以表达为求节点数为n/2+1,深度为k+1的树的种数。(())()序列可以表示为下图:
如何递推这个问题的结果呢?当时笔者就卡在这个地方。直接求节点数m=n/2+1,深度为k+1的树的种数还是比较困难的。我们可以枚举第一个儿子所形成的子树的种数和剩下部分树的种数。只要其中一部分的深度等于k+1即可。这样就有三种情况:左边子树深度为k+1,剩下部分深度为k+1;左边深度不够,右边深度满足;左边深度满足,右边深度不够。深度为k+1还可以递推,深度不足则需要枚举可能的深度,复杂度就高了。
笔者就卡在这里了。看了一下别人的解题报告= =。
原来可以这样,每次求节点为m,深度小于等于k+1的子树的数量,再减去节点为m,深度小于k+1的子树的数量,那么得到的必是所求。
思路肯定是对的。后来遇到的问题就是大数模版的问题。以前用的别人的大数模板运算减法时除了问题。花了很长时间完成了自己的大数模版,完美支持负数和减法。今天早上提交一发,就A了。
代码如下:
/* * 大数模版 * 完美支持负数及加减法操作 * 支持乘法,大小比较,赋值 * 支持与long long类型的赋值比较 * SF-_- 14.04.01 */#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;const int K = 10000; // 数组里每位代表1Wconst int M = 30; // 一共10位const char show[] = "%04lld";struct Bignum{ LL a[M*2]; // 大数数组 int len; // 长度 bool negative; // 正负 Bignum() { clear(); } void clear() { len=0; negative=false; memset(a, 0, sizeof(a)); } Bignum(LL num) { *this=num; } Bignum operator=(LL num) { clear(); if(num<0) negative=true, num=-num; while(num) a[len++]=num%K,num/=K; return *this; } Bignum(const Bignum& cmp) { memcpy(this, &cmp, sizeof(Bignum)); } Bignum operator=(const Bignum& cmp) { memcpy(this, &cmp, sizeof(Bignum)); return *this; } int absCmp(const Bignum& cmp) { if(len!=cmp.len) return len>cmp.len?1:-1; for(int i=len-1;i>=0;i--) if(a[i]!=cmp.a[i]) return a[i]>cmp.a[i]?1:-1; return 0; } int absCmp(LL num) { Bignum cmp(num); return absCmp(cmp); } bool operator<(const Bignum& cmp) { if(negative^cmp.negative) return negative?true:false; if(negative) return absCmp(cmp)>0; else return absCmp(cmp)<0; } bool operator<(LL num) { Bignum cmp(num); return *this<cmp; } bool operator==(const Bignum& cmp) { if(negative^cmp.negative) return false; return absCmp(cmp)==0; } bool operator==(LL num) { Bignum cmp(num); return *this==cmp; } void absAdd(const Bignum& one, const Bignum& two) { len=max(one.len, two.len); for(int i=0;i<len;i++) { a[i]+=one.a[i]+two.a[i]; if(a[i]>=K) a[i]-=K, a[i+1]++; } if(a[len]) len++; } void absSub(const Bignum& one, const Bignum& two) { len=one.len; for(int i=0;i<len;i++) { a[i]+=one.a[i]-two.a[i]; if(a[i]<0) a[i+1]--,a[i]+=K; } while(len>0 && a[len-1]==0) len--; } void absMul(const Bignum& one, const Bignum& two) { len=one.len+two.len; for(int i=0;i<one.len;i++) for(int j=0;j<two.len;j++) a[i+j]+=one.a[i]*two.a[j]; for(int i=0;i<len;i++) if(a[i]>=K) a[i+1]+=a[i]/K,a[i]%=K; while(len>0 && a[len-1]==0) len--; } Bignum operator+(const Bignum& cmp) { Bignum c; if(negative^cmp.negative) { bool res = absCmp(cmp)>0; c.negative = !(negative^res); if(res) c.absSub(*this, cmp); else c.absSub(cmp, *this); } else if(negative) { c.negative=true; c.absAdd(*this, cmp); } else { c.absAdd(*this, cmp); } return c; } Bignum operator-(const Bignum& cmp) { Bignum cpy; if(cpy==cmp) return *this; else cpy=cmp, cpy.negative^=true; return *this+cpy; } Bignum operator*(const Bignum& cmp) { Bignum c; if(c==cmp || c==*this) return c; c.negative = negative^cmp.negative; c.absMul(*this, cmp); return c; } void output() { if(len==0) { puts("0"); return; } if(negative) printf("-"); printf("%lld", a[len-1]); for(int i=len-2;i>=0;i--) printf(show, a[i]); puts(""); }};Bignum dp[155][155];Bignum dfs(int n, int k){ if(n==1) return 1; if(k==1) return 0; Bignum &ans = dp[n][k]; if(!(ans==-1)) return ans; ans=0; for(int i=1;i<n;i++) ans=ans+dfs(i, k-1)*dfs(n-i, k); return ans;}void init(){ for(int i=0;i<155;i++) for(int j=0;j<155;j++) dp[i][j]=-1;}int main(){ init(); int n,k; while(~scanf("%d%d", &n, &k)) { if(n&1) puts("0"); else (dfs(n/2+1, k+1)-dfs(n/2+1, k)).output(); }}大数模版这东西,最好自己写一个,或者完全将别人的读懂。经常用,发现问题及时修改。无论是网络赛还是正式比赛,有个靠谱的大数模版总是好的。
- Uva 10157 - Expressions 解题报告(递推)
- UVa 11234Expressions解题报告
- Uva 11375 Matches 解题报告(递推+高精度)
- Uva 11137 Ingenuous Cubrency 解题报告(递推)
- Uva 10253 - Series-Parallel Networks 解题报告(递推)
- Uva 1393 - Highways 解题报告(递推)
- Uva 11645 - Bits 解题报告(递推+大数)
- Uva 10079 - Pizza Cutting 解题报告(递推)
- Uva 10081 - Tight Words 解题报告(递推)
- Uva 580 - Critical Mass 解题报告(递推)
- UVa-10891 Game of Sum ACM解题报告(递推O(n^2)算法)
- Uva 11174 Stand in a Line 解题报告(递推+逆元)
- Uva 11361 Investigating Div-Sum Property 解题报告(递推)
- Uva 10312 - Expression Bracketing 解题报告(卡特兰数+递推)
- Uva 10497 - Sweet Child Makes Trouble 解题报告(递推+大数)
- HDU:2013解题报告(递推)
- UVa 327 - Evaluating Simple C Expressions解题报告
- 1242递推解题报告
- String path 、String basePath
- quick中的一些小细节,逐步更新
- 项目管理笔记
- Source Insight3.5注册码
- 屏幕宽高的取值
- Uva 10157 - Expressions 解题报告(递推)
- 黑马学习笔记1
- TCP长连接与短连接的区别
- 今年三月不想读新春
- SharePoint 2013 App Development读书笔记4
- 数据结构的顺序表及其操作
- 郭富城《好舞蹈》献综艺首秀 称不愿随便结婚
- java io 之 File
- SharePoint 2010/2013 在某块代码段中临时禁用触发event handler(receiver)