1. 程式人生 > 其它 >luogu P7531 [USACO21OPEN] Routing Schemes P

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
*/