• 【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;
    }
    
  • 相关阅读:
    一键java环境配置
    eclipse + tomcat7 + maven 配置过程
    eclipse/myeclipse link 方式安装插件
    eclipse maven plugin 插件 安装 和 配置
    Spring MVC 教程,快速入门,深入分析
    Spring MVC 框架搭建及详解
    Javassist介绍
    OO的奇妙冒险4
    OO的奇妙冒险3
    OO的奇妙冒险2
  • 原文地址:https://www.cnblogs.com/stoorz/p/14779116.html
Copyright © 2020-2023  润新知