997D Cycles in product

传送门

题目大意

https://www.luogu.org/problemnew/show/CF997D

分析

我们发现两棵树互不相关

于是我们可以分别求出两棵树的信息

我们点分,人啊按后设f[i][x]为从根出发走i步到x中间不经过根的方案数,g[i][x]为可以经过根的方案数

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define add(x,y) x=(x+y)%mod
const int mod = 998244353;
int c[80][80],m;
struct tree {
    int n,ans[80],f[80][5000],g[80][5000];
    int root,sum,siz[5000],w[5000],a[5000],tot;
    bool vis[5000];
    vector<int>v[5000];
    inline void getrt(int x,int fa){
      siz[x]=1;
      w[x]=0;
      for(int i=0;i<v[x].size();i++)
        if(v[x][i]!=fa&&!vis[v[x][i]]){
          getrt(v[x][i],x);
          siz[x]+=siz[v[x][i]];
          w[x]=max(w[x],siz[v[x][i]]);
        }
      w[x]=max(w[x],sum-siz[x]);
      if(!root||w[x]<w[root])root=x;
    }
    inline void dfs(int x,int fa){
      a[++tot]=x;
      siz[x]=1;
      for(int i=0;i<v[x].size();i++)
        if(v[x][i]!=fa&&!vis[v[x][i]]){
          dfs(v[x][i],x);
          siz[x]+=siz[v[x][i]];
        }
    }
    inline void work(int x){
      tot=0;
      dfs(x,0);
      int i,j,k;
      memset(f,0,sizeof(f));
      memset(g,0,sizeof(g));
      f[0][x]=g[0][x]=1;
      for(i=1;i<=m;i++)
        for(j=1;j<=tot;j++){
          for(k=0;k<v[a[j]].size();k++){
            if(vis[v[a[j]][k]])continue;
            if(a[j]!=x)add(f[i][a[j]],f[i-1][v[a[j]][k]]);
            add(g[i][a[j]],g[i-1][v[a[j]][k]]);
          }
        }
      for(i=1;i<=tot;i++){
          if(a[i]==x){
            for(j=0;j<=m;j++)add(ans[j],g[j][a[i]]);
          }else {
            for(j=0;j<=m;j++)
              for(k=0;k+j<=m;k++)
                add(ans[k+j],(long long)f[j][a[i]]*g[k][a[i]]%mod);
          }
      }
      vis[x]=1;
      for(i=0;i<v[x].size();i++)
        if(!vis[v[x][i]]){
          root=0;
          sum=siz[v[x][i]];
          getrt(v[x][i],x);
          work(root);
        }
    }
    inline void solve(){
      sum=n;
      root=0;
      memset(vis,0,sizeof(vis));
      memset(ans,0,sizeof(ans));
      getrt(1,0);
      work(root);
    }
};
tree t1,t2;
int main(){
    int i,j,k;
    scanf("%d%d%d",&t1.n,&t2.n,&m);
    c[0][0]=1;
    for(i=1;i<=m;i++)c[i][i]=c[i][0]=1;
    for(i=1;i<=m;i++)
      for(j=1;j<i;j++)c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    for(i=0;i<=t1.n;i++)t1.v[i].clear();
    for(i=0;i<=t2.n;i++)t2.v[i].clear();
    for(i=1;i<t1.n;i++){
      int x,y;
      scanf("%d%d",&x,&y);
      t1.v[x].push_back(y);
      t1.v[y].push_back(x);
    }
    for(i=1;i<t2.n;i++){
      int x,y;
      scanf("%d%d",&x,&y);
      t2.v[x].push_back(y);
      t2.v[y].push_back(x);
    }
    t1.solve(),t2.solve();
    int Ans=0;
    for(i=0;i<=m;i++)
      Ans=(Ans+(long long)t1.ans[i]*t2.ans[m-i]%mod*c[m][i]%mod)%mod;
    cout<<Ans;
    return 0;
}
posted @ 2019-02-20 14:10  水题收割者  阅读(284)  评论(0编辑  收藏  举报