51Nod1250 排列與交換

2021-08-08 16:13:29 字數 1903 閱讀 3184

乙個陣列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的整數,表示...