Codeforces 340E 錯排問題dp

2021-08-04 05:37:16 字數 1298 閱讀 9954

給出一串長度為n的序列a,將1~n填入序列中-1的位置,使得整個序列是乙個1~n的排列,而且保證a[i]!=i,問一共有多少種構造方案。

錯排問題,這裡有了限制條件,有些位置已經被數字填過。

這裡將數字分成不同的型別:

已經被用過的數不用考慮

沒有被用過的數,但自己的位置已經被占用,這種數為無限制數,因為可以填在任意-1的位置,這樣的數有cnt2個

沒有被用過的數,而且自己的位置沒有被占用,這種數為有限制數,它不能填在自己的位置上,這樣的數有cnt1個

那麼先填有限制數,因為很顯然無限制數可以填在任意-1位置,最後有限制的數的方案數乘上無限制數的全排列數即可。

設dp[i]為i個有限制的數填好滿足條件的方案數,考慮第i個數:

它可以填在任意無限制數的最終能填的位置上,錯排數+1,從dp[i-1]轉移過來,一共有cnt2個無限制數,所以方案數為cnt2

若前i-1個數全部錯排,那麼它可以和這i-1個數的任意乙個交換位置,構造出前i個數完全錯排,從dp[i-1]轉移過來,方案數為i-1

若前i-1個數中有i-2個數完全錯排,只有1個數排對,拿第i個數和這個排對的數交換,也可以構造出前i個數完全錯排,這個排對的數有i-1種可能,因此方案數為i-1,從dp[i-2]轉移過來

因此狀態轉移方程為:

dp[i] = dp[i-1] * cnt2 + dp[i-1] * (i-1) + dp[i-2] * (i-1)

最後dp[cnt1] * f[cnt2]即為答案,其中f[cnt2]為cnt2的階乘。

#include 

using

namespace

std;

typedef

long

long ll;

const ll mod = 1e9 + 7;

const

int maxn = 2005;

ll dp[maxn], f[maxn];

int a[maxn], pos[maxn], vis[maxn];

int main()

f[0] = 1;

for (int i = 1; i <= n; i++)

int cnt1 = 0, cnt2 = 0;

for (int i = 1; i <= n; i++)

}dp[0] = 1;

for (int i = 1; i <= cnt1; i++)

printf("%i64d\n", dp[cnt1] * f[cnt2] % mod);

return

0;}

CodeForces 340B 幾何 暴力

給出平面上4 n 300 4 leq n leq300 4 n 30 0個點,然後要求取四個點構成多邊形,並且面積最大。然後題目特別說明了不保證多邊形是凸多邊形。列舉四個點太慢,不妨把凸多邊形分解為兩個三角形,然後列舉多邊形的對角線,再列舉所有的點用叉積判斷點是否在直線的上方和下方並且更新答案。乙個...

Codeforces 976E 題解報告

1 當把所有的倍數2 a都加到同一health上,health增加的最多 2 先計算每乙個creature的hp dmg,按該值對所有的creature排序 再求和,i include using namespace std const int n 200 1000 9 int hp n dmg n...

codeforces 1030E 暴力 思維)

題目 題意 給定一些數,可將區間 l r 中某些數的二進位制位的1的位置更換,使得最終區間所有數異或和為0,求這樣的區間個數。思路 在那裡瞎dp了好久,wa的很徹底,借鑑了一下別人的思路。區間合法的條件是 這個區間1的個數為偶數,並且區間中二進位制位1最多的乙個數的二進位制個數小於等於和的一半。我們...