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 }

 

posted @ 2018-07-07 16:26  menhera  阅读(233)  评论(0编辑  收藏  举报