• 【CF512D】Fox And Travelling(拓扑+树上背包)


    点此看题面

    • 给定一张(n)个点(m)条边的图。
    • 访问图中一个点,需要满足与它直接相连的所有点中至多只有一个没被访问过。
    • 对于每个(kin[0,n]),你需要求出访问(k)个点的方案数。
    • (nle100)

    拓扑去环

    首先我们考虑,环上的点是永远不可能被访问的,且两个环之间的路径上的点也是永远不可能被访问的(因为它们度数始终大于等于(2))。

    故我们完全可以从原图中先把所有环删去,而这一过程的实现可以用拓扑,因为环是不可能加入到拓扑序列中的。

    删去环后原图就变成了森林,但是其中的树分无根树和有根树两类:

    • 如果这本来就是一棵树,就是无根树
    • 如果这本来与一个环相连,就以与环相连的点为根。

    树上背包

    有根树的树上背包应该是很容易的吧,转移方程就是:

    [f_{x,j+k} exttt{+=}C_{j+k}^j imes f_{x,j} imes f_{y,k} ]

    这里因为两个序列自身是有序的,所以它们合并的方案数只要乘上一个组合数就好了。

    而对于无根树,我们以每个点为根都做一次树上背包。

    那么考虑选(i)个点的每种方案会被重复计算多少次(假设树大小为(tot)),发现若(i ot=tot),则只要不以这(i)个点为根都会把该方案计算一遍。

    也就是说,做无根树时,对于(i ot=tot),我们需要给最终的(f_i)除以(tot-i)

    最后不同树之间的合并又是一个背包,转移和上面给出的方程基本一致,就不再赘述了。

    代码:(O(n^3))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100
    #define X 1000000009
    using namespace std;
    int n,m,C[N+5][N+5];
    I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    struct Graph
    {
    	int ee,lnk[N+5];struct edge {int to,nxt;}e[N*N+5];
    	I int& operator [] (CI x) {return lnk[x];}
    	I edge& operator () (CI x) {return e[x];}
    	I void add(CI x,CI y) {e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y;}
    }G,P;
    namespace Topo//拓扑
    {
    	int d[N+5],q[N+5],vis[N+5],IQ[N+5],rt[N+5],ty[N+5];
    	I void MakeRt(CI x,CI Rt)//以Rt为根(对于无根树,方便起见也给一个根)
    	{
    		rt[x]=Rt;for(RI i=P[x];i;i=P(i).nxt) !rt[P(i).to]&&(MakeRt(P(i).to,Rt),0);
    	}
    	I void Work()
    	{
    		RI i,H=1,T=0;for(i=1;i<=G.ee;++i) ++d[G(i).to];//初始化度数
    		for(i=1;i<=n;++i) d[i]<=1&&(IQ[q[++T]=i]=1);//初始化队列
    		W(H<=T) for(vis[q[H]]=1,i=G[q[H++]];i;i=G(i).nxt)//拓扑去环
    			!vis[G(i).to]&&--d[G(i).to]<=1&&!IQ[G(i).to]&&(IQ[q[++T]=G(i).to]=1);
    		RI x,f;for(x=1;x<=T;++x) if(d[q[x]])
    		{
    			for(f=1,i=G[q[x]];i;i=G(i).nxt) IQ[G(i).to]&&(P.add(q[x],G(i).to),P.add(G(i).to,q[x]),f=0);//连边
    			f&&(ty[q[x]]=1),IQ[q[x]]=0;//判断是否与环相连
    		}
    		for(x=1;x<=T;++x) ty[q[x]]&&(MakeRt(q[x],q[x]),0);for(x=1;x<=T;++x) !rt[q[x]]&&(MakeRt(q[x],q[x]),0);//优先建有根树,剩下的是无根树
    	}
    }
    namespace Bag//树上背包
    {
    	int tot,f[N+5][N+5],f_[N+5],g[N+5],F[N+5];
    	I void DP(CI x,CI lst=0)//树形DP
    	{
    		for(RI i=1;i<=g[x];++i) f[x][i]=0;f[x][g[x]=0]=1;
    		for(RI i=P[x],j,k;i;i=P(i).nxt) if(P(i).to^lst)//树上背包板子,但注意组合数
    		{
    			for(DP(P(i).to,x),j=g[x];~j;--j) for(k=1;k<=g[P(i).to];++k)
    				f[x][j+k]=(1LL*f[x][j]*f[P(i).to][k]%X*C[j+k][j]+f[x][j+k])%X;g[x]+=g[P(i).to];
    		}
    		++g[x],f[x][g[x]]=f[x][g[x]-1];//因为根只能放最后一个,可直接复制答案
    	}
    	I void Walk(CI x,CI lst=0)//以每个点为根做背包
    	{
    		RI i;for(i=P[x];i;i=P(i).nxt) P(i).to^lst&&(Walk(P(i).to,x),0);
    		for(DP(x),i=1;i<=g[x];++i) f_[i]=(f_[i]+f[x][i])%X;
    	}
    	I void Solve(CI x,CI ty)//求解x所在的树,ty表示是否有根
    	{
    		RI i,j;if(ty) for(DP(x),i=1;i<=g[x];++i) f_[i]=f[x][i];//有根树直接DP
    		else {for(i=1;i<=n;++i) f_[i]=0;for(Walk(x),i=1;i^g[x];++i) f_[i]=1LL*f_[i]*QP(g[x]-i,X-2)%X;}//无根树给f[i]除以g[x]-i
    		for(i=tot;~i;--i) for(j=1;j<=g[x];++j) F[i+j]=(1LL*F[i]*f_[j]%X*C[i+j][i]+F[i+j])%X;tot+=g[x];//总背包统计所有答案
    	}
    }
    int main()
    {
    	RI i,j,x,y;for(scanf("%d%d",&n,&m),i=1;i<=m;++i) scanf("%d%d",&x,&y),G.add(x,y),G.add(y,x);
    	for(C[0][0]=i=1;i<=n;++i) for(C[i][0]=j=1;j<=i;++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%X;//预处理组合数
    	for(Topo::Work(),Bag::F[0]=i=1;i<=n;++i) i==Topo::rt[i]&&(Bag::Solve(i,Topo::ty[i]),0);//拓扑去环,然后分别处理每一棵树
    	for(i=0;i<=n;++i) printf("%d
    ",Bag::F[i]);return 0;//输出总背包中的答案
    }
    
  • 相关阅读:
    linux常用命令
    mysql 开发基础系列20 事务控制和锁定语句(上)
    sql server 性能调优之 资源等待 CXPACKET
    mysql 开发基础系列19 触发器
    mysql 开发基础系列18 存储过程和函数(下)
    mysql 开发基础系列17 存储过程和函数(上)
    sql server 性能调优之 资源等待PAGEIOLATCH
    mysql 开发基础系列16 视图
    mysql 开发基础系列15 索引的设计和使用
    sql server 性能调优之 当前用户请求分析 (1)
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF512D.html
Copyright © 2020-2023  润新知