k上升段,對於排列問題的處理
阿新 • • 發佈:2017-09-23
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上升段,對於排列問題的處理