题解 CF762F [Tree nesting]
Link
唯一的一篇洛谷题解说的不是很清楚,让我来说清楚一点。你还可以参考大象的题解。
这是一道比较麻烦的树形+状压DP。
我们把
我们设
初始值:
转移:
其中
全局
DP的复杂度是
然而这样肯定算重复,根据某个我不知道的结论,算重复的次数恰好是T与T自我匹配匹配的方案数,所以除掉就好了。
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7 , N = 1000 , M = 12;
inline void add(int &x , int y) {x += y ; if(x >= mod) x -= mod;}
inline void sub(int &x , int y) {x -= y ; if(x < 0) x += mod;}
struct Tree : vector<vector<int>> {
void AddEdge(int x , int y) {
this->at(x).push_back(y) , this->at(y).push_back(x);
}
};
void Del(vector<int> &vec , int element) {
for(auto it = vec.begin() ; it != vec.end() ; ++it) {
while(*it == element) {
it = vec.erase(it);
if(it == vec.end()) return ;
}
}
}
Tree getroot(Tree x , int rt) {
queue<int> que;
que.push(rt);
while(que.size()) {
int cur = que.front();
que.pop();
for(auto nxt : x[cur]) {
Del(x[nxt] , cur);
que.push(nxt);
}
}
return x;
}
int Log2[1 << M];
struct TreeMatcher {
vector<int> dp[N][M];
int dfs(Tree &S , Tree &T , int s , int t) {
vector<int> &cur = dp[s][t];
if(!cur.empty()) return cur.back();
cur.resize(1 << T[t].size());
cur[0] = 1;
for(auto nxt : S[s]) {
for(int i = (int)cur.size() - 1 ; ~i ; --i)
for(int j = i ; j ; j ^= (j & -j)) {
int node = Log2[j & -j];
if(cur[i ^ (1 << node)])
add(cur[i] , 1LL * cur[i ^ (1 << node)] * dfs(S , T , nxt , T[t][node]) % mod);
}
}
return cur.back();
}
int match(Tree &S , Tree &T) {
if(S.size() < T.size())
return 0;
if(T.size() <= 1)
return S.size();
auto clr = [&] {
for(int i = 0 ; i < S.size() ; ++i)
for(int j = 0 ; j < T.size() ; ++j) dp[i][j].clear();
};
int ans = 0;
Tree s = getroot(S , 0);
for(int j = 0 ; j < T.size() ; ++j) {
Tree t = getroot(T , j);
clr();
for(int i = 0 ; i < S.size() ; ++i)
add(ans , dfs(s , t , i , j));
}
return ans;
}
};
inline int Inv(int x) {
return x <= 1 ? x : 1LL * (mod - mod / x) * Inv(mod % x) % mod;
}
Tree S , T;
TreeMatcher matcher;
int main() {
auto Input = [&](Tree &tree) {
int n ;
scanf("%d" , &n);
tree.resize(n);
for(int i = 1 , x , y ; i < n ; ++i) {
scanf("%d %d" , &x , &y);
tree.AddEdge(x - 1, y - 1);
}
};
Input(S) , Input(T);
*Log2 = -1 ; for(int i = 1 ; i < (1 << M) ; ++i) Log2[i] = Log2[i >> 1] + 1;
printf("%lld\n" , 1LL * matcher.match(S , T) * Inv(matcher.match(T , T)) % mod);
return 0;
}