luogu P7531 [USACO21OPEN] Routing Schemes P
阿新 • • 發佈:2021-12-21
https://www.luogu.com.cn/problem/P7531
玄妙DP題被BEST定理淦過去的這個出題人Benq就是遜啊
首先回憶一把\(BEST\)定理是什麼
一個有向圖歐拉回路的數量設為\(F\),一個以\(rt\)為根的內向生成樹個數為\(G\)
\[T=G\prod_{i=1}^n (in[i]-1)! \]即每個內向樹對應\(\prod(in[i]-1)!\)條歐拉回路,證明考慮雙射不難
那麼對於這題呢?
我們建一個虛點,向每個\(S\)連邊,每個\(T\)向虛點連邊,跑矩陣樹即可
code:
#include<bits/stdc++.h> #define ll long long #define mod 1000000007 #define N 205 using namespace std; ll qpow(ll x, ll y) { ll ret = 1; for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod; return ret; } ll a[N][N]; ll DET(int n) { ll ans = 1; for(int i = 1; i <= n; i ++) { int j = i; for(int k = i; k <= n; k ++) if(a[k][i]) j = k; if(j != i) ans = mod - ans, swap(a[j], a[i]); for(int j = i + 1; j <= n; j ++) { ll t = a[j][i] * qpow(a[i][i], mod - 2) % mod; for(int k = i; k <= n; k ++) { a[j][k] = (a[j][k] - a[i][k] * t % mod + mod) % mod; } } } for(int i = 1; i <= n; i ++) ans = ans * a[i][i] % mod; return ans; } int n, k, in[N][N], py[N]; ll fac[N]; char st[N]; void solve() { scanf("%d%d", &n, &k); int tot = 0; for(int i = 0; i <= n; i ++) for(int j = 0; j <= n; j ++) a[i][j] = in[i][j] = 0; scanf("%s", st + 1); for(int i = 1; i <= n; i ++) if(st[i] == 'S') in[i][i] ++; for(int i = 1; i <= n; i ++) { scanf("%s", st + 1); for(int j = 1; j <= n; j ++) if(st[j] == '1') in[i][j] = mod - 1, in[j][j] ++; } for(int i = 1; i <= n; i ++) if(in[i][i]) py[i] = ++ tot; else py[i] = 0; for(int i = 1; i <= n; i ++) if(py[i]) for(int j = 1; j <= n; j ++) if(py[j]) { a[py[i]][py[j]] = in[i][j]; } ll ans = 1; for(int i = 1; i <= tot; i ++) ans = ans * fac[a[i][i] - 1] % mod; ans = ans * DET(tot) % mod; // 刪掉超級點 printf("%lld\n", ans); } int t; int main() { // freopen("a.out","w",stdout); scanf("%d", &t); fac[0] = 1; for(int i = 1; i <= 100; i ++) fac[i] = fac[i - 1] * i % mod; while(t --) solve(); return 0; } /* 1 6 0 SR.S.R 010000 000000 000000 000010 000001 000000 */