bzoj3162 独钓寒江雪 树Hash 树dp 组合数学

Posted Loser Of Life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\n",ans);
130     }
131     else printf("%lld\\n",(f[root]+g[root])%mod);
132 }
133 int sb=haha();
134 int main(){;}
bzoj3162

 

以上是关于bzoj3162 独钓寒江雪 树Hash 树dp 组合数学的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3162 独钓寒江雪

bzoj3162独钓寒江雪

BZOJ3197[Sdoi2013]assassin 树同构+动态规划+KM

江雪-《唐诗三百首》数据源API接口应用

poj3162(树形dp+线段树求最大最小值)

手机在身边 验证码没泄露却依然被盗刷 这个漏洞你不得不防!