• [2019牛客多校第四场][G. Tree]


    题目链接:https://ac.nowcoder.com/acm/contest/884/G

    题目大意:给定一个树(A),再给出(t)次询问,问(A)中有多少连通子图与树(B_i)同构。(|A|leq 2000,tleq 10000, |B_i|leq 12)

    题解:本题实际上是Codeforces 762F的加强版,关于这题的题解请戳这里

       本题做法与之前这道题类似,也是预处理出树的最小表示法后进行树形DP,但是由于这里有多达一万次询问,所以考虑预处理枚举所有点数不超过(12)的树并求出他们的最小表示。对于如何预处理所有满足条件的树,我的方法是假设当前树的大小为(n),将第(n+1)个点作为当前点或其祖先的儿子加入树中,并继续递归直至树的大小达到(12)。这样预处理后会发现点数不超过(12)的树只有不到(8000)个。接下来就是要对树(A)进行DP,设f[i][j]表示有多少以(i)为根节点的子树与编号为(j)的树同构,再令(ans[j]=sum_{i=1}^{n}f[i][j]),对于每个询问的答案就是(sum ans[j]),这里的(j)是树(B)以不同点为根时对应的编号。

       另外,在预处理的时候,我们同样可以预处理出当编号为(j)的树的根作为编号为(i)的树的根的儿子合并进来之后新树的编号,这样的合并关系只有不到(14000)组。这样对树(A)进行DP时就可以枚举所有这样的合并关系进行计算,将这一部分时间复杂度优化到(O(14000n))

    #include<bits/stdc++.h>
    using namespace std;
    #define N 2001
    #define M 1<<12
    #define MM 8001 
    #define NN 16773121
    #define MOD 1000000007
    int len(int x){return 32-__builtin_clz(x);}
    int Union(int x,int y){return (x<<len(y))|y;}
    int cnt;
    set<int>id[13];
    int uni[MM][MM];
    int num_to_id[NN];
    int id_to_num[MM];
    int f[N][MM];
    vector<int>Id[13];
    struct Tree
    {
        int sz[N];
        int n,ans[NN];
        vector<int>d[N];
        vector<int>mp[MM];
        void read()
          {
          scanf("%d",&n);
          for(int i=1;i<=n;i++)
            d[i].clear();
          for(int i=2;i<=n;i++)
            {
            int u,v;
            scanf("%d%d",&u,&v);
            d[u].push_back(v);
            d[v].push_back(u);
            }
          }
        int dfs(int cur,int pre)
          {
          sz[cur]=1;
          int res=1;
          vector<int>tmp;
          for(auto nxt:d[cur])if(nxt!=pre)
            tmp.push_back(dfs(nxt,cur)),sz[cur]+=sz[nxt];
          sort(tmp.begin(),tmp.end());
          for(auto x:tmp)res=Union(res,x);
          res<<=1;
          if(!num_to_id[res])cnt++,mp[cnt]=tmp,id_to_num[cnt]=res,num_to_id[res]=cnt;
          for(int i=0;i<tmp.size();i++)
            {
            int R=1;
            for(int j=0;j<tmp.size();j++)if(j!=i)
              R=Union(R,tmp[j]);
            R<<=1;
            uni[num_to_id[R]][num_to_id[tmp[i]]]=num_to_id[res];
            }
          id[sz[cur]].insert(num_to_id[res]);
          return res;
          }
        void getID()
          {
          for(int i=1;i<=n;i++)
            dfs(i,0);
          }
        void DP2(int cur,int pre)
          {
          sz[cur]=1;
          f[cur][1]=1;
          for(auto nxt:d[cur])if(nxt!=pre)
            {
            DP2(nxt,cur);
            for(int i=min(12,sz[cur]);i>=1;i--)
              for(auto ii:Id[i])
                {
                int v=f[cur][ii];
                if(!v)continue;
                for(int j=1;j<=min(12-i,sz[nxt]);j++)
                  for(auto jj:Id[j])
                    (f[cur][uni[ii][jj]]+=v*f[nxt][jj]%MOD)%=MOD;
                }
            sz[cur]+=sz[nxt];
            }
          for(int i=1;i<=min(12,sz[cur]);i++)
            for(auto ii:Id[i])
              (ans[ii]+=f[cur][ii])%=MOD;
          }
    }S,T;
    set<int>s;
    int fa[13];
    vector<int>d[13];
    void fuck(int cur,int pre)
    {
        fa[cur]=pre;
        for(int i=1;i<=12;i++)
          T.d[i]=d[i];
        T.n=cur;
        if(cur==12){T.dfs(1,0);return;}
        int x=cur;
        while(x!=0)
          {
          d[x].push_back(cur+1);
          fuck(cur+1,x);
          d[x].pop_back();
          x=fa[x];
          }
    }
    int main()
    {
        fuck(1,0);
        for(int i=1;i<=12;i++)
          for(auto j:id[i])Id[i].push_back(j);
        S.read();
        S.DP2(1,0);
        int t;
        scanf("%d",&t);
        while(t--)
          {
          T.read();
          int ans=0;
          s.clear();
          for(int i=1;i<=T.n;i++)
            s.insert(T.dfs(i,0));
          for(auto x:s)(ans+=S.ans[num_to_id[x]])%=MOD;
          printf("%d
    ",ans);
          }
        return 0;
    }
    View Code
  • 相关阅读:
    hdu2222 AC自动机入门
    bzoj1095: [ZJOI2007]Hide 捉迷藏 动态点分治学习
    【NOI2014】起床困难综合症 贪心
    bzoj1822: [JSOI2010]Frozen Nova 冷冻波网络流
    洛谷3767 膜法 带权并查集+分治
    NOI2015品酒大会 后缀数组
    NOI2015程序自动分析 并查集
    NOI2015软件包管理器 树剖线段树
    51nod1244 欧拉函数之和 杜教筛
    51nod1244 莫比乌斯函数之和 杜教筛
  • 原文地址:https://www.cnblogs.com/DeaphetS/p/11260559.html
Copyright © 2020-2023  润新知