1. 程式人生 > >k上升段,對於排列問題的處理

k上升段,對於排列問題的處理

style col 不用 處理 -1 std 排列 -c 描述

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上升段,對於排列問題的處理