本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000 
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:UOJ290

正解:$DP$+仙人掌

解题报告:

  考虑环上的边,不可能在连边中再被覆盖,所以只需要考虑树边就好了。

  把环拆掉,只剩下若干棵树,就是一个森林,最后把每棵树的答案用乘法原理合并起来就好了。

    对于每个节点$u$,我们考虑他的子树的连边方案数如何统计。

    如果我们强制每个结点的子树必须向外连一条边(显然最多一条),往上统计的话,

  那么假设$u$的子树内没有向外连边,那么就是把儿子节点的$ans$乘起来。

  如果向外连边了,就需要考虑互相连边的合法情况有多少种了。我们发现这个方案数只和儿子节点个数有关,可以很容易的用递推式来表示:

  $g[n]=g[n-1]+g[n-2]*(n-1)$

    预处理出$g$数组,每次对于每个节点先把儿子节点的$ans$全乘进来,接下来需要分类讨论节点$u$是不是一棵树的根。

  如果是根的话,则不能向外连边,那么再乘上儿子节点个数的$g$就好了(相当于是组合了节点个数个点的互相连边方式);

  否则,可以向外连边,那么把节点$u$本身也可以算进来,就是再乘上儿子节点个数$+1$的$g$。

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
#include <bitset>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 500011;
const int MAXM = 1000011;
const int mod = 998244353;
int n,m,ecnt,first[MAXN],to[MAXM],next[MAXM],father[MAXN],lu[MAXN],dfn[MAXN],deep[MAXN];
LL g[MAXN],f[MAXN],ans;
struct node{ int id,x; }a[MAXN];
inline bool cmp(node q,node qq){ return q.x<qq.x; }
inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
inline int getint(){
int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
} inline void dfs(int x,int fa){
dfn[x]=++ecnt;
for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(v==fa) continue;
if(!dfn[v]) father[v]=x,deep[v]=deep[x]+1,dfs(v,x);
}
} inline void dp(int x,bool rt){
lu[x]=-1; f[x]=1; int tot=0;//the number of son
for(int i=first[x];i;i=next[i]) {
int v=to[i]; if(v==father[x]) continue;
if(lu[v]!=1) continue;
tot++;
dp(v,0); f[x]*=f[v]; f[x]%=mod;
}
if(tot==0) return ;
if(!rt) f[x]*=g[tot+1],f[x]%=mod;
else f[x]*=g[tot],f[x]%=mod;
} inline void work(){
g[0]=g[1]=1; for(int i=2;i<=500001;i++) g[i]=g[i-1]+g[i-2]*(i-1),g[i]%=mod;
int T=getint(); int x,y; bool ck;
while(T--) {
n=getint(); m=getint(); ecnt=1;
for(int i=1;i<=n;i++) first[i]=father[i]=dfn[i]=deep[i]=lu[i]=0;
for(int i=1;i<=m;i++) {
x=getint(); y=getint();
link(x,y); link(y,x);
}
ecnt=0; deep[1]=1; dfs(1,0); ck=true;
for(int i=1;i<=m;i++) {//统计lu数组(到根的路径条数),判断是否为仙人掌
x=to[i<<1]; y=to[i<<1|1]; if(dfn[x]<dfn[y]) swap(x,y);
while(x!=y) {
lu[x]++;
if(lu[x]>2) { ck=false; break; }
x=father[x];
}
}
if(!ck) { printf("0\n"); continue; }
for(int i=1;i<=n;i++) a[i].id=i,a[i].x=deep[i];
sort(a+1,a+n+1,cmp);
ans=1;
for(int i=1;i<=n;i++) {
x=a[i].id;
if(lu[x]!=-1) {
dp(x,1);
ans*=f[x]; ans%=mod;
}
}
printf("%lld\n",ans);
}
} int main()
{
work();
return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

BZOJ4787/UOJ290 【ZJOI2017】仙人掌的更多相关文章

  1. 【BZOJ4784】[ZJOI2017]仙人掌(Tarjan,动态规划)

    [BZOJ4784][ZJOI2017]仙人掌(Tarjan,动态规划) 题面 BZOJ 洛谷 题解 显然如果原图不是仙人掌就无解. 如果原图是仙人掌,显然就是把环上的边给去掉,变成若干森林连边成为仙 ...

  2. [BZOJ4784][ZJOI2017]仙人掌(树形DP)

    4784: [Zjoi2017]仙人掌 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 312  Solved: 181[Submit][Status] ...

  3. bzoj4784 [Zjoi2017]仙人掌

    Description 如果一个无自环无重边无向连通图的任意一条边最多属于一个简单环,我们就称之为仙人掌.所谓简单环即不经过重复的结点的环. 现在九条可怜手上有一张无自环无重边的无向连通图,但是她觉得 ...

  4. ●洛谷P3687 [ZJOI2017]仙人掌

    题链: https://www.luogu.org/problemnew/show/P3687题解: 计数DP,树形DP. (首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0) 然后由于本来 ...

  5. 【做题】ZJOI2017仙人掌——组合计数

    原文链接 https://www.cnblogs.com/cly-none/p/ZJOI2017cactus.html 给出一个\(n\)个点\(m\)条边的无向连通图,求有多少种加边方案,使得加完后 ...

  6. LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】

    题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...

  7. zjoi2017 仙人掌

    题解: 好难的dp啊...看题解看了好久才看懂 http://blog.csdn.net/akak__ii/article/details/65935711 如果一开始的图就不是仙人掌,答案显然为0, ...

  8. 2019.02.07 bzoj4784: [Zjoi2017]仙人掌(仙人掌+树形dp)

    传送门 题意:给一个无向连通图,问给它加边形成仙人掌的方案数. 思路: 先考虑给一棵树加边形成仙人掌的方案数. 这个显然可以做树形dp. fif_ifi​表示把iii为根的子树加边形成仙人掌的方案数. ...

  9. BZOJ4784 ZJOI2017仙人掌(树形dp+dfs树)

    首先考虑是棵树的话怎么做.可以发现相当于在树上选择一些长度>=2的路径使其没有交,同时也就相当于用一些没有交的路径覆盖整棵树. 那么设f[i]为覆盖i子树的方案数.转移时考虑包含根的路径.注意到 ...

随机推荐

  1. Flask-Session SQLAlchemy Script Migrate wtforms

    Flask-session Flask-session跟框架自带的session有什么区别呢~ 框架自带的session是通过请求上下文~放入到Local中的~那如果我们想把session放入别的地方 ...

  2. C# 编写 TensorFlow 人工智能应用

    TensorFlowSharp入门使用C#编写TensorFlow人工智能应用学习. TensorFlow简单介绍 TensorFlow 是谷歌的第二代机器学习系统,按照谷歌所说,在某些基准测试中,T ...

  3. 工作笔记——区块链POC

    1.基础配置 安装SecureCRT 8.0链接到虚拟服务器,并配置docker 安装文件上传到服务器工具FileZilla

  4. 11、classmethod和staticmethod

    类中定义的函数有两大类(3小种)用途,一类是绑定方法,另外一类是非绑定方法 1. 绑定方法:特点:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入1.1 绑定给对象的:类中定义的函数默 ...

  5. idea 取消控制台的行数限制

    有时候我们要输出大量的信息放到控制台显示,但是多了之后就出现最上面的信息被覆盖删除, 因此就需要设置控制台的显示行数,但在idea7之后的版本中,取消了对控制台行数设置选项, 只能通过更改配置文件进行 ...

  6. 部署apollo-client到maven私服上时遇到的问题及排查过程

    场景回顾: 应用客户端如果需要接入到Apollo配置服务中心的话,需要引用apollo-client的依赖包使之与config-server保持连接,从而可以及时的收到更新之后的配置信息. 1.将ap ...

  7. 对Java CAS的一些了解(正在整理学习中)

    ①引言 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题 ...

  8. 20145316 《Java程序设计》第8周学习总结

    20145316 <Java程序设计>第8周学习总结 教材学习内容总结 NIO&NIO2 NIO使用频道(channel)衔接数据节点,对数据区的标记提供了clear(),rewi ...

  9. [2011-3-9 12:59 ]As3.0中的位图(Bitmap/BitmapData)用法

    1.位图使用(模糊)滤镜 //创建一个矩形区域的BitmapData var bmd:BitmapData = new BitmapData(80, 30, false, 0xefefef); //画 ...

  10. wamp 安装memcached

    PECL 的全称是 The PHP Extension Community Library ,是一个开放的并通过 PEAR(PHP Extension and Application Reposito ...