看到資料範圍很容易想到 dp 方程式
設 \(f[i][j]\) 代表已經連了 \(i\) 條邊, 還有 \(j\) 個奇數點, 並且方案全部合法的方案數
那麼有\[\displaystyle \beginf[i][j] = &f[i - 1][j + 2]*\binom\\+&f[i - 1][j - 2]*\binom\\+&f[i - 1][j]*(n-j)*j\end
\]分別代表連兩個奇數點, 兩個偶數點, 乙個奇數點乙個偶數點
注意一下邊界即可
但是問題在這裡, 這次連的邊有可能與之前新連的某一條邊重合, 這樣方案就不合法了, 我們可以強制這兩條邊是先後連的
因為我們求的是連邊的方案, 沒有順序, 所以這樣不會對答案造成影響
即\[\displaystyle f[i][j] -= f[i - 2][j]*(\binom-(i-2))
\]這兩條邊先後連, 所以在這之前已經連了 \(i - 2\) 條邊, 這條邊可能連在任意兩個點中間, 但是不能與之前的那 \(i - 2\) 條邊相重複了, 因為實際上我們是把 dp 的兩步轉移並做了一步, 若與之前的 \(i - 2\) 條邊重合了, 那麼在第一次轉移後的 \(f\) 就不符合全部合法的定義了
除此之外, 每次轉移完之後都要除以 \(i\) , 因為方案是無序的
舉乙個例子, 比如說上次我們連邊的方案分別是 \((1, 2)\) , \((2, 3)\) , \((1, 3)\)
若這次我們分別連上 \(3\) , \(1\) , \(2\) , 那麼三種方案最終都是 \((1, 2, 3)\) , 重複了
所以要除去 \(i\)
#include #include #include #include const int n = 1005;
const int mod = 10007;
using namespace std;
int n, m, k, d[n], c[n][n], f[n][n], inv[n], cnt;
template < typename t >
inline t read()
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w; }
int main()
printf("%d\n", f[k][0]);
return 0;
}
bzoj 2169 連邊 DP 容斥
題目 就和這篇部落格說的一樣 注意每次是 i 而不是 i 因為 i 1 時也已經去了重,現在就是對於新加一條邊的多種方式帶來一種局面去重,從每一種局面看,新加的邊可以是任意一條,所以 i。如下 include include include include using namespace std t...
退役四連測題解(一)
有q只猴子要從第一棵樹到第n棵樹去,第i只猴子一次跳躍的最遠距離為ki。如果它在第x棵樹,那它最遠可以跳到第x ki棵樹。如果第j棵樹的高度比第i棵樹高或相等,那麼它從第i棵樹直接跳到第j棵樹,它的勞累值會增加1。所有猴子一開始在第一棵樹,請問每只猴子要跳到第n棵樹花費的勞累值最小。第一行乙個整數n...
題解 BZOJ 4717 裝備
傳送門 由於這道題是許可權題,所以題面我也放在這裡了 我不是許可權狗 題目背景 小q最近喜歡上了一款遊戲,名為 艦隊connection 在遊戲中,小q指揮強大的艦隊南征北戰,從而成為了一名dalao。在遊戲中,不僅船隻能力很重要,搭配合適的裝備更是如虎添翼。小q潛心研究配裝三十年,終於 把裝備湊齊...