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[num−1]×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; }