博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【PKUSC2019】线弦图【计数】【树形DP】【分治FFT】
阅读量:5946 次
发布时间:2019-06-19

本文共 2550 字,大约阅读时间需要 8 分钟。

Description

定义线图为把无向图的边变成点,新图中点与点之间右边当且仅当它们对应的边在原图中有公共点,这样得到的图。

定义弦图为不存在一个长度大于3的纯环,纯环的定义是在环上任取两个不相邻的点,它们之间都没有边,也就是不存在没有弦的环的无向图。

现在给出一棵n个点的树,你可以在上面添加任意多条边(不能重边),要求得到的图的线图是弦图,求加边的方案数。

n<=200000

Solution

画图可以发现,一个无向图的线图是弦图的充要条件就是不存在长度大于3的环(不一定是纯环)

也就是说,我们加边只能加成三角形,并且加的边还不能交叉。

转化后的题意等价于将树上的边分成若干个集合,每个集合要么是单独一条边,要么是两条相邻的边,问方案数。

\(O(n^2)\)的暴力呼之欲出,我们记\(f[i][0/1]\)表示处理完\(i\)的子树,\(i\)向父亲的这条边是否与子树内的边组合了。

转移的时候,我们只需要知道所有儿子中有几个0,也就是有几条边需要我们来分配。

不妨再DP预处理出一个数组\(g[i][0/1]\),表示一个点下面挂着i条边,要分配集合,i的父亲边是否参与的方案数。

我们考虑每次新加一条边,要么自成集合,要么与之前的某一个组合,有

\(g[i][0]=g[i-1]+g[i-2][0]*(i-1),g[i][1]=g[i-1][0]*i\)

由于只要知道有几个0,这显然可以分治NTT优化,这样就做完了。

时间复杂度\(O(n\log^2 n)\)

Code

以下代码未经测试,完全不能保证正确性。

(惨遭证伪,请勿参考)

#include 
#define fo(i,a,b) for(int i=a;i<=b;++i)#define fod(i,a,b) for(int i=a;i>=b;--i)#define N 200005#define M 524288using namespace std;const int mo=998244353;typedef long long LL;int n,m1,fs[N],nt[2*N],dt[2*N];LL f[N][2],g[N];LL ksm(LL k,LL n){ LL s=1; for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo; return s;}void link(int x,int y){ nt[++m1]=fs[x]; dt[fs[x]=m1]=y;}namespace poly{ int len,st[N],le[N],a[M+1]; int u1[M+1],u2[M+1],l2[M+1],cf[20],wg[M+1],wi[M+1],ny[M+1],bit[M+1]; void init() { fo(i,0,18) l2[cf[i]=(1<
>1]>>1)|((i&1)<
=mo)?x-mo:x;} int dec(int x,int y) {x-=y;return(x<0)?x+mo:x;} void DFT(int *a,int num) { fo(i,0,num-1) if(i
>1;h
<<=1,l>>=1) { for(int j=0;j
<<1)) { int *x=a+j,*y=x+h,*w=wi,v; for(int i=0;i
>1; doit(l,mid),doit(mid+1,r); int num=cf[l2[le[l]+le[mid+1]-1]]; prp(num); memset(u1,0,4*num),memset(u2,0,4*num); fo(i,0,le[l]-1) u1[i]=a[st[l]+i]; fo(i,0,le[mid+1]-1) u2[i]=a[st[mid]+i]; DFT(u1,num),DFT(u2,num); fo(i,0,num-1) u1[i]=(LL)u1[i]*u2[i]%mo; IDFT(u1,num); le[l]+=le[mid+1]-1; fo(i,0,le[l]-1) a[st[l]+i]=u1[i]; }}using namespace poly;void dfs(int k,int fa){ for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; if(p!=fa) dfs(p,k); } len=0; int cnt=0; for(int i=fs[k];i;i=nt[i]) { int p=dt[i]; if(p!=fa) { cnt++; a[st[cnt]=len++]=f[p][1]; a[len++]=f[p][0]; le[cnt]=2; } } if(!cnt) f[k][0]=1; else { doit(1,cnt); f[k][0]=f[k][1]=0; fo(i,0,le[1]-1) { f[k][0]=(f[k][0]+(LL)a[i]*g[i])%mo; if(i) f[k][1]=(f[k][1]+(LL)a[i]*g[i-1]%mo*(LL)i)%mo; } }}int main(){ cin>>n; fo(i,1,n-1) { int x,y; scanf("%d%d",&x,&y); link(x,y),link(y,x); } g[0]=1,g[1]=1; fo(i,2,n) g[i]=(g[i-1]+g[i-2]*(i-1))%mo; init(); dfs(1,0); printf("%lld\n",f[1][0]);}

转载于:https://www.cnblogs.com/BAJimH/p/10945891.html

你可能感兴趣的文章
linux安全---cacti+ntop监控
查看>>
鸟哥的linux私房菜-shell简单学习-1
查看>>
nagios配置监控的一些思路和工作流程
查看>>
通讯组基本管理任务三
查看>>
赫夫曼编码实现
查看>>
html页面显示div源代码
查看>>
Centos下基于Hadoop安装Spark(分布式)
查看>>
wdcp 安装
查看>>
快递查询接口的调用与解析案例
查看>>
服务器性能优化配置建议
查看>>
oracle sql语句实现累加、累减、累乘、累除
查看>>
3D地图的定时高亮和点击事件(基于echarts)
查看>>
接口由40秒到200ms优化记录
查看>>
java 视频播放 多人及时弹幕技术 代码生成器 websocket springmvc mybatis SSM
查看>>
Activiti6.0,spring5,SSM,工作流引擎,OA
查看>>
第十三章:SpringCloud Config Client的配置
查看>>
使用 GPUImage 实现一个简单相机
查看>>
CoinWhiteBook:区块链在慈善事业中的应用
查看>>
Mac上基于Github搭建Hexo博客
查看>>
阿里云服务器ECS开放8080端口
查看>>