Andrew Stankevich—1

Little Brackets

Time Limit: 2 Seconds       Memory Limit: 65536 KB

Consider all regular bracket sequences with one type of brackets. Let us call the depth of the sequence the maximal difference between the number of opening and the number of closing brackets in a sequence prefix. For example, the depth of the sequence "()()(())" is 2, and the depth of "((()(())()))" is 4.

Find out the number of regular bracket sequences with n opening brackets that have the depth equal to k. For example, for n = 3 and k = 2 there are three such sequences: "()(())", "(()())", "(())()".


Input

Input file contains several test cases. Each test case is described with n and k (1 <= k <= n <= 50).

Last testcase is followed by two zeroes. They should not be processed.


Output

For each testcase output the number of regular bracket sequences with n opening brackets that have the depth equal to k.

Separate output for different testcases by a blank line. Adhere to the format of the sample output.


Sample Input

3 2
37 23
0 0

Sample Output

Case 1: 3

Case 2: 203685956218528


Author:  Andrew Stankevich

Source: Andrew Stankevich's Contest #7

【分析

...不得不说这个系列的题目真的挺不错的..做起来挺复杂但是也挺有趣的

题意:给你n对括号,让你求出深度为k的方案数,深度就是说最深的嵌套括号层数.题目里有解释

显然这里要考虑的是dp,对于f[i][j]表示i对括号能组成深度不超过j的方案数,状态转移还是比较巧妙的,我们考虑一点,那就是

如果给你一个当前状态s,它的深度是a,那么它其中一定有一个会有一个    (s1)  存在,s1的深度是a-1,那么对于这个 (s1)  它的周围不管怎么加括号,都不会影响深度,只会增加方案数,当然它周围增加的括号深度不能比a-1大,

所以就发现了一个状态转移那就是f[k-1][j-1]*f[i-k][j],这里的k∈[1,i]然后把这些状态的方案数全部加起来就是f[i][j]

所以f[i][j]=sum( f[k-1][j-1]*f[i-k][j] ) (1<=k<=i)

那么状态转移方程已经有了,剩下的就是初始化了,一开始我想到的初始化是f[i][1]=1,显然对于深度为1的状态只可能是()()()()()这种类型

但是我计算之后发现,其实初始化应该是f[0][j],因为对于状j态转移,会出现f[0][j]这个位置,也就是k=i的时候,当然再做一次f[i][1]的初始化也是没有问题的~区别就是你做两层初始化和做一层初始化的区别。。本质上没有任何区别。。

那么剩下的问题就是高精度了,首先我们需要高精度乘法和加法,然后考虑到f[i][j]表示的是深度不超过j的方案数,但是我们需要的是深度为j的方案数,所以~答案应该是f[n][m]-f[n][m-1],也就是说还需要一个高精度减法....挺考验细节的....很有意思的题目

【代码】

#include <stdio.h>
#include <string.h>
int f[55][55][100];
int a[100];
int len;
void add(int i,int j,int k)
{
	//[k-1][j-1]*[i-k][j]
	memset(a,0,sizeof(a));
	for (int ii=1;ii<=f[i-k][j][0];ii++)
		for (int jj=1;jj<=f[k-1][j-1][0];jj++)
			a[ii+jj-1]+=f[i-k][j][ii]*f[k-1][j-1][jj];
	for (len=1;a[len]||(len<f[i-k][j][0]+f[k-1][j-1][0]-1);len++) 
	{
		a[len+1]+=a[len]/10;
		a[len]%=10;
	}
	len--;
	if (len<f[i][j][0]) len=f[i][j][0];
	for (int ii=1;ii<=len;ii++)
	{
		f[i][j][ii]+=a[ii];
		f[i][j][ii+1]+=f[i][j][ii]/10;
		f[i][j][ii]%=10;
	}
	while(f[i][j][len+1]) f[i][j][len+1]+=f[i][j][len]/10,f[i][j][len]%=10,len=len+1;	
	f[i][j][0]=len;
}


void init()
{
	memset(f,0,sizeof(f));
	for (int i=0;i<=50;i++)	f[0][i][1]=f[0][i][0]=1;
	for (int i=1;i<=50;i++)
		for (int j=1;j<=50;j++)
			for (int k=1;k<=i;k++)
				add(i,j,k);
}
void write(int n,int m)
{
	memset(a,0,sizeof(a));
	for (int i=1;i<=f[n][m][0];i++)
	{
		a[i]+=f[n][m][i]-f[n][m-1][i];
		if (a[i]<0) a[i]+=10,a[i+1]--;
	}
	len=f[n][m][0];
	while (!a[len]) len--;
	for (int i=len;i>0;i--) printf("%d",a[i]);
	printf("\n");
}



int main()
{
	init();
	int n,m;
	int pp=0;
	while (~scanf("%d%d",&n,&m) && (n||m))
	{
		if (pp) printf("\n");
		printf("Case %d: ",++pp);
		write(n,m);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值