分析:
假設在第一個樹上我們有一個長度為x的環,在第二樹上我們有一個長度為y的環,那么可以在叉積樹上構造出$\binom{x+y}{x}$個長度為x+y的環
問題的關鍵就變成了如何統計出在一個樹上的長度為i的環的個數
設$f(u,v,k)$表示從u點出發走k步回到u點,中途不經過點v的方案數,其中v是u的相鄰點
考慮求解的轉移過程,一定是從u走到某個鄰接點w(w!=v),然后從w走到w(不經過u),然后再回到u,於是有轉移方程
這個是$O(n^2k^2)$的,但明顯里面的w不需要枚舉,只需要拿sum減去w=v的情況就行了,於是變成了$O(nk^2)$

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mp make_pair 4 const int maxn=4000,mod=998244353; 5 int k; 6 int ans; 7 int C[80][80]; 8 void inc(int &a,int b) 9 { 10 a=(a+b)%mod; 11 } 12 struct wjmzbmr 13 { 14 int n; 15 vector<int> g[maxn+5]; 16 vector<int> dp[80][maxn+5]; 17 int sum[80][maxn+5]; 18 int ans[maxn+5],sz[maxn+5]; 19 map<pair<int,int>,int> s; 20 void init() 21 { 22 for(int i=1;i<n;++i) 23 { 24 int u,v; 25 scanf("%d%d",&u,&v); 26 g[u].push_back(v),g[v].push_back(u); 27 } 28 for(int i=1;i<=n;++i) 29 for(int j=0;j<g[i].size();++j) 30 s[mp(i,g[i][j])]=j; 31 for(int i=1;i<=n;++i) sz[i]=g[i].size(),g[i].push_back(0); 32 for(int t=0;t<=k;++t) 33 for(int i=0;i<=n;++i) 34 dp[t][i].resize(sz[i]+1,0); 35 } 36 void work() 37 { 38 for(int i=1;i<=n;++i) 39 for(int j=0;j<=sz[i];++j) 40 { 41 42 dp[0][i][j]=1; 43 inc(sum[0][g[i][j]],1); 44 } 45 for(int i=2;i<=k;++i) 46 for(int u=1;u<=n;++u) 47 for(int j=0;j<=sz[u];++j) 48 { 49 int v; 50 if(j<sz[u]) v=g[u][j];else v=0; 51 int id; 52 if(v==0) id=0; 53 else 54 id=s[mp(v,u)]; 55 for(int t=0;t<=i-2;++t) 56 dp[i][u][j]=((dp[i][u][j]+1LL*dp[i-t-2][u][j]*(sum[t][u]-dp[t][v][id])%mod)%mod+mod)%mod; 57 inc(sum[i][v],dp[i][u][j]); 58 } 59 for(int i=0;i<=k;i+=2) 60 for(int u=1;u<=n;++u) 61 inc(ans[i],dp[i][u][sz[u]]); 62 } 63 }tree[2]; 64 int main() 65 { 66 //freopen("ce.in","r",stdin); 67 scanf("%d%d%d",&tree[0].n,&tree[1].n,&k); 68 tree[0].init(),tree[1].init(); 69 tree[0].work(); 70 tree[1].work(); 71 C[0][0]=1; 72 for(int i=1;i<=k;++i) 73 { 74 C[i][0]=1; 75 for(int j=1;j<=i;++j) 76 C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; 77 } 78 for(int i=0;i<=k;++i) 79 inc(ans,int(1LL*tree[0].ans[i]*tree[1].ans[k-i]%mod*C[k][i]%mod)); 80 printf("%d\n",ans); 81 return 0; 82 }