码迷,mamicode.com
首页 > 其他好文 > 详细

Bzoj4784: [Zjoi2017]仙人掌

时间:2018-05-31 12:53:24      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:clu   reg   tar   const   geo   upd   https   void   bre   

题面

传送门

Sol

首先判断是能成为仙人掌

然后考虑\(DP\)
因为所有的环内不可能连边,那么直接删掉
变成一个森林
对每个树求出方案然后相乘就是答案

一个巧妙的转化:看成选取若干条路径恰好覆盖所有的树边的方案数

\(g[i]\)表示\(i\)个点两两配对的方案数
\(g[i]=g[i-1]+g[i-2]*(i-1)\)
即要么不配对,要么选一个配对

\(f[i]\)表示子树的方案数
首先\(f[u]=\Pi_{v\in{son(u)}} f[v]\)
\(sum\)\(u\)的儿子数
如果\(u\)不为根,那么还可以有一个点向上匹配\(f[u]+=g[sum+1]\)
否则\(f[u]+=g[sum]\)

# include <bits/stdc++.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

const int maxn(5e5 + 5);
const int mod(998244353);

int n, m, dfn[maxn], low[maxn], idx, g[maxn], f[maxn], cactus, sta[maxn], top, col[maxn];
bool vis[maxn << 2];

struct Edge{
    int first[maxn], cnt, nxt[maxn << 2], to[maxn << 2];

    IL void Init(){
        cnt = 0, Fill(first, -1);
    }

    IL void Add(RG int u, RG int v){
        vis[cnt] = 0, nxt[cnt] = first[u], to[cnt] = v, first[u] = cnt++;
    }
} e1;

IL void Tarjan(RG int u, RG int fe){
    dfn[u] = low[u] = ++idx, sta[++top] = u;
    RG int flg = 0;
    for(RG int e = e1.first[u]; e != -1; e = e1.nxt[e]){
        if(e == fe) continue;
        RG int v = e1.to[e];
        if(!dfn[v]){
            Tarjan(v, e ^ 1), low[u] = min(low[u], low[v]);
            if(low[v] < dfn[u]){
                if(flg) cactus = 0;
                flg = 1;
            }
        }
        else{
            low[u] = min(low[u], dfn[v]);
            if(dfn[v] < dfn[u]){
                if(flg) cactus = 0;
                flg = 1;
            }
        }
    }
    while(low[u] == dfn[u]){
        col[sta[top--]] = u;
        if(sta[top + 1] == u) break;
    }
}

IL void Upd(RG int &x, RG int y){
    x += y;
    if(x >= mod) x -= mod;
}

IL void Solve(RG int u, RG int rt){
    f[u] = dfn[u] = 1; RG int sum = 0;
    for(RG int e = e1.first[u]; e != -1; e = e1.nxt[e]){
        RG int v = e1.to[e];
        if(dfn[v] || vis[e]) continue;
        Solve(v, rt);
        f[u] = 1LL * f[u] * f[v] % mod;
        ++sum;
    }
    if(u != rt) f[u] = 1LL * f[u] * g[sum + 1] % mod;
    else f[u] = 1LL * f[u] * g[sum] % mod;
}

int main(){
    for(RG int t = Input(); t; --t){
        e1.Init(), cactus = 1, top = idx = 0, n = Input(), m = Input();
        for(RG int i = 1; i <= n; ++i) col[i] = dfn[i] = low[i] = f[i] = 0;
        for(RG int i = 1, a, b; i <= m; ++i)
            a = Input(), b = Input(), e1.Add(a, b), e1.Add(b, a);
        g[0] = g[1] = 1;
        for(RG int i = 2; i <= n + 1; ++i)
            g[i] = g[i - 1], Upd(g[i], 1LL * (i - 1) * g[i - 2] % mod);
        Tarjan(1, -1);
        if(!cactus){
            puts("0");
            continue;
        }
        for(RG int i = 1; i <= n; ++i)
            for(RG int e = e1.first[i]; e != -1; e = e1.nxt[e])
                if(col[i] == col[e1.to[e]]) vis[e] = 1;
        for(RG int i = 1; i <= n; ++i) dfn[i] = 0;
        RG int ans = 1;
        for(RG int i = 1; i <= n; ++i)
            if(!f[i]) Solve(i, i), ans = 1LL * ans * f[i] % mod;
        printf("%d\n", ans);
    }
    return 0;
}

Bzoj4784: [Zjoi2017]仙人掌

标签:clu   reg   tar   const   geo   upd   https   void   bre   

原文地址:https://www.cnblogs.com/cjoieryl/p/9116046.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!