CF997D

分析:

  假设在第一个树上我们有一个长度为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 }
View Code

 

posted @ 2018-07-03 14:45  Chellyutaha  阅读(1434)  评论(0编辑  收藏  举报