乙個陣列a = [1, 2, 3, …, n]。
對a進行好恰好k次相鄰交換,能得到多少個不同的序列 (s1)?
對a進行最多k次交換,你能得到多少個不同的序列 (s2)?
一次相鄰交換是指交換陣列a中兩個相鄰位置的元素,即:交換a[i]和a[i+1]或者a[i]和a[i-1]。
一次交換是指交換陣列a中的任意兩個位置不同的元素,即:交換a[i]和a[j],1 <= i, j <= n, i != j。
給出陣列a的長度n,以及次數k,求s1和s2。由於結果很大,輸出mod 1000000007的結果。
例如:原始陣列: [1, 2, 3]
1. 經過兩次相鄰交換:
我們得到 [1, 2, 3], [2, 3, 1], [3, 1, 2] ==> s1 = 3
2. 經過最多兩次交換:
1) 0次交換後: [1, 2, 3]
2) 1次交換後: [2, 1, 3], [3, 2, 1], [1, 3, 2].
3) 兩次交換後: [1, 2, 3], [2, 3, 1], [3, 1, 2] ==> s2 = 6
第乙個問:設f[
i][j
] 表示做到i,交換次數為j。
那麼通過第i個不斷往前交換就可以使得被考慮到的所有序列不重不漏。顯然f
[i][
j]=f
[i−1
][j−
i+1]
+...
+f[i
−1][
j]。
所以用乙個字首和優化即f[
i][j
]+=f
[i][
j−1]
就可以o(
1)轉移了。
答案就是σ(
i−k)
mod2
=0f[
n][i
] ,因為只要i與k奇偶性一樣,就可以無聊地交換到k次。
第二個問:更簡單,設f[
i][j
] 表示做到i,交換次數為j。
第i個數可以向前面i-1個位置交換,所以 f[
i][j
]=f[
i−1]
[j]+
f[i−
1][j
−1]∗
(i−1
) .
答案為σni
=1f[
n][i
] 這道題目教會我們對於序列dp,通常可以想到「通過第i個不斷往前交換就可以使得被考慮到的所有序列不重不漏」。可以解決一部分序列上的簡單dp
#include
#include
#include
#include
#include
#define n 3005
#define ll long long
#define mo 1000000007
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
ll f[n][n];
ll i,j,k,l,n,m,ans;
int main()
if (i) fo(j,1,k) f[i][j]=(f[i][j]+f[i][j-1])%mo;
}fo(i,0,k)if(i%2==k%2)ans=(ans+f[n][i])%mo;
printf("%lld ",ans);
memset(f,0,sizeof(f));
f[0][0]=1;
fo(i,1,n)
ans=0;
fo(i,0,k) ans=(ans+f[n][i])%mo;
printf("%lld",ans);
return
0;}
51nod 1250 排列與交換
題目大意 你有乙個初始為 1 到 n的順序陣列 問題一 恰好進行 k 次相鄰交換,最後有多少不同的排列 問題二 進行不多於 k次交換 不一定相鄰 最後有多少種不同的排列 n k 3000 思路 這道題沒有什麼新意,其主要思路就是將恰好變為最少,即乙個排列我們要用最少的操作次數得到。對於第一問,考慮乙...
51nod 1250 排列與交換
對a進行好恰好k次相鄰交換,能得到多少個不同的序列 s1 對a進行最多k次交換,你能得到多少個不同的序列 s2 一次相鄰交換是指交換陣列a中兩個相鄰位置的元素,即 交換a i 和a i 1 或者a i 和a i 1 一次交換是指交換陣列a中的任意兩個位置不同的元素,即 交換a i 和a j 1 i,...
51nod 1574 排列轉換
現在有兩個長度為n的排列p和s。要求通過交換使得p變成s。交換 pi 和 pj 的代價是 i j 要求使用最少的代價讓p變成s。單組測試資料。第一行有乙個整數n 1 n 200000 表示排列的長度。第二行有n個範圍是1到n的整數,表示排列p。每個整數只出現一次。第三行有n個範圍是1到n的整數,表示...