T2
【題目描述】
將到任意排列,然後在排列的每兩個數之間根據他們的大小關係插入和。問在所有排列中,有多少個排列恰好有個。答案對取模。
【輸入格式】
第一行個整數。
【輸出格式】
一個整數表示答案。
【樣例輸入】
5 2
【樣例輸出】
66
【數據範圍】
對於%的數據:
對於%的數據:
思路:
看到這一題,求方案數,那肯定就是動態規劃啦。
假設我們已經把前 個數排列好並且已經標號 號以及 號,這時候我們在增加i這個數,有 個位置可以選擇。但有一點需要注意的是,不論插在哪兩個數中間(即不論替換掉哪個不等號),形式都爲(或或)。
舉個例子,若已有不等數列:
接下來我們插入 這個數,則有 種情況:
然後我想到的就是表示狀態的方法:用表示用 ~ 組成的不等數列中,號數等於的方案數。
接下來思考的就是狀態轉移方程。
首先,我們可以推出與的關係,即增加一個小於號有多少種方案。
不難推出,(原本不等數列大於號的數量加上,即原本符號數減去原本小於號數 加(若在數列最前面),即用,代替,相當於增加一個);
然後推出與的關係,即增加一個大於號有多少種方案。
(原本不等數列小於號的數量加上1)。
最後是邊界:。
以上就是我自己的思路,附上分代碼:
#include<bits/stdc++.h>
#define N 1000+10
using namespace std;
int mod=2012;
int f[N][N];
int n,k;
int main(){
memset(f,0,sizeof(f));
cin>>n>>k;
f[2][0]=1;f[2][1]=1;
for(int i=2;i<=n;i++)
for(int j=0;j<i;j++){
f[i+1][j+1]=(f[i+1][j+1]+(i-j)*f[i][j])%mod;
f[i+1][j]=(f[i+1][j]+(j+1)*f[i][j])%mod;
}
cout<<f[n][k];
return 0;
}
注意模數!
接下來附上老師提供的題解:
對於% 的數據,搜索打表,狀態壓縮動態規劃…
對於等類似的排列計數問題,以動態規劃和組合數學種大方向爲基本解決方向。
組合數學在最難也就到楊輝三角左右,所以這題我從動態規劃展開。
如果此類排列問題在腦中的模型是:“有個格子,填入”,那麼相對應的就不得不記錄哪些數填過了(從左到右填入)或者哪些格子填過了(從小到大填入)。這樣一來就必須要使用狀態壓縮來存儲這些信息,就使得複雜度變得難以接受。
而如果換個模型:“從小到大把數字插入數列”。注意是數列而不是格子,這樣一來就不需要記錄是哪些數字插入了(而只要記錄插入到了第幾個數字),同時不需要記錄每個數字的具體位置,也不需要記錄數字的相對位置,而只需記錄相對關係的數目(對本題而言就是有幾個)。
因爲是從小到大插入數字,所以當前插入的數字一定大於所有已經插入的。
藍色是當前插入的數字,如果它插入到關係的個數字之間(或者數列最左端),就會使數列的數量不變,數量:
類似的,插入到關係的個數字之間(或者數列最右端),數列的數量,數量不變。
表示前個數字構成的數列中,恰有個號的方案數(號就有個)。
.
時空複雜度:
若打表則時間複雜度爲
完結撒花!