Hrbust 1298 Pills【dp+卡特兰数】

Pills
Time Limit: 1000 MSMemory Limit: 32768 K
Total Submit: 50(28 users)Total Accepted: 28(26 users)Rating: Special Judge: No
Description
Aunt Lizzie takes half a pill of a certain medicine every day. She starts with a bottle that contains N pills.

On the first day, she removes a random pill, breaks it in two halves, takes one half and puts the other half back into the bottle.

On subsequent days, she removes a random piece (which can be either a whole pill or half a pill) from the bottle. If it is half a pill, she takes it. If it is a whole pill, she takes one half and puts the other half back into the bottle.

In how many ways can she empty the bottle? We represent the sequence of pills removed from the bottle in the course of 2N days as a string, where the i-th character is W if a whole pill was chosen on the i-th day, and H if a half pill was chosen (0 <= i < 2N). How many different valid strings are there that empty the bottle?
Input
The input will contain data for at most 1000 problem instances. For each problem instance there will be one line of input: a positive integer N <= 30, the number of pills initially in the bottle. End of input will be indicated by 0.
Output
For each problem instance, the output will be a single number, displayed at the beginning of a new line. It will be the number of different ways the bottle can be emptied.
Sample Input
6
1
4
2
3
30
0
Sample Output
132
1
14
2
5
3814986502092304
Source
The 2011 Rocky Mountain Regional Contest

题目大意:

一共有N片药,每次吃半片,我们视为所有药片是相同没有区别的,如果我们取出来的是完整的一片,那么吃半片,把剩下的半片放回去。

问已知有N片药,能够有多少种吃法。


思路:


1、(记不住某次训练dp的时候遇到一个括号匹配相关的问题,但是和卡特兰数不想干,但是我怎么做来着搞出来个解的相关序列,用OEIS一查是卡特兰数.........那个序列就是说,我们已知有2N个括号,对应需要将其完美匹配,问有多少种分配方式)初次接触卡特兰数,记忆比较深刻啊~


2、我们考虑设定dp【i】【j】,表示当前dp过程进行到第i位,一共使用了j个右括号的方案数。

那么不难推出其状态转移方程:

dp【i】【j】=dp【i-1】【j-1】+dp【i-1】【j】;

这里有一个限制,对应i-j需要大于等于j才行,这里i-j表示左括号的个数,因为我们要得到一个完美匹配,所以我们在第i位的时候,肯定是左括号只能大于等于右括号的个数才行。


3、那么将上述模型套入本题,将完整的药片看成左括号,将一半的药片看成右括号。那么模型是一样的,所以按照上述dp方式直接搞即可。


Ac代码:


#include<stdio.h>
#include<string.h>
using namespace std;
#define ll long long int 
ll dp[70][35];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(n==0)break;
        dp[0][0]=1;
        for(int i=1;i<=n*2;i++)
        {
            for(int j=0;j<=i&&j<=n;j++)
            {
                if(i-j>=j)
                dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
            }
        }
        printf("%lld\n",dp[2*n][n]);
    }
}











  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值