题意: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
#include
#include
#include
#include
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;
}