Pills | ||||||
| ||||||
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]);
}
}