LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】
题目分析:
不难注意到仙人掌边可以删掉。在森林中考虑树形DP。
题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数。
接着将所有的边接到当前点,然后每两个方案可以任意拼接。然后考虑引一条边上去的情况,选一个点不与周围连边就行了。
判仙人掌利用dfs树与树前缀和即可。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1050000; 5 const int mod = 998244353; 6 7 int T,n,m,arr[maxn],C[maxn],d[maxn],up[maxn],dep[maxn]; 8 int f[maxn],gi[maxn]; 9 10 struct edge{int u,v,flag;}edges[maxn]; 11 12 vector <pair<int,int> > g[maxn]; 13 vector <int> nxt[maxn]; 14 15 void read(){ 16 scanf("%d%d",&n,&m); 17 for(int i=1;i<=n;i++){ 18 nxt[i].clear(),g[i].clear(),arr[i] = 0,d[i]=0,dep[i]=0,up[i]=0; 19 f[i] = 0;gi[i] = 0; 20 } 21 for(int i=1;i<=m;i++){ 22 scanf("%d%d",&edges[i].u,&edges[i].v); 23 g[edges[i].u].push_back(make_pair(edges[i].v,i)); 24 g[edges[i].v].push_back(make_pair(edges[i].u,i)); 25 edges[i].flag = 0; 26 } 27 } 28 29 void DFST(int now,int dp){ 30 dep[now] = dp; 31 for(auto it:g[now]){ 32 if(!dep[it.first]) { 33 up[it.first] = it.second; nxt[now].push_back(it.first); 34 DFST(it.first,dp+1); 35 } 36 else if(dep[it.first] < dep[now]) continue; 37 else d[it.first]++,d[now]--,edges[it.second].flag = 1; 38 } 39 } 40 41 void dfsup(int now){for(auto it:nxt[now]) dfsup(it),d[now] += d[it];} 42 43 int cactus(){ 44 DFST(1,1); dfsup(1); 45 for(int i=1;i<=n;i++) if(d[i] > 1) return 0; 46 for(int i=1;i<=n;i++) if(d[i] == 1) edges[up[i]].flag = 1; 47 return 1; 48 } 49 50 void dfs(int now,int fa){ 51 arr[now] = 1;int multi = 1,cnt = 0; 52 for(auto it:nxt[now]){ 53 if(it == fa) continue; 54 cnt++;dfs(it,now); 55 multi = (1ll*multi*gi[it])%mod; 56 } 57 if(!cnt) f[now] = gi[now] = 1; 58 else{ 59 f[now] = (1ll*multi*C[cnt])%mod; 60 gi[now] = f[now] + ((1ll*multi*C[cnt-1])%mod)*cnt%mod; 61 gi[now] %= mod; 62 } 63 } 64 65 void work(){ 66 if(!cactus()) {puts("0");return;} 67 for(int i=1;i<=n;i++) nxt[i].clear(); 68 for(int i=1;i<=m;i++) 69 if(!edges[i].flag){ 70 nxt[edges[i].u].push_back(edges[i].v); 71 nxt[edges[i].v].push_back(edges[i].u); 72 } 73 int ans = 1; 74 for(int i=1;i<=n;i++) if(!arr[i]) {dfs(i,0); ans = (1ll*ans*f[i])%mod;} 75 printf("%d\n",ans); 76 } 77 78 int main(){ 79 scanf("%d",&T); 80 C[0] = C[1] = 1; 81 for(int i=2;i<=500000;i++) C[i] = (C[i-1] + (1ll*(i-1)*C[i-2])%mod)%mod; 82 while(T--){ 83 read(); 84 work(); 85 } 86 return 0; 87 }