Loading

UNR #10 D2T2 补题记录

完全想不到点双啊,如果有个点双部分分感觉真过了。

注意到点双的性质:dfs 树中,子树内可以绕过父亲到达更上方的祖先。这意味着非叶子不能作为根,否则有横叉边。对于叶子,如果祖先有分岔也不行,又因为 dfs 树的根只有一个儿子,所以唯一能作为根的情况是:一条链,链头和链尾可以作为根。

这样就可以直接 dp 求 dfs 树的个数,不需要关心其他点作为根。然后算哈密顿路径数量,如果图是点双就做完了。

图不是点双时,对于每个点双求不同点作为根时 dfs 树数量,以及两两之间的哈密顿路径数量。哈密顿数量求解可以这样:随便找一个点作为中转点,以该点为起点 dp,对于两个点求答案时,可以枚举中转点两边的点集。

注意到可以作为根的点在园方树上形成一条路径,可以点边容斥,总时间复杂度 \(\mathcal O(2^n n^2)\)

点击查看代码
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define pir pair <ll, ll>
#define fi first
#define se second
#define mkp make_pair
#define pb push_back
#define i128 __int128
#define uLL unsigned LL
#define For(i, a, b) for(ll i = a; i <= b; i++)
#define DFor(i, a, b) for(ll i = a; i >= b; i--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
template <class T1, class T2> void chkmax(T1 &x, const T2 y) { x = x < y? y : x; }
template <class T1, class T2> void chkmin(T1 &x, const T2 y) { x = x < y? x : y; }
template <class T> void rd(T &x) {
    char ch; bool f = 0;
    while(!isdigit(ch = getchar()))
        if(ch == '-') f = 1;
    x = ch - '0';
    while(isdigit(ch = getchar()))
        x = (x << 1) + (x << 3) + ch - '0';
    if(f) x = -x;
}
const ll maxn = 1e6 + 10, mod = 998244353;
template <class T1, class T2>
void add(T1 &x, const T2 y) { x = x + y >= mod? x + y - mod : x + y; }
template <class T1, class T2>
void sub(T1 &x, const T2 y) { x = x < y? x + mod - y : x - y; }
template <class T1, class T2>
ll pls(const T1 x, const T2 y) { return x + y >= mod? x + y - mod : x + y; }
template <class T1, class T2>
ll mus(const T1 x, const T2 y) { return x < y? x + mod - y : x - y; }
using namespace std;

struct FastMod {
    LL m, p;
    FastMod(ll P) { m = ((i128) 1 << 64) / P, p = P; }
    ll mod(LL x) {
        x -= (((i128) x * m) >> 64) * p;
        return x < p? x : x - p;
    }
} F(mod);

ll n, m, dfn[22], low[22], ti, stk[22], top, cnt, h[44][22], c[22][22];
vector <ll> to[22], g[44];
bool vis[22];

ll k, f[1 << 20][22], e[22], id[22], now, s[22], len, ld[1 << 20];
ll dp[1 << 20][22];
void dfs(ll u) {
    now ^= 1 << u - 1, s[len] |= 1 << u - 1;
    while(e[u] & now) {
        ll v = ld[e[u] & now];
        dfs(v);
    }
}
void work(ll S) {
    now = S, len = 0;
    For(i, 1, k)
        if(now & (1 << i - 1)) s[++len] = 0, dfs(i);
}
vector <ll> vec[1 << 20];
void solve(ll t, vector <ll> p) {
    k = p.size();
    For(i, 1, n) id[i] = -1;
    For(i, 0, k - 1) id[p[i]] = i;
    For(i, 1, k) {
        ll x = p[i - 1]; e[i] = 0;
        for(ll y: to[x])
            if(id[y] >= 0) e[i] |= 1 << id[y];
    }
    For(S, 0, (1 << k) - 1) 
        For(i, 1, k) f[S][i] = dp[S][i] = 0;
    For(i, 1, k) f[0][i] = 1;
    // debug("SF\n");
    For(S, 1, (1 << k) - 2) {
        work(S);
        // debug("RF %d %d\n", S, (1 << k) - 1 - S);
        for(ll i: vec[(1 << k) - 1 - S]) {
            // if(S == 3) debug("P %d\n", i);
            ll w = 1;
            For(j, 1, len) {
                ll sum = 0;
                for(ll x: vec[e[i] & s[j]])
                    add(sum, f[s[j] ^ (1 << x - 1)][x]);
                w = F.mod((LL) w * sum);
            }
            f[S][i] = w;
        }
    }
    dp[1][1] = 1;
    For(S, 1, (1 << k) - 2) {
        if(S & 1 ^ 1) continue;
        for(ll i: vec[S])
            for(ll j: vec[((1 << k) - 1 - S) & e[i]])
                add(dp[S | (1 << j - 1)][j], dp[S][i]);
    }
    For(i, 1, k) h[t][p[i - 1]] = f[(1 << k) - 1 - (1 << i - 1)][i];
    static ll q[22][22];
    For(i, 1, k)
        For(j, i + 1, k) q[i][j] = 0;
    for(ll S = 1; S < (1 << k) - 2; S += 2)
        For(i, 1, k)
            For(j, i + 1, k)
                add(q[i][j], F.mod((LL) dp[S][i] * dp[(1 << k) - S][j]));
    For(i, 1, k)
        For(j, i + 1, k) {
            ll x = p[i - 1], y = p[j - 1];
            c[x][y] = c[y][x] = q[i][j];
        }
}

void tarjan(ll u, ll fa = 0) {
    stk[++top] = u, vis[u] = true;
    dfn[u] = low[u] = ++ti;
    for(ll v: to[u])
        if(v ^ fa) {
            if(vis[v]) chkmin(low[u], dfn[v]);
            else {
                tarjan(v); chkmin(low[u], low[v]);
                if(low[v] >= dfn[u]) {
                    vector <ll> d; d.pb(u);
                    do d.pb(stk[top]); while(stk[top--] ^ v);
                    ++cnt;
                    for(ll x: d) g[cnt].pb(x), g[x].pb(cnt);
                    // debug("sv %d\n", cnt);
                    solve(cnt, d);
                }
            }
        }
}

ll par[44];
void tdfs(ll u, ll fa = 0) {
    par[u] = fa;
    for(ll v: g[u])
        if(v ^ fa) tdfs(v, u);
}

int main() {
    // freopen("dfs7.in", "r", stdin);
    // freopen("dfs.out", "w", stdout);
    rd(n), rd(m); cnt = n;
    For(S, 1, (1 << n) - 1) {
        ld[S] = (S & 1? 0 : ld[S >> 1]) + 1;
        For(i, 1, n)
            if(S & (1 << i - 1)) vec[S].pb(i);
    }
    For(i, 1, m) {
        ll u, v; rd(u), rd(v);
        to[u].pb(v), to[v].pb(u);
    }
    tarjan(1);
    ll ans = 0;
    For(i, 1, n) {
        tdfs(i);
        ll w = 1;
        For(j, n + 1, cnt) w = (LL) w * h[j][par[j]] %mod;
        add(ans, w);
        For(j, i + 1, n) {
            if(par[par[j]] ^ i) continue;
            ll t = par[j];
            w = c[j][i];
            For(k, n + 1, cnt)
                if(k ^ t) w = (LL) w * h[k][par[k]] %mod;
            sub(ans, w);
        }
    }
    printf("%d\n", ans);
    return 0;
}
posted @ 2026-07-13 12:06  Sktn0089  阅读(30)  评论(0)    收藏  举报