zoukankan      html  css  js  c++  java
  • bzoj3162 独钓寒江雪 树Hash 树dp 组合数学

    链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3162

    题意:给出一棵无根树,求出本质不同独立集数目。

    这道题真是一道好题……无限$orz$ $VFleaKing$……对着题解看了半天才看明白明明是你太蒻了……

    好了不废话直接切入正题。首先我们需要找出一个方式使得所有的同构树形态都一样,怎么办呢,找到这个树的中心,以这个中心为根重新搞。

    但是怎么搞出中心呢……首先,中心一定在整棵树最长的链上。那么我们先随意以一个点为起点广搜一次找到最远点,然后以这个点为起点再广搜一次,这两个最远的点就是树上最远点对。

    然后我们就一点一点往回缩……缩到中点就是中心……但是可能有一个问题……就是这个中点可能在边上……这时候我们就需要接出一个虚拟节点做根……

    然后,我们就要考虑求解了。如果说只求独立集数目那很简单树形$DP$即可……然而这个题目还有一个条件:同构树算同一种……因此我们还要判一下树同构……所以我们还需要判同构……于是我又现学了树$Hash$……

    然后我们可以发现,本质不同的方案数就有$C(k,p+k-1)$种……

    然后儿子列表就可以改变……变为同一结构出现了多少次……

    于是我们可以把正常的独立集公式变一下:

    ($f[]$表示选这个节点,$g[]$表示不选这个节点)

    二次项系数直接$C(m,n)$就好了……

    接下来分类讨论……有中点时,方案数为$f[root]+g[root]$……没有时,由于两个端点不能同时选中,所以还需要继续分类讨论……直接上代码吧……

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<queue>
      6 using namespace std;
      7 const int maxn=500005,mod=(int)1e9+7,mod2=(int)1e9+9,inf=0x3f3f3f3f;
      8 struct node
      9 {
     10     int to,next;
     11 }edge[maxn<<1];
     12 int head[maxn],tot=-1;
     13 void addedge(int u,int v)
     14 {
     15     edge[++tot]=(node){v,head[u]};head[u]=tot;
     16 }
     17 int n,dis[maxn],from[maxn];
     18 int q[maxn],h,t;
     19 int bfs(int x)
     20 {
     21     static bool vis[maxn];fill(vis,vis+n+1,0);fill(dis,dis+n+1,inf);h=t=0;
     22     vis[x]=1,dis[x]=0,q[++t]=x;
     23     while(h<t)
     24     {
     25         int now=q[++h];
     26         for(int i=head[now];i!=-1;i=edge[i].next)
     27         {
     28             int v=edge[i].to;
     29             if(!vis[v])dis[v]=dis[now]+1,q[++t]=v,vis[v]=1,from[v]=i;
     30         }
     31     }
     32     for(int i=1;i<=n;i++)
     33         if(dis[i]>dis[x])x=i;
     34     return x;
     35 }
     36 inline long long qpow(long long x,int tim)
     37 {
     38     long long tmp=1;
     39     for(;tim;tim>>=1,x=x*x%mod)
     40         if(tim&1)tmp=tmp*x%mod;
     41     return tmp;
     42 }
     43 long long inv[maxn];
     44 void pre()
     45 {
     46     inv[1]=1;
     47     for(int i=2;i<=n;i++)inv[i]=(mod-inv[mod%i])*(mod/i)%mod;
     48 }
     49 inline long long C(long long x,long long y)
     50 {
     51     if(x<0)x+=mod;if(x>=mod)x-=mod;long long ans=1;
     52     for(int i=1;i<=y;i++)ans=(ans*(x+1-i))%mod,ans=(ans*inv[i])%mod;
     53     return ans;
     54 }
     55 int root,son[maxn],cp,size[maxn];long long Has[maxn];
     56 inline bool cmp(int x,int y)
     57 {
     58     return Has[x]<Has[y];
     59 }
     60 inline void getson(int now)
     61 {
     62     cp=0;
     63     for(int i=head[now];i!=-1;i=edge[i].next)
     64     {
     65         int v=edge[i].to;
     66         if(dis[v]==dis[now]+1)son[++cp]=v;
     67     }
     68     sort(son+1,son+cp+1,cmp);
     69 }
     70 long long Gethash(int now)
     71 {
     72     getson(now);long long ans=1;
     73     for(int i=1;i<=cp;i++)ans=(ans+qpow(2,Has[son[i]]))%mod,ans=ans*Has[son[i]]%mod;
     74     return ans;
     75 }
     76 void Pre()
     77 {
     78     for(int i=t;i>=1;i--)
     79     {
     80         int j=i;
     81         while(i>1&&dis[q[i]]==dis[q[i-1]])i--;
     82         for(int k=i;k<=j;k++)Has[q[k]]=Gethash(q[k]);
     83     }
     84 }
     85 long long f[maxn],g[maxn];
     86 void solve()
     87 {
     88     for(int i=t;i;i--)
     89     {
     90         int now=q[i];f[now]=g[now]=1;getson(now);size[now]=1;
     91         for(int j=1;j<=cp;j++)size[now]+=size[son[j]];
     92         for(int j=1;j<=cp;j++)
     93         {
     94             int k=j;
     95             while(j<cp&&Has[son[j+1]]==Has[son[j]])j++;
     96             f[now]=(f[now]*C(g[son[j]]+j-k,j-k+1))%mod,g[now]=(g[now]*C(f[son[j]]+g[son[j]]+j-k,j-k+1))%mod;
     97         }
     98     }
     99 }
    100 int haha()
    101 {
    102     scanf("%d",&n);memset(head,-1,sizeof(head));
    103     for(int i=1;i<n;i++)
    104     {
    105         int x,y;scanf("%d%d",&x,&y);
    106         addedge(x,y);addedge(y,x);
    107     }
    108     int x=bfs(1),y=bfs(x),l=dis[y],pos=y;
    109     while(dis[pos]>((l>>1)+1))pos=edge[from[pos]^1].to;
    110     int lpos;
    111     if(l&1)
    112     {
    113         n++;
    114         lpos=edge[from[pos]^1].to;edge[from[pos]].to=n;edge[from[pos]^1].to=n;addedge(n,pos);addedge(pos,n),addedge(n,lpos);addedge(lpos,n);
    115         root=n;
    116     }
    117     else
    118     {
    119         if(n!=1)pos=edge[from[pos]^1].to;
    120         root=pos;
    121     }
    122     bfs(root);pre();Pre();solve();
    123     if(l&1)
    124     {
    125         long long ans=0;
    126         if(Has[pos]==Has[lpos])ans=(ans+f[pos]*g[pos]%mod),ans=(ans+C(g[pos]+1,2));
    127         else ans=(ans+f[pos]*g[lpos]%mod),ans=(ans+g[pos]*f[lpos]%mod),ans=(ans+g[pos]*g[lpos]%mod);
    128         ans%=mod;
    129         printf("%lld
    ",ans);
    130     }
    131     else printf("%lld
    ",(f[root]+g[root])%mod);
    132 }
    133 int sb=haha();
    134 int main(){;}
    bzoj3162
  • 相关阅读:
    A+B for Input-Output Practice (VIII)
    A+B for Input-Output Practice (VI)
    A+B for Input-Output Practice (VII)
    A+B for Input-Output Practice (IV)
    1.1.4 A+B for Input-Output Practice (V)
    1.1.3 A+B for Input-Output Practice (III)
    基础练习 龟兔赛跑预测
    基础练习 回形取数
    Python实用黑科技——以某个字段进行分组
    Python黑科技神奇去除马赛克
  • 原文地址:https://www.cnblogs.com/Loser-of-Life/p/7598578.html
Copyright © 2011-2022 走看看