HDU 4689 Derangement【DP递推】【好题】【思维题】

Derangement

Time Limit: 7000/7000 MS (Java/Others)    Memory Limit: 65535/102400 K (Java/Others)
Total Submission(s): 1170    Accepted Submission(s): 396


Problem Description
A derangement is a permutation such that none of the elements appear in their original position. For example, [5, 4, 1, 2, 3] is a derangement of [1, 2, 3, 4, 5]. Subtracting the original permutation from the derangement, we get the derangement difference [4, 2, -2, -2, -2], where none of its elements is zero. Taking the signs of these differences, we get the derangement sign [+, +, -, -, -]. Now given a derangement sign, how many derangements are there satisfying the given derangement sign?
 

Input
There are multiple test cases. Process to the End of File.
Each test case is a line of derangements sign whose length is between 1 and 20, inclusively.
 

Output
For each test case, output the number of derangements.
 

Sample Input
 
  
+- ++---
 

Sample Output
 
  
1 13
 

Author
Zejun Wu (watashi)
 

Source

题意:1到n的n个数,打乱后减去原来的数的正负号,形成一串正负号的字符串,如[1,2,3,4,5]打乱后变成[5,4,1,2,3]就是[+,+,-,-,-]。给定这样一串正负号形成的字符串,有几种排列方式。

dp[i][j]表示前i个位置中有j个空位(+号)没有确定负号全部确定

“+'时

要么使空位增加,要么不变

增加时,直接空位增加:dp[i][i]+=dp[i-1][j-1]

不变时,表示把当前的数填到前面未确定的j个空位中去:dp[i][j]+=dp[i-1][j]*j

‘-'时,因为必须确定

要么减少,要么不变

不变时,表示把当前数填到前面的j个空位中:dp[i][j]+=dp[i-1][j]*j

减少时,表示把当前数填到前j-1位中去,再从前j-1位中拿一个数填到当前位:dp[i][j]+=dp[i-1][j-1]*(j-1)*(j-1)


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define ll long long

ll dp[30][30];
char num[100];

int main()
{
	while (~scanf("%s", num))
	{
		int len = strlen(num);
		memset(dp, 0, sizeof(dp));
		dp[0][0] = 1;
		for (int i = 1; i <= len; i++)
		{
			if (num[i - 1] == '+')
			{
				for (int j = 0; j <= i; j++)
				{
					dp[i][j] += dp[i - 1][j - 1];
					dp[i][j] += dp[i - 1][j] * (ll)j;
				}
			}
			else
			{
				for (int j = 0; j <= i; j++)
				{
					// dp[i][j - 1] += dp[i - 1][j] * j * j;
					dp[i][j] += dp[i - 1][j] * (ll)j;
					dp[i][j] += dp[i - 1][j + 1] * (ll)(j + 1) * (ll)(j + 1);
				}
			}
		}
		// printf("%lld\n", dp[len][0]);
		cout << dp[len][0] << endl;
	}
	return 0;
}




转载于:https://www.cnblogs.com/Archger/p/8451629.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值