luogu P7531 [USACO21OPEN] Routing Schemes P
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
*/