码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-09-23 17:16:15      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:namespace   输出   long   div   pre   一个   define   处理   排列   

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

 

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

标签:namespace   输出   long   div   pre   一个   define   处理   排列   

原文地址:http://www.cnblogs.com/star-eternal/p/7581477.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!