uoj#290. 【ZJOI2017】仙人掌(数数+仙人掌+树形dp)
这图可以说是非常形象了2333
模拟赛的时候打了个表发现为一条链的时候答案是\(2^{n-2}\)竟然顺便过了第一个点
然后之后订正的时候强联通分量打错了调了一个上午
首先不难发现我们可以去掉所有在环上的边,那么就变成了一个森林,不同的树之间不可能有连边,那么只要所有树的答案乘起来就好了,只要在每一棵树内部树形\(dp\)即可
考虑对于\(u\),它的子树如何统计答案
我们强制子树必须得向外连一条边(显然最多只有一条),然后往上统计
如果子树里没有向外连边,每一棵子树的答案乘起来
如果向外连边的话,那么要把子树内的边两两匹配上。设\(g_i\)为\(i\)个点互相两两匹配的方案数,那么递推式为$$g_i=g_{i-1}+(i-1)\times g_{i-2}$$
边界条件为\(g_0=g_1=1\)
上面的意思是,如果第\(i\)个不连边,那么方案数就是\(g_{i-1}\),如果连边,那么有\(i-1\)种连法,连完后这两个点都不能再连边了
那么要把子树内的边两两匹配,如果当前节点是根,那么就是子树内向外连的每条链互相匹配,记\(tot\)为当前节点儿子个数,那么就是\(g_{tot}\),否则链还可以继续往上连,那么是\(g_{tot+1}\),可以考虑为把当前节点也加入匹配的队列,如果有链和它连上就代表这条链要继续向外连
然后记得开始的时候判一下是不是仙人掌就好了
//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
inline void swap(R int &x,R int &y){x^=y^=x^=y;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
void write(int x){if(x>9)write(x/10);putchar(x%10+48);}
void writeln(R int x){write(x);putchar('\n');}
const int N=1e6+5,P=998244353;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
return res;
}
struct eg{int v,nx,w;}e[N<<1];int head[N],tot=1;
inline void add_edge(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dfn[N],col[N],vis[N],f[N],g[N],st[N],low[N];
int n,m,cnt,top,tim,u,v,ans;bool qwq;
inline void clr(){fp(i,1,n)dfn[i]=col[i]=f[i]=vis[i]=head[i]=0;tim=cnt=top=qwq=0,tot=ans=1;}
void tarjan(int u,int fa){
bool flag=0;st[++top]=u;
dfn[u]=low[u]=++tim;
go(u)if(v!=fa){
if(!dfn[v]){
tarjan(v,u);cmin(low[u],low[v]);
if(low[v]<dfn[u]){
if(flag)return qwq=1,void();
flag=1;
}
}else{
cmin(low[u],dfn[v]);
if(low[v]<dfn[u]){
if(flag)return qwq=1,void();
flag=1;
}
}
}
if(low[u]==dfn[u])do{col[st[top--]]=u;}while(st[top+1]!=u);
}
void dp(int u,int fa){
vis[u]=f[u]=1;int tot=0;
go(u)if(v!=fa&&!e[i].w){
dp(v,u),++tot;
f[u]=mul(f[u],f[v]);
}
if(tot)f[u]=mul(f[u],fa?g[tot+1]:g[tot]);
}
int main(){
// freopen("testdata.in","r",stdin);
g[0]=g[1]=1;fp(i,2,N-5)g[i]=add(g[i-1],mul(i-1,g[i-2]));
int T=read();
while(T--){
n=read(),m=read(),clr();
fp(i,1,m)u=read(),v=read(),add_edge(u,v),add_edge(v,u);
tarjan(1,0);
if(qwq){writeln(0);continue;}
fp(i,2,tot)e[i].w=(col[e[i].v]==col[e[i^1].v]);
fp(i,1,n)if(!vis[i])dp(i,0),ans=mul(ans,f[i]);
writeln(ans);
}return 0;
}
uoj#290. 【ZJOI2017】仙人掌(数数+仙人掌+树形dp)的更多相关文章
- UOJ#290. 【ZJOI2017】仙人掌 仙人掌,Tarjan,计数,动态规划,树形dp,递推
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ290.html 题解 真是一道好题! 首先,如果不是仙人掌直接输出 0 . 否则,显然先把环上的边删光. ...
- codeforces 456 D. A Lot of Games(字典数+博弈+思维+树形dp)
题目链接:http://codeforces.com/contest/456/problem/D 题意:给n个字符串.进行k次游戏.每局开始,字符串为空串,然后两人轮流在末尾追加字符,保证新的字符串为 ...
- Codeforces 1118 F2. Tree Cutting (Hard Version) 优先队列+树形dp
题目要求将树分为k个部分,并且每种颜色恰好在同一个部分内,问有多少种方案. 第一步显然我们需要知道哪些点一定是要在一个部分内的,也就是说要求每一个最小的将所有颜色i的点连通的子树. 这一步我们可以将所 ...
- [BZOJ4784][ZJOI2017]仙人掌(树形DP)
4784: [Zjoi2017]仙人掌 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 312 Solved: 181[Submit][Status] ...
- LOJ2250 [ZJOI2017] 仙人掌【树形DP】【DFS树】
题目分析: 不难注意到仙人掌边可以删掉.在森林中考虑树形DP. 题目中说边不能重复,但我们可以在结束后没覆盖的边覆盖一个重复边,不改变方案数. 接着将所有的边接到当前点,然后每两个方案可以任意拼接.然 ...
- 2019.02.07 bzoj4784: [Zjoi2017]仙人掌(仙人掌+树形dp)
传送门 题意:给一个无向连通图,问给它加边形成仙人掌的方案数. 思路: 先考虑给一棵树加边形成仙人掌的方案数. 这个显然可以做树形dp. fif_ifi表示把iii为根的子树加边形成仙人掌的方案数. ...
- bzoj 4784: [Zjoi2017]仙人掌【tarjan+树形dp】
其实挺简单的但是没想出来---- 首先判断无解情况,即,一开始的图就不是仙人掌,使用tarjan判断如果一个点dfs下去有超过一个点比他早,则说明存在非简单环. 然后考虑dp,显然原图中已经属于某个简 ...
- 【NOI P模拟赛】仙人掌(圆方树,树形DP)
题面 n n n 个点, m m m 条边. 1 ≤ n ≤ 1 0 5 , n − 1 ≤ m ≤ 2 × 1 0 5 1\leq n\leq 10^5,n-1\leq m\leq 2\times1 ...
- 树形DP(统计直径的条数 HDU3534)
分析:首先树形dp(dfs计算出每个点为根节点的子树的最长距离和次长距离),然后找出L=dis[u][0]+dis[u][1]最长的那个点u,然后在以u为根节点dfs,统计长度为L的条数:具体做法:把 ...
随机推荐
- python3用pdfminer3k在线读取pdf文件
import importlib import sys import random from urllib.request import urlopen from urllib.request imp ...
- mini2440 uboot烧写uImage
mini2440下烧写u-boot后,就可以用u-boot烧写linux内核了. 安装mkimage工具: apt-get install u-boot-tools 解压缩官方mini2440 lin ...
- Android WiFi系统架构【转】
本文转载自:http://blog.csdn.net/liuhaomatou/article/details/40398753 在了解WIFI模块的系统架构之前.我心中就有一个疑问,那么Android ...
- BZOJ 1231 [Usaco2008 Nov]mixup2 混乱的奶牛:状压dp + 滚动数组
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1231 题意: 给你n个数字s[i],问你有多少个排列,使得任意相邻两数字之差的绝对值大于m ...
- Python: scikit-image 图像的基本操作
这个用例说明Python 的图像基本运算 import numpy as np from skimage import data import matplotlib.pyplot as plt cam ...
- arm-linux-gcc4.4.3编译s3c2410平台linux内核
写在前面:2.6.14版本的内核用arm-linux-gcc4.4.3没有编译成功,下载2.6.37版本的内核用arm-linux-gcc4.4.3编译通过. 一.首先下载linux内核: linux ...
- umount 卸载 无响应的 NFS 文件系统
当NFS Client 无法访问 NFS Server的适合,在Client上df操作等就会挂起. 这个适合需要将挂载的NFS卸载掉.在不知道挂载点的情况下,可以使用nfsstat -m 命令来查看. ...
- CF Round #459
好菜啊 第一场cf就菜成这样...mdzz 可能是我把题看的太简单了吧... T1AC T2AC T3WA T4看错题 T5不会写 T3想的是栈+暴力 正解: 对于一个pretty串的任意一个位置, ...
- javaCV入门指南:调用FFmpeg原生API和JavaCV是如何封装了FFmpeg的音视频操作?
通过"javaCV入门指南:序章 "大家知道了处理音视频流媒体的前置基本知识,基本知识包含了像素格式.编解码格式.封装格式.网络协议以及一些音视频专业名词,专业名词不会赘述,自行搜 ...
- check_MK安装部署(nagios4版本)
概述: 操作系统版本:CentOS release 6.3 (Final) 64位 nagios版本:Nagios Core 4.0.6 pnp4nagios版本:pnp4nagios-0.6.22 ...