POJ 1671 Rhyme Schemes

Rhyme Schemes
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 1175   Accepted: 645   Special Judge

Description

The rhyme scheme for a poem (or stanza of a longer poem) tells which lines of the poem rhyme with which other lines. For example, a limerick such as If computers that you build are quantum 
Then spies of all factions will want 'em 
Our codes will all fail 
And they'll read our email 
`Til we've crypto that's quantum and daunt 'em 

Jennifer and Peter Shor (http://www.research.att.com/~shor/notapoet.html) 

Has a rhyme scheme of aabba, indicating that the first, second and fifth lines rhyme and the third and fourth lines rhyme. 
For a poem or stanza of four lines, there are 15 possible rhyme schemes: 
aaaa, aaab, aaba, aabb, aabc, abaa, abab, abac, abba, abbb, abbc, abca, a bcb, abcc, and abcd. 
Write a program to compute the number of rhyme schemes for a poem or stanza of N lines where N is an input value.

Input

Input will consist of a sequence of integers N, one per line, ending with a 0 (zero) to indicate the end of the data. N is the number of lines in a poem.

Output

For each input integer N, your program should output the value of N, followed by a space, followed by the number of rhyme schemes for a poem with N lines as a decimal integer with at least 12 correct significant digits (use double precision floating point for your computations).

Sample Input

1
2
3
4
20
30
10
0

Sample Output

1 1
2 2
3 5
4 15
20 51724158235372
30 846749014511809120000000
10 115975

Source

Greater New York 2003

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define MAXN 100
double f[MAXN][MAXN];

double dfs(int high, int len){
	int i;
	double ret;
	if (len == 1) return high;
	if (f[len][high] >= 0) return f[len][high];
	for (i = 1, ret = 0; i <= high; i++){
		ret += dfs(max(high, i + 1), len - 1); 
	}
	return f[len][high] = ret;
}

int main(){
	int i, j, n;
	for (i = 0; i < MAXN; i++)
		for (j = 0; j < MAXN; j++)
			f[i][j] = -1;
	while(scanf("%d", &n), n != 0){
		printf("%d %.0f\n", n, dfs(1, n));
	}
	return 0;
}
/*
问题:将n个点分成一个个集合,问分法数。
例如,n=4,
aaab, aaba, abcd, 是不同分法,
但是aaab = bbba, abcd = abdc
从输入样例可以看出, abdc这种写法是不合法的,或者说是没必要考虑

类似数位DP做的
数学上,叫第二类Stirling数
S(n,k) = k*S(n-1,k) + S(n-1,k-1)
状态: 前n个点,分成了k个集合

奇怪的,n=50以后,结果为0,再大点就RE了...
*/

补充:

Bell数
又称为贝尔数,是以埃里克·坦普尔·贝尔(Eric Temple Bell)为名的。

B(n)是包含n个元素的集合的划分方法的数目。

B(0) = 1, B(1) = 1, B(2) = 2, B(3) = 5, 
B(4) = 15, B(5) = 52, B(6) = 203,...

递推公式为,
B(0) = 1,
B(n+1) = Sum(0,n) C(n,k)B(k). n = 1,2,...

其中,Sum(0,n)表示对k从0到n求和,C(n,k) = n!/[k!(n-k)!]
-------------------------
Stirling数
又称为斯特灵数,在组合数学,Stirling数可指两类数,都是由18世纪数学家James Stirling提出的。

第一类Stirling数是有正负的,其绝对值是包含n个元素的集合分作k个环排列的方法数目。

递推公式为,
S(n,0) = 0, S(1,1) = 1.
S(n+1,k) = S(n,k-1) + nS(n,k)。

第二类Stirling数是把包含n个元素的集合划分为正好k个非空子集的方法的数目。

递推公式为,
S(n,n) = S(n,1) = 1,
S(n,k) = S(n-1,k-1) + kS(n-1,k).
-------------
每个贝尔数都是"第二类Stirling数"的和。
B(n) = Sum(1,n) S(n,k).

你可能感兴趣的:(POJ 1671 Rhyme Schemes)