zoukankan      html  css  js  c++  java
  • 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
    ",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 }
  • 相关阅读:
    快速幂取模算法详解
    牛客网小白月赛5I区间(差分数组)
    多重背包模板
    hdu5791(DP)
    CodeForces
    最长上升子序列LIS(51nod1134)
    POJ1088(记忆搜索加dp)
    最长公共子序列LCS(POJ1458)
    Gym 100971J-Robots at Warehouse
    模板
  • 原文地址:https://www.cnblogs.com/Menhera/p/9277590.html
Copyright © 2011-2022 走看看