ZJOI 2017 仙人掌

题链

SOL: 一道很奇怪的计数题。

 我们先考虑树的做法:

用h[i]表示有i个带匹配的子树,它们之间匹配的方案数

h[i]=h[i-1]+(i-1)*h[i-2]

  • 如果i子树不与其他子树相连,那么方案就是h[i−1]
  • 如果与其他子树连接,那么有(i−1)中选择方式,而当选择一个子树以后,有两个子树不能再连接,那么方案就是(i−1)∗h[i−2]

 

  f[i]表示做完以i为根的子树,且没有路径可以向上扩展。 
  g[i]表示做完以i为根的子树,且有路径可以向上扩展。 

 f[x]=Πg[son]×h[num]

 g[x]=f[x]+Πg[son]×h[num1]×num

我们考虑仙人掌,我们发现环对答案没有贡献,将其删掉就好了。

那么变成了一片森林,就可以做了。

#include<bits/stdc++.h>
#define N 500107
#define M N<<2|1
#define mo 998244353
#define LL long long
using namespace std;
LL h[N]; int n,T,a,b,m;
void pre() {
    h[0]=1;
    for (int i=1;i<N;i++) 
      h[i]=(h[i-1]+(i>1?h[i-2]*(i-1):0))%mo;
}
#define sight(c) ('0'<=c&&c<='9')
inline void read(int &x){
    static char c;
    for (c=getchar();!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
}
void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);}
inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); }
inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); }
struct Node{
    #define eho(x) for(int i=head[x];i;i=net[i])
    #define v fall[i]
    LL ans,f[N],g[N];
    int s[N],top,tim,tot,vis[N],low[N],dfn[N],head[N],net[M],fall[M],catus,col[N];
    void clear(int n) { n=min(sizeof vis,(3+n)*(sizeof top));
      ans=1; memset(vis,0,n); top=0; tim=0;
      tot=1; memset(head,0,n); memset(col,0,n);
      memset(dfn,0,n),memset(low,0,n); catus=0;
    }
    void init() {
      ans=1; memset(vis,0,sizeof vis); top=0; tim=0;
      tot=1; memset(head,0,sizeof head); memset(col,0,sizeof col);
      memset(dfn,0,sizeof dfn),memset(low,0,sizeof low); catus=0;
    }
    inline void add(int x,int y){
        fall[++tot]=y; net[tot]=head[x]; head[x]=tot;
    }
    inline void adds(int x,int y) {
        add(x,y); add(y,x);
    }
    void Tarjan(int x,int fa){
        dfn[x]=low[x]=++tim;
        s[++top]=x;
        bool flag=0;
        eho(x) if (v!=fa) {
            if (!dfn[v])  { Tarjan(v,x); 
               low[x]=min(low[x],low[v]);
               if (low[v]<dfn[x]) {
                   if (flag) {catus=1;return;}
                   flag|=1;
               }
            } else {
                low[x]=min(low[x],dfn[v]);
                if (dfn[v]<dfn[x]) {
                  if (flag) {catus=1;return;}
                     flag|=1;    
                }
            }
        }
        if (dfn[x]==low[x]) 
            do col[s[top--]]=x; while (s[top+1]!=x);
    }
    void dfs(int x,int fa){
        vis[x]=1;
        f[x]=1; g[x]=0;
        int num=0;
        eho(x) {
            if (col[x]==col[v]||fa==v) continue;
            dfs(v,x);
            f[x]=f[x]*g[v]%mo;
            num++;
        }
        g[x]=f[x]*h[num]%mo+f[x]*h[num-1]%mo*num%mo;
        f[x]=f[x]*h[num]%mo;
    }
    inline LL work() {
        Tarjan(1,0);
        if (catus) return 0;
        for (int i=1;i<=n;i++) if (!vis[i]) {
            dfs(i,0); ans=ans*f[i]%mo;
        } return ans;
    }
}G;int NN;
signed main () {
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    read(T); pre(); G.init();
    while (T--) {
        read(n); read(m); //NN=max(n,m);
        while (m--) read(a),read(b),G.adds(a,b);
        writeln(G.work());
        G.clear(n);
    } 
    return 0;
}

 

posted @ 2018-03-10 13:53  泪寒之雪  阅读(303)  评论(0编辑  收藏  举报