k上升段,对于排列问题的处理

K上升段

问题描述:
对于n的一个全排列,如果它可以划分成k个单调递增序列,每个序列都尽可能最长,则称其为k上升段。例如:排列1 2 4 5 6 3 9 10 7 8是一个合法的3上升段,它可以划分成1 2 4 5 6;3 9 10;7 8这三个单调递增序列。对每个给定的(n,k),请你给出n的所有k上升段的个数。

输入格式:
输入仅有1行,包含两个数n, k(1 < n < 20, 1 < k < n)。

输出格式:
输出n的所有k上升段的个数。

样例
输入:
3 2
输出:
4
( 说明,符合条件的排列是132,312,213,231)

这道题不用深搜,用dp

对于一个全排列i,假设划分成了j段。

那么如果在每一段的末尾加一个数,那么就可以变成i+1个数的划分成为j段。

还有,如果在每一个头,或者非段末加入,那么就可以变成i+1个全排列划分成了j+1段

对于每一个位置,都可以是一种方案书,那么这就是加法原理和乘法原理

设dp(i,j)表示对于第i个数,划分成j段的方案数

dp(i,j)=dp(i-1,j)*j+dp(i-1,j-1)*(i-j+1)

码量很少附上代码

#include<cstdio>
#include<algorithm>
#define N 20+1
#define ll long long
using namespace std;
ll f[N][N];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)f[i][1]=f[i][i]=1;
    for(int i=2;i<=n;i++)
        for(int j=1;j<i;j++)
            f[i][j]=f[i-1][j]*j+f[i-1][j-1]*(i-j+1);
    printf("%lld",f[n][k]);        
}

 

posted @ 2017-09-23 16:03  star_eternal  阅读(294)  评论(0编辑  收藏  举报