[海军国际项目办公室]数树
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[海军国际项目办公室]数树相关的知识,希望对你有一定的参考价值。
数树
题目概述
题解
我们先不考虑树
T
2
T2
T2树内部的同构情况,算出总的方案数,最后除去同构的方案。
显然,树
T
1
T1
T1和
T
2
T2
T2都是无根树,我们不妨先给
T
1
T1
T1定一个根,这样的话,
T
1
T1
T1中每一种能映射到
T
2
T2
T2上的合法方案都会存在一个确定的根,在我们将我们把
T
2
T2
T2的根定义为该对应点时,这两块刚好能够匹配。
我们不妨枚举在
T
2
T2
T2中每个点为根时的情况,这样所有点的相对高度与位置都是确定的,我们可以把它放到
T
1
T1
T1上,看有多少个连通块能跟其匹配。
将
T
2
T2
T2放到
T
1
T1
T1求出匹配显然可以用
d
p
dp
dp来求出。
我们定义
d
p
i
,
j
dp_{i,j}
dpi,j表示
T
1
T1
T1上的点
i
i
i匹配
T
2
T2
T2上的点
j
j
j的方案数。
其转移过程我们可以通过状压来维护。
由于我们此时
T
2
T2
T2的根是固定的,所以点
j
j
j在
T
2
T2
T2上的儿子也是固定的。
我们要让
i
i
i在
T
1
T1
T1上的儿子依次匹配
j
j
j在
T
2
T2
T2上的儿子,求出匹配的方案数。
我们定义
f
i
,
j
,
S
f_{i,j,S}
fi,j,S表示
i
i
i在
T
1
T1
T1上的儿子匹配了
j
j
j在
T
2
T2
T2上的儿子集合为
S
S
S的方案数,其转移显然是一个背包的过程,加入的
i
i
i的儿子,枚举其匹配
j
j
j的哪一个儿子或者不匹配。
显然,
d
p
i
,
j
=
f
i
,
j
,
s
o
n
j
dp_{i,j}=f_{i,j,son_{j}}
dpi,j=fi,j,sonj,其中
s
o
n
j
son_{j}
sonj表示
j
j
j儿子的全集。
∑
i
=
1
n
d
p
i
,
r
t
\\sum_{i=1}^{n}dp_{i,rt}
∑i=1ndpi,rt就是
T
2
T2
T2以
r
t
rt
rt为根放到
T
1
T1
T1上匹配得到的方案数之和。
我们要枚举
r
t
rt
rt,整个
d
p
dp
dp的过程是
O
(
n
m
2
2
m
)
O\\left(nm^22^m\\right)
O(nm22m)的。
但是
T
2
T2
T2的内部存在同构的情况,比如一棵完全二叉树,交换它的左右儿子,树的形态并没有发生改变,但如果是我们上面的匹配过程的话,它是会被重复计算的。
即相同的点集,存在不同的映射方法,而这种映射方法会导致我们的重复计算。
而这种映射方法在匹配的根不同的情况下依旧可能导致相同,如果只根据匹配方的点集是相当麻烦的。
我们不如考虑以某一个点为根的树形态会产生多少的同构,也就是按以这个节点为根的树与我们的原
T
2
T2
T2进行上面
d
p
dp
dp转移的匹配,得到的
h
r
t
h_{rt}
hrt表示以
r
t
rt
rt为根的
T
2
T2
T2与原
T
2
T2
T2的同构数。
将原来的
∑
i
=
1
n
d
p
i
,
r
t
\\sum_{i=1}^{n}dp_{i,rt}
∑i=1ndpi,rt除去
h
r
t
h_{rt}
hrt即可,因为原来匹配的就是以
r
t
rt
rt为根的树,它产生的同构树与
h
r
t
h_{rt}
hrt相当。
所以这样跑两趟
d
p
dp
dp就可以了。
时间复杂度 O ( ( n + m ) m 2 2 m ) O\\left((n+m)m^22^m\\right) O((n+m)m22m)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 3005
#define MAXM (1<<10)+5
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x<<'\\n'
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){putchar('\\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,dp[MAXN][12],f[MAXM],tmp[MAXM],g[12][12],ans,ord[15],h[12],sumtr;
vector<int>A[MAXN],B[15],G[15];
void dosaka1(int u,int fa){
G[u].clear();int siz=B[u].size();
for(int i=0;i<siz;i++){
int v=B[u][i];if(v==fa)continue;
dosaka1(v,u);G[u].pb(v);
}
}
void dosaka2(int u,int fa){
int siz=A[u].size();
for(int i=0;i<siz;i++)if(A[u][i]!=fa)dosaka2(A[u][i],u);
for(int i=1;i<=m;i++){
f[0]=1;int sz=G[i].size();
for(int j=0;j<sz;j++)ord[j]=G[i][j];
if(sz)[海军国际项目办公室]打拳