Input
Output
Sample Input
Sample Output
HINT
Source
2013湖北互测week1
http://www.elijahqi.win/archives/2923
orz vfk orz icefox
想做这道题很久了 看网上题解也看了很久了始终明白不了 后来有幸看到icefox巨佬的题解看到了http://vfleaking.blog.163.com/blog/static/17480763420134452440444/
去看一看vfk原来的题解就会豁然开朗
如何hash一棵树 学习了下scarlyw巨佬的blog 就是根据子树大小把子树的hash值都加起来即可 如果专门只求树上独立集计数的话 答案就是设dp[i][0/1]分别表示当前处于i号节点我是否选取当前节点 那么dp[i][1]=显然就是所有子树中不选的乘积
dp[i][0]就是所有子树中选与不选和的乘积
学习了一个组合数学的相关知识 当时bj集训的时候有一道题我看出来是这样做了然而不会算这个的通式 即:有n种物品要求从中选m个求问方案数 那么就是c(n+m-1)(m)
但是这题要求求本质不同的独立集个数 这时候就需要做的时候把所有本质相同的看作一个子树 那么就相当于在这些本质相同中选xx个 利用上面的组合数学相关知识即可解决由于结构不同的子树再怎么弄都不会成为本质 相同的,所以我们将结构相同的子树分成一块
#include<cstdio>
#include<cctype>
#include<algorithm>
#define g 233
#define N 500010
using namespace std;
const int mod=1e9+7;
#define ll unsigned long long
inline char gc(){
static char now[1<<16],*S,*T;
if (T==S) {T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
int y,next;
}data[N<<1];
ll p[N],hs[N];ll dp[N][2];//1->choose this node 0->not choose
int size[N],h[N],n,G1,G2,inv[N],num;
inline void get_root(int x,int fa){
size[x]=1;bool flag=1;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa) continue;
get_root(y,x);size[x]+=size[y];
if (size[y]*2>n) flag=0;
}if (size[x]*2<n) flag=0;if (flag) !G1?G1=x:G2=x;
}
inline bool cmp(const int &a,const int &b){return hs[a]<hs[b];}
inline int calc(ll n,int m){static ll ans;ans=1;n%=mod;
for (int i=m;i;--i) ans=ans*inv[i]%mod*(n+1-i)%mod;return ans;
}
inline void dfs(int x,int fa){
static int q[N],top;hs[x]=1;size[x]=1;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if(y==fa) continue;
dfs(y,x);size[x]+=size[y];hs[x]+=p[size[y]]*hs[y];
}top=0;
for (int i=h[x];i;i=data[i].next){
int y=data[i].y;if (y==fa) continue;q[++top]=y;
}sort(q+1,q+top+1,cmp);dp[x][0]=dp[x][1]=1;
for (int i=1,j;i<=top;i=j){static int v;
for (j=i+1;j<=top&&hs[q[i]]==hs[q[j]];++j);v=q[i];
dp[x][0]=dp[x][0]*calc(dp[v][0]+dp[v][1]+j-i-1,j-i)%mod;
dp[x][1]=dp[x][1]*calc(dp[v][0]+j-i-1,j-i)%mod;
}
}
int main(){
freopen("bzoj3162.in","r",stdin);
n=read();p[0]=1,p[1]=g,inv[1]=1;
for (int i=2;i<=n;++i) inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod,p[i]=p[i-1]*g;
for (int i=1;i<n;++i){
static int x,y;x=read();y=read();
data[++num].y=y;data[num].next=h[x];h[x]=num;
data[++num].y=x;data[num].next=h[y];h[y]=num;
}get_root(1,1);int ans=0;
G2?(dfs(G1,G2),dfs(G2,G1)):dfs(G1,G1);
if(G2){
if (hs[G1]!=hs[G2]) ans=(dp[G1][0]*dp[G2][1]+dp[G1][1]*dp[G2][0]+dp[G1][0]*dp[G2][0])%mod;
else ans=(dp[G1][0]*dp[G1][1]+calc(dp[G1][0]+1,2))%mod;
}else ans=(dp[G1][0]+dp[G1][1])%mod;
printf("%d\n",ans);
return 0;
}