HDU-4489-The King’s Ups and Downs

HDU-4489-The King’s Ups and Downs

这道题是一道组合dp=-=嘻嘻
传送门

怎么这么巧捏,我昨天刚刚写了个组合的代码跑概率论,结果今天就来了个组合dp,昨天还苦恼着组合问题都忘了的人,今天就快乐到飞起了哈哈哈

题目大概就是让你求波浪的序列有多少个=-=
其实我不懂它给的d有什么用,反正我就把它输入之后然后输出就没了=-=
其余的都是预处理打表的。。。
这个波浪序列就是说高矮高矮或者矮高矮高排列的,这里的高矮是相对的。
我们考虑
将一个最高的第n个人排入到已经排好的n-1个人中,假设插入的位置是j.
那么这个最高的第n个人的左边一定是以高低结尾的
同理这个最高的第n个人的右边一定是以低高结尾的
则我们设
dp[i][0]表示长度为i的序列以低高开头的方法数
dp[i][1]表示长度为i的序列以高低结尾的方法数
同时考虑组合情况,因为第n个人的左边有j-1个人,右边有n-j个人
考虑从n-1个人中选j-1个人到左边即可,就是C(j-1,n-1)
那么此时的方法数就是dp[n-j][0] * dp[j - 1][1] * C(j - 1, n - 1)
我们再想想如果j正好处于中间的位置,即左边的人数等于右边的人数。
那么此时的方法数dp[i][0] = dp[i][1]
我们用一个数组ans[i]表示i个人满足要求的排列总数
那么这些排列总数中一定是对称的,即以高低结尾的方法数等于以低高开头的方法数。因为这些排列是对称的嘛。
所以就有dp[i][0] = dp[i][1] = ans[i] / 2;

好啦!我解释完啦~~

上代码啦~

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

ll dp[25][2];
ll c[25][25];
ll ans[25];

void Combine()
{
	for (int i = 0; i <= 20; i++)
	{
		c[i][0] = 1;
	} 
	for (int i = 1; i <= 20; i++)
	{
		for (int j = 1; j <= i; j++)
		{
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
		}
	}
}

void solve()
{
	ans[1] = 1;
	dp[0][0] = dp[0][1] = 1;
	dp[1][0] = dp[1][1] = 1;
	
	for (int i = 2; i <= 20; i++)
	{
		ll cnt = 0;
		for (int k = 0; k <= i; k++)
		{
			int j = i - k - 1;
			cnt += dp[k][0] * dp[j][1] * c[i - 1][j];
		}
		ans[i] = cnt;
		dp[i][0] = dp[i][1] = cnt / 2;
	} 
}

int main()
{
	Combine();
	solve();
	int t;
	cin >> t;
	while (t--)
	{
		ll n, d;
		cin >> d >> n;
		cout << d << " " << ans[n] << endl;
	}
	return 0;
}
发布了39 篇原创文章 · 获赞 2 · 访问量 999

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/104616101