BZOJ 3162 独钓寒江雪

Posted avancent

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3162 独钓寒江雪相关的知识,希望对你有一定的参考价值。

题意是求一棵无根树本质不同独立集的个数

那个所谓“极寒点”的选取就是独立集。

结构相同就是树同构,完全相同就是树的形态和独立集都相同。

我们先求出树的重心,就可以转化为有根树同构问题。

令$f[u][1]$为在$u$的子树中,选取$u$的方案树,$f[u][0]$为在$u$的子树中,不选取$u$的方案数。

得到最基本的DP方程:

$f[u][0]=\prod_{v\in\;son(u)}(f[v][0]+f[v][1])$

$f[u][1]=\prod_{v\in\;son(u)}f[v][0]$

但是可能出现直径长为奇数的情况,需要分类讨论。

判断树同构用哈希乱搞就好了。

技术分享
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <algorithm>
  5 using namespace std;
  6 #define maxn 500010
  7 #define mod 1000000007
  8 #define p1 2150527
  9 #define p2 1231231237
 10 #define LL long long
 11 inline int read()
 12 {
 13     int s=0,f=1;
 14     char ch=getchar();
 15     while(ch<0||ch>9)
 16     {
 17         if(ch==-)
 18             f=-1;
 19         ch=getchar();
 20     }
 21     while(ch>=0&&ch<=9)
 22         s=s*10+ch-0,ch=getchar();
 23     return s*f;
 24 }
 25 struct edge
 26 {
 27     int u,v,nex;
 28 }e[maxn<<1];
 29 int pr[maxn],cnt=1;
 30 int siz[maxn];
 31 void add(int u,int v)
 32 {
 33     e[++cnt]=(edge){u,v,pr[u]};
 34     pr[u]=cnt;
 35     e[++cnt]=(edge){v,u,pr[v]};
 36     pr[v]=cnt;
 37 }
 38 int rt[2],root;
 39 LL inv[maxn];
 40 LL haha[maxn];
 41 LL f[maxn][2];
 42 int st[maxn];
 43 bool cmp(int a,int b)
 44 {
 45     return haha[a]<haha[b];
 46 }
 47 LL C(int n,int m)
 48 {
 49     LL ans=n;
 50     for(;m>1;m--)
 51         ans=ans*(n-m+1)%mod*inv[m]%mod;
 52     return ans;
 53 }
 54 void dp(int u,int fa)
 55 {
 56     int top=0,i,j;
 57     haha[u]=20010416;
 58     for(i=pr[u];i;i=e[i].nex)
 59         if(e[i].v!=fa)
 60             dp(e[i].v,u);
 61     for(i=pr[u];i;i=e[i].nex)
 62         if(e[i].v!=fa)
 63             st[++top]=e[i].v;
 64     sort(st+1,st+top+1,cmp);
 65     f[u][0]=f[u][1]=1;
 66     for(i=1;i<=top;i=j)
 67     {
 68         for(j=i+1;j<=top;j++)
 69             if(haha[st[i]]!=haha[st[j]])
 70                 break;
 71         f[u][0]=f[u][0]*C((j-i-1+f[st[i]][0]+f[st[i]][1])%mod,j-i)%mod;
 72         f[u][1]=f[u][1]*C((j-i-1+f[st[i]][0])%mod,j-i)%mod;
 73     }
 74     for(i=1;i<=top;i++)
 75         haha[u]=haha[u]*p1+(haha[st[i]]+i)*p2;
 76 }
 77 int n;
 78 void dfs(int u,int fa)
 79 {
 80     bool flag=1;
 81     siz[u]=1;
 82     int i,v;
 83     for(i=pr[u];i;i=e[i].nex)
 84     {
 85         v=e[i].v;
 86         if(v!=fa)
 87         {
 88             dfs(v,u);
 89             if((siz[v]<<1)>n)
 90                 flag=0;
 91             siz[u]+=siz[v];
 92         }
 93     }
 94     if((siz[u]<<1)<n)
 95         flag=0;
 96     if(flag)
 97     {
 98         if(rt[0])
 99             rt[1]=u;
100         else
101             rt[0]=u;
102     }
103 }
104 void init()
105 {
106     inv[0]=inv[1]=1;
107     for(int i=2;i<=n;i++)
108         inv[i]=(mod-mod/i*inv[mod%i]%mod)%mod;
109 }
110 int main()
111 {
112     n=read();
113     init();
114     int u,v;
115     for(int i=1;i<=n-1;i++)
116     {
117         u=read();
118         v=read();
119         add(u,v);
120     }
121     dfs(1,0);
122     if(rt[1])
123     {
124         root=n+1;
125         for(int i=pr[rt[0]];i;i=e[i].nex)
126             if(e[i].v==rt[1])
127             {
128                 e[i].v=e[i^1].v=root;
129                 break;
130             }
131         add(root,rt[0]);
132         add(root,rt[1]);
133     }
134     else
135         root=rt[0];
136     dp(root,0);
137     if(!rt[1])
138         printf("%lld",(f[root][0]+f[root][1])%mod);
139     else
140     {
141         u=rt[0];
142         v=rt[1];
143         if(haha[u]==haha[v])
144             printf("%lld",(f[u][0]*f[u][1]%mod+C(f[u][0]+1,2))%mod);
145         else
146             printf("%lld",(f[u][0]*f[v][0]%mod+f[u][1]*f[v][0]%mod+f[u][1]*f[v][0]%mod)%mod);
147     }
148 }
BZOJ 3162

 

以上是关于BZOJ 3162 独钓寒江雪的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3162 独钓寒江雪

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

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

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

寒江独钓:Windows内核安全编程的图书目录

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