题链:

https://www.luogu.org/problemnew/show/P3687
题解:

计数DP,树形DP。

(首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0)
然后由于本来图中就存在于环中的边,不可能再次被包含,
所以图中的环就把这个图分为的若干颗树。
那么答案就是分别求出每颗树的方案数并相乘。
现在问题变为了求:把一颗树通过连边使得仍然是仙人掌的方案数。
定义如下3个数组:
f[u]:表示u这颗子树中没有一条从u到子树内某个的节点的路径可以向其它子树连边的方案数。
g[u]:表示u这颗子树中有一条从u到子树内某个节点的路径可以其它子树连边的方案数。
以及一个预处理的h[n]:
表示有n个元素,每个元素可以选择另一个元素与其两两匹配或者该元素不与任何元素匹配的方案数。
先看看h[n]的求法:
h[n]=h[n-1]+h[n-2]*(n-1)
即表明第n个元素要么独立,要么与另外(n-1)个元素中的某一个匹配。
然后看看怎样DP:
对于当前的子树的根u,v是其儿子节点,num是其儿子节点个数
$$f[u]=\sum g[v] \times h[num] $$
因为num个儿子有h[num]种匹配方案数,所以乘上h[num]
(所谓的匹配就是把g[v]中的那条路径的末端和与它匹配的那个v'的g[v']中的那条路径的末端连边)

然后还要求出当前的g[u]:
$$g[u]=f[u]+\sum g[v] \times h[num-1] \times num$$
含义如下:
由于u点自己可以成为g[u]中的那条路径的末端,所以$$+f[u]$$
然后u还可以选择一个儿子g[son]中的路径来连上自己形成新的g[u]中的路径。
这样的话,方案数是 $g[son]* \sum_{v!=son} g[v] \times h[num-1] = \sum g[v] \times h[num-1]$
又因为u有num个儿子,即有num中选法,所以:
$$+\sum g[v] \times h[num-1] \times num $$

代码:

#include<bits/stdc++.h>
#define MAXN 500005
#define MOD 998244353
#define rint register int
using namespace std;
int Case,N,M,dnt,cactus,ANS;
int dfn[MAXN],lu[MAXN],fa[MAXN],f[MAXN],g[MAXN],h[MAXN];
struct node{int id,odr;bool operator < (const node &rtm) const{return odr<rtm.odr;}
}A[MAXN];
struct Edge{int ent;int to[MAXN*4],nxt[MAXN*4],head[MAXN];void Reset(int n){for(rint i=1;i<=n;i++) head[i]=0; ent=2;}void Adde(int u,int v){to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;}
}E;
void dfs(int u,int dad){dfn[u]=++dnt; fa[u]=dad;for(int e=E.head[u];e;e=E.nxt[e]){int v=E.to[e];if(dfn[v]) continue;dfs(v,u);}
}
void DP(int u,int rt){lu[u]=-1; f[u]=1; int num=0,gson=1;for(int e=E.head[u];e;e=E.nxt[e]){int v=E.to[e];if(lu[v]!=1||v==fa[u]) continue;DP(v,0); num++;gson=1ll*gson*g[v]%MOD;}f[u]=1ll*gson*h[num]%MOD;g[u]=(1ll*f[u]+1ll*gson*h[num-1]%MOD*num)%MOD;
}
int main(){h[0]=h[1]=1;for(int i=1;i<=500000;i++) h[i]=(1ll*h[i-1]+1ll*h[i-2]*(i-1))%MOD;for(scanf("%d",&Case);Case;Case--){scanf("%d%d",&N,&M);E.Reset(N); dnt=0; cactus=1; ANS=1;for(rint i=1;i<=N;i++) lu[i]=dfn[i]=fa[i]=0;for(int i=1,a,b;i<=M;i++)scanf("%d%d",&a,&b),E.Adde(a,b),E.Adde(b,a);dfs(1,0);for(int e=1,u,v;e<=M;e++){u=E.to[e*2]; v=E.to[e*2+1];if(dfn[u]>dfn[v]) swap(u,v);while(v!=u){lu[v]++;if(lu[v]>2){cactus=0;break;}v=fa[v];}}if(!cactus){printf("%d\n",0); continue;}for(int i=1;i<=N;i++) A[i]=(node){i,dfn[i]};sort(A+1,A+N+1);for(int i=1,u;i<=N;i++){u=A[i].id;if(lu[u]==-1) continue;DP(u,1); ANS=1ll*ANS*f[u]%MOD; }printf("%d\n",ANS);}return 0;
}

  

转载于:https://www.cnblogs.com/zj75211/p/8541648.html

●洛谷P3687 [ZJOI2017]仙人掌相关推荐

  1. ●洛谷P3688 [ZJOI2017]树状数组

    题链: https://www.luogu.org/problemnew/show/P3688 题解: 二维线段树. 先不看询问时l=1的特殊情况. 对于一个询问(l,r),如果要让错误的程序得到正确 ...

  2. 洛谷P3688/uoj#291. [ZJOI2017]树状数组

    传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...

  3. 2021寒假——洛谷刷题计划(35题)

    (希望大家不要Copy) AC:Accept,程序通过. CE:Compile Error,编译错误. PC:Partially Correct,部分正确. WA:Wrong Answer,答案错误. ...

  4. 洛谷刷题部分代码(C语言)

    洛谷刷题部分代码存档 我刚刚发现做过的题再找源代码有一点麻烦,遂决定以博客的形式保存.以方便引用.更新. P1055 [NOIP2008 普及组] ISBN 号码 #include<stdio. ...

  5. 洛谷-题解 P2672 【推销员】

    独门思路!链表加优先队列! 这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法 思路: 1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了 ...

  6. 洛谷 P1142 轰炸

    洛谷 P1142 轰炸 题目描述 "我该怎么办?"飞行员klux向你求助. 事实上,klux面对的是一个很简单的问题,但是他实在太菜了. klux要想轰炸某个区域内的一些地方,它们 ...

  7. 洛谷 P1387 最大正方形

    P1387 最大正方形 题目描述 在一个n*m的只包含0和1的矩阵里找出一个不包含0的最大正方形,输出边长. 输入输出格式 输入格式: 输入文件第一行为两个整数n,m(1<=n,m<=10 ...

  8. 洛谷P2763 试题库问题

    题目:https://www.luogu.org/problemnew/show/P2763 题目描述 «问题描述: 假设一个试题库中有n道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性. ...

  9. 动态规划——洛谷_P1057传球游戏

    题目: 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏.游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球, ...

最新文章

  1. 太任性!00 后少年买不到回国机票,因“泄愤”找黑客攻击系统,被判刑 4 年
  2. 用python中函数输出杨辉三角_用Python输出一个杨辉三角的例子
  3. php 遍历文件夹并压成zip_php ZipArchive实现多文件打包下载实例
  4. python encode函数_关于字符串:在python中使用unicode()和encode()函数
  5. mysql indexkey提取,MySQL元数据获取基础笔记day06
  6. PHP培训领航者兄弟连IT教育推出兄弟会教育模式
  7. 第二空间计算机最新破解,雨过天晴海外版 电脑时光机 - RollBack Rx v10.2.2699597837 多国语言特别版...
  8. 5G接入网学习:回顾电调天线
  9. 阿里巴巴(杭州)转正答辩失败流水账
  10. python case用法_Python Switch Case三种实现方法代码实例
  11. 【Multisim仿真】用555定时器+CD4017实现流水灯
  12. 《我是北大旁听生/郑球洋》
  13. 有线路由器加无线路由器WAN接LAN和LAN接LAN的连线方法
  14. 19、论文解读:Intensity Scan Context: Coding Intensity and Geometry Relations for Loop Closure Detection
  15. jdk的安装、卸载与简介
  16. webpack优化系列七:首屏加载优化
  17. 李峋同款爱心代码Python版
  18. getAttribute()用法
  19. git add出现 “fatal: in unpopulated submodule XXX“ 错误
  20. ios中在app应用内刷新小组件数据

热门文章

  1. c#自定义事件的使用方法
  2. word之八大文本替换技巧
  3. qq互联开放平台 开源SDK共享 常见问题
  4. Asp.net ajax、Anthem.net、Ajax pro三大ajax框架论坛网友比较
  5. 漫步数学分析一——实数轴
  6. 去哪儿-03-index-swiper
  7. C++的使用Lambda
  8. 10815 - Andy's First Dictionary
  9. Java操作MySQL
  10. java 图片上传_java web图片上传和文件上传实例