題目鏈結
題意:給定n,要求構造滿足要求的排列,對於其中的一些成員,值大於左右鄰居,對於另一些成員,值小於左右鄰居。輸出滿足條件的排列種數。
思路:設dp[
i][j
]dp[i][j]
dp[i][
j]為前i
ii 個數構成的滿足條件的合法排列,且末尾為j
jj的個數。
那麼對於第i
ii個數,我們只需要考慮其與左鄰居的關係(第i個數與右鄰居的關係等價於第(i+1)個數與左鄰居的關係)
構建乙個陣列a
aa如果第i
ii個數大於左鄰居,則a[i
]=
1a[i] = 1
a[i]=1
如果第i
ii個數小於左鄰居,則a[i
]=
0a[i] = 0
a[i]=0
如果第i
ii個數等於左鄰居,則a[i
]=−1
a[i] = -1
a[i]=−
1 另外還需要考慮的乙個問題是,當我們在考慮前i
ii個數組成的排列且末尾為j
jj時,我們如何通過dp[
i−1]
dp[i-1]
dp[i−1
]的值來快速推出dp[
i]
dp[i]
dp[i
]的值,因為當j
<
ij < i
j<
i時,對於dp[
i−1]
dp[i-1]
dp[i−1
]陣列中的合法排列,j
jj是有可能已經出現在這些排列的中間,如果再在末尾插入j
jj,就出現了排列中有兩個j
jj的矛盾。
那應該如何來解決這個問題呢?此時有乙個非常巧妙也非常經典的構建新排列的方式,當我們在乙個排列的末尾插入j
jj時,為避免衝突,我們將原排列的所有不小於j
jj的數通通+1+1
+1,這樣的好處時,既不破壞原排列相鄰數之間的大小關係,同時也避免了兩個j
jj出現的可能。
故此時就可以利用排列的構造方法來求得dp的狀態轉移方程了:
當a [i
]=
1a[i] = 1
a[i]=1
時 d p[
i][j
]=∑k
=1j−
1dp[
i−1]
[k
]dp[i][j] = \sum_^dp[i-1][k]
dp[i][
j]=∑
k=1j
−1d
p[i−
1][k
]當a[i]
=0
a[i] = 0
a[i]=0
時 d p[
i][j
]=∑k
=ji−
1dp[
i−1]
[k
]dp[i][j] = \sum_^dp[i-1][k]
dp[i][
j]=∑
k=ji
−1d
p[i−
1][k
]當a[i]
=−
1a[i] = -1
a[i]=−
1時 dp[
i][j
]=∑k
=1i−
1dp[
i−1]
[k
]dp[i][j] = \sum_^dp[i-1][k]
dp[i][
j]=∑
k=1i
−1d
p[i−
1][k
] 此題得解。
**:
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
typedef
long
long ll;
const
int mod =
1e9+7;
const
int a =
5000+10
;int dp[a]
,sum[2]
[a],a[a]
;int
main()
for(
int i=
1;i<=l ;i++
) a[x]=1
;a[x+1]
=0;}
if(flag ==0)
puts
("0");
else
} ll ans =0;
for(
int i=
1;i<=n ;i++)if
(ans <
0) ans +
= mod;
printf
("%i64d\n"
,ans);}
return0;
}
51Nod 1296 有限制的排列
acm模版 個人感覺,這個應該算是數字 dp。先通過處理輸入資料獲取乙個 state,表示每相鄰兩項之間的大小關係,state i 0,表示無特別關係,state i 1 表示第 i 項小於第 i 1 項,state i 2 表示第 i 項大於第 i 1 項。接著搞乙個 dp i j 表示由前 i ...
51Nod 1296 有限制的排列
計算整數集合滿足下列條件的的排列個數 在位置a1,a2,ak小於其鄰居 編號從0開始 在位置b1,b2,bl大於其鄰居。輸出符合條件的排列數量mod 1000000007的結果。例如 n 4,a b 符合條件的排列為 2 1 4 3 3 2 4 1 4 2 3 1 3 1 4 2 4 1 3 2 i...
51Nod 1020 逆序排列(DP)
題目鏈結 題目描述 在乙個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱為乙個逆序。乙個排列中逆序的總數就稱為這個排列的逆序數。如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序數是4。1 n的全排列中,逆序數最小為0 正序 最大為n n 1 2 倒序 ...