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]); }
夫君子之行,
静以修身,俭以养德;
非澹泊无以明志,
非宁静无以致远。
夫学须静也,才须学也;
非学无以广才,非志无以成学。
慆慢则不能励精,
险躁则不能冶性。
年与时驰,意与日去,
遂成枯落,多不接世。
悲守穷庐,将复何及!