1. 程式人生 > >ZJOI 2017 仙人掌

ZJOI 2017 仙人掌

owa include pan 向上 top node space ret ear

題鏈

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; }

ZJOI 2017 仙人掌