SHOI2016 黑暗前的幻想鄉

2022-05-09 10:27:09 字數 1438 閱讀 5758

嘟嘟嘟

這題昨天看覺得沒有思路,今天看了一眼覺得就是個水題。

首先如果不考慮每乙個人只能選一條路的話,那就是求一張無向圖(有重邊,有自環)的生成樹個數。這個直接用矩陣樹定理+高斯消元求解行列式即可解決。

現在有了限制,怎麼辦?

容斥!其實和[zjoi2016]小星星這道題有點像。

想一下,如果乙個公司修了兩條路,那麼一定會有乙個公司哪條路都沒修。所以我們容斥一下:每乙個公司修一條路的方案數=至少有0個公司沒有修路的方案數-至少有1個公司沒修路+至少2個公司沒修路-至少3個公司沒修路……所以\(o(2 ^n)\)列舉沒修路的公司,然後每一次用修路的公司構造基爾霍夫矩陣,然後高斯消元求解。

複雜度\(o(2 ^ n * n ^ 3)\)。實際上跑的很快。

寫完後debug了一會兒,發現是因為鄰接矩陣我都賦值成了1,實際上應該遇到一條邊就+1。

#include#include#include#include#include#include#include#include#include#include#includeusing namespace std;

#define enter puts("")

#define space putchar(' ')

#define mem(a, x) memset(a, x, sizeof(a))

#define in inline

typedef long long ll;

typedef double db;

const int inf = 0x3f3f3f3f;

const db eps = 1e-8;

const int maxn = 20;

const ll mod = 1e9 + 7;

in ll read()

in void write(ll x)

in void myfile()

int n;

int e[maxn][maxn * maxn][2], cnt[maxn];

in ll inc(ll a, ll b)

in ll quickpow(ll a, ll b)

int a[maxn][maxn], d[maxn][maxn];

in void build(int pos)

}ll f[maxn][maxn];

in ll gauss()

}ll ans = 1;

for(int i = 1; i <= n; ++i) ans = ans * f[i][i] % mod;

return ans;

}int main()

ll ans = 0;

for(int s = 0; s < (1 << (n - 1)); ++s)

write(ans), enter;

return 0;

}

SHOI2016 黑暗前的幻想鄉

點此看題 好久沒有做過這麼版的題了 首先你要知道指數級容斥,也就是我們列舉乙個公司集合,表示我們只在這些公司中選邊,那麼我們就用全部公司 少乙個公司 少兩個公司 來計算就行。知道邊算生成樹,不就是矩陣樹定理麼?include include include include using namespa...

SHOI2016 黑暗前的幻想鄉

幻想鄉是個什麼東西?逃 就是設 dp i 表示至多i個公司修建道路,那麼我們有 ans dp n 1 dp n 2 dp n 3 balabala 就是那個容斥公式嘛qwqwq 然後每次都跑一次矩陣樹定理qwqwq 但是這樣的時間複雜度是 o n 32 所以說。跑的。2s。很勉強qwqwq 如下 i...

SHOI2016 黑暗前的幻想鄉

如果沒有建築公司的限制,那麼就是個 mathrm 板子 其實有了也一樣 發現 n leq 17 考慮容斥 每次欽定一些建築公司,計算它們包含的邊的生成樹的方案數 複雜度 mathrm 2 nn 3 include include include include define rg register ...