zoukankan      html  css  js  c++  java
  • 【CF762F】Tree nesting

    题目

    题目链接:https://codeforces.com/contest/762/problem/F
    给定两棵树 (S,T),求 (S) 有多少个连通子图与 (T) 同构。
    (S) 的大小 (nleq 1000)(T) 的大小 (mleq 12)

    思路

    固定 (S) 的根节点为 (1),枚举 (T) 的根节点 (i) 以及 (S) 中与 (i) 匹配的点 (j),然后往 (j) 的子树内尝试匹配 (T)
    注意到因为枚举了 (T) 的根,所以可能会记重,不难发现若 (T) 与自身有 (k) 种同构,那么每一种方案都会计算 (k) 次,最后把答案除以 (k) 即可。
    考虑如何匹配,设 (f[x][s]) 表示 (s) 中的点 (x) 为根,且 (x) 这一层节点需要匹配 (T) 中节点集合为 (s) 的方案数。因为我们固定了 (S) 的根,(T) 的根,以及匹配子树的根,所以每一层节点都是匹配相同层数节点的。
    预处理 ( ext{bit}_x) 表示 (T) 中节点 (x) 的儿子的集合。那么

    [f[x][s]=f[ ext{pre}_x][s]+sum_{iin s}f[ ext{son}_x][ ext{bit}_i] imes f[ ext{pre}_x][s ext{ xor }2^{i-1}] ]

    其中 ( ext{pre}_x) 表示 (x) 的前一个兄弟节点,( ext{son}_x) 表示 (x) 的最后一个儿子节点。
    转移也就是如果 (x) 不去匹配 (s) 中的任何点,那么贡献就是 (f[ ext{pre}_x][s]),否则枚举匹配的点 (i),那么 (x) 的儿子们(从最后一个儿子 ( ext{son}_x) 开始转移)就需要匹配 (T)(i) 的儿子节点 ( ext{bit}_i),集合 (s) 中其他的节点就由 (x) 的兄弟节点匹配。
    记忆化搜索即可。最后除以 (T) 自身匹配数量可以直接把 (T) 复制给 (S) 再跑一遍。
    时间复杂度 (O(nm^22^m)),显然是一个十分宽松的上界。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=1010,M=(1<<12),MOD=1e9+7;
    int n,m,ans,f[N][M];
    
    struct edge
    {
    	int next,to;
    };
    
    ll fpow(ll x,ll k)
    {
    	ll ans=1;
    	for (;k;k>>=1,x=x*x%MOD)
    		if (k&1) ans=ans*x%MOD;
    	return ans;
    }
    
    struct Tree1
    {
    	int tot,head[N],bit[N];
    	edge e[N*2];
    	
    	void add(int from,int to)
    	{
    		e[++tot]=(edge){head[from],to};
    		head[from]=tot;
    	}
    	
    	void dfs(int x,int fa)
    	{
    		bit[x]=0;
    		for (int i=head[x];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (v!=fa) dfs(v,x),bit[x]|=(1<<v-1);
    		}
    	}
    }T;
    
    struct Tree2
    {
    	int tot,head[N],pre[N],son[N];
    	edge e[N*2];
    	
    	void add(int from,int to)
    	{
    		e[++tot]=(edge){head[from],to};
    		head[from]=tot;
    	}
    	
    	void dfs1(int x,int fa)
    	{
    		int last=0; son[x]=0;
    		for (int i=head[x];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (v!=fa)
    			{
    				pre[v]=last; son[x]=v; last=v;
    				dfs1(v,x); 
    			}
    		}
    	}
    	
    	int dfs2(int x,int s)
    	{
    		if (!s) return 1;
    		if (!x) return 0;
    		if (f[x][s]!=-1) return f[x][s];
    		f[x][s]=dfs2(pre[x],s);
    		for (int i=1;i<=m;i++)
    			if (s&(1<<i-1))
    				f[x][s]=(f[x][s]+1LL*dfs2(son[x],T.bit[i])*dfs2(pre[x],s^(1<<i-1)))%MOD;
    		return f[x][s];
    	}
    	
    	int solve()
    	{
    		int ans=0;
    		dfs1(1,0);
    		for (int i=1;i<=m;i++)
    		{
    			memset(f,-1,sizeof(f));
    			T.dfs(i,0);
    			for (int j=1;j<=n;j++)
    				ans=(ans+dfs2(son[j],T.bit[i]))%MOD;
    		}
    		return ans;
    	}
    }S;
    
    int main()
    {
    	scanf("%d",&n);
    	memset(S.head,-1,sizeof(S.head));
    	memset(T.head,-1,sizeof(T.head));
    	for (int i=1,x,y;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		S.add(x,y); S.add(y,x);
    	}
    	scanf("%d",&m);
    	for (int i=1,x,y;i<m;i++)
    	{
    		scanf("%d%d",&x,&y);
    		T.add(x,y); T.add(y,x);
    	}
    	ans=S.solve(); n=m;
    	memcpy(S.e,T.e,sizeof(S.e));
    	memcpy(S.head,T.head,sizeof(S.head));
    	printf("%lld",ans*fpow(S.solve(),MOD-2)%MOD);
    	return 0;
    }
    
  • 相关阅读:
    目录和文件的权限设置方法
    logstash5 单实例多配置文件实现
    elasticsearch 使用快照方式迁移数据
    mysql 主库有数据通过锁库做主从
    mfs挂载
    web页面性能分析一些网址
    centos7 ffmpeg安装
    (转)在 Windows 上安装Rabbit MQ 指南
    (转)TeamCity配置笔记
    (转)分布式缓存GemFire架构介绍
  • 原文地址:https://www.cnblogs.com/stoorz/p/14779116.html
Copyright © 2011-2022 走看看