[BZOJ:3162]:独钓寒江雪

题解:

求本质不同的独立集的个数

首先独立集的个数是很好做的

\(f[u][0/1]\)表示节点\(u\)不选/选的方案数

然后dp就是

\(f[u][0] = f[u][0] * (f[v][0] + f[v][1])\)

\(f[u][1] = f[u][1] * f[v][0]\)

考虑怎么去重

不论把这个树怎么转或者以哪一个点为根

最后重心肯定不会变

所以我们可以把重心拎出来当根

一般在树上求本质不同的东西可以优先考虑重心

然后如果有两个重心(最多肯定只有两个==)那么这两个重心肯定由一条边连着

就可以新建一个节点连向这两个重心

然后dp

在dp计数的时候

如果\(k\)个子树\(v\)是本质上相同的

那么这\(k\)个子树的贡献总和就是就是\(C(f[v][0] + (f[v][1]) + k - 1 , k)\)

要求的是本质不同的独立集

所以就相当于可以随意编号

那么我们假设有n个子树,每个子树都有m个方案

那么我们按照选择的方案排序后如果相同就是重复的

所以我们就让后面的每一个选择的方案编号都比前一个大

这样就相当于方程整数解问题了

还有一个问题就是这个组合数怎么算?

因为k不大但是前面那个东西太大了

所以我们就相当于把\(C(n,m)\)底下那个\((n-m)!\)和上面的约分

那么就变成了\(\frac{n * (n - 1) * .. * (n - m + 1)}{m!}\)

然后注意这题卡哈希卡的挺厉害

最后换成我的生日才过的

代码

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define LL long long
# define ull unsigned long long
const int M = 500005 ;
const long long mod = 1e9 + 7 ;
const long long INF = 1e9 ;
const ull Base = 23333333333ULL ;
using namespace std ;
inline int read() {
    char c = getchar() ; int x = 0 , w = 1 ;
    while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ;  }
    while(c >='0' && c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    return x*w ;
}

int n , num = 1 , hea[M] ;
int size[M] , sonsz[M] , tmx = INF , rtnum , rt[M] , st[M] ;
long long fac[M] , finv[M] ;
LL f[M][2] ;
ull hsh[M] ;
struct E { int nxt , to ; } edge[M << 1] ;

inline void add_edge(int from , int to) {
    edge[++num].nxt = hea[from] ;  
    edge[num].to = to ; hea[from] = num ; 
}
inline bool Cmp(int a , int b) {
    if(hsh[a] == hsh[b]) return ((f[a][0] + f[a][1]) % mod < (f[b][0] + f[b][1]) % mod) ;
    return hsh[a] < hsh[b] ;
}
inline bool Same(int a , int b) {
    if(hsh[a] == hsh[b] && ((f[a][0] + f[a][1]) % mod) == ((f[b][0] + f[b][1]) % mod)) return true ;
    return false ;
}
inline long long Fpw(long long Base , int k) {
    long long temp = 1 ;
    while(k) {
        if(k & 1) temp = (temp * Base) % mod ;
        Base = (Base * Base) % mod ; k >>= 1 ;
    }
    return temp ;
}
void Grt(int u , int father) {
    size[u] = 1 ; int Mx = -1 ;
    for(int i = hea[u] ; i ; i = edge[i].nxt) {
        int v = edge[i].to ; if(v == father) continue ;
        Grt(v , u) ; size[u] += size[v] ; Mx = max(Mx , size[v]) ;
    }
    Mx = max(Mx , n - size[u]) ; sonsz[u] = Mx ; tmx = min(tmx , Mx) ;
}
inline long long C(long long n , int m) {
    n %= mod ; if(n < m) return 0 ; long long Ans = 1 ; m = min(1LL * m , n - m) ;
    for(int i = n ; i >= n - m + 1 ; i --) Ans = (1LL * Ans * i) % mod ;
    Ans = (Ans * finv[m]) % mod ; return Ans ;
}
void Dfs(int u , int father) {
    f[u][0] = f[u][1] = 1 ;
    for(int i = hea[u] ; i ; i = edge[i].nxt) {
        int v = edge[i].to ; if(v == father) continue ;
        Dfs(v , u) ;
    }
    int top = 0 ;
    for(int i = hea[u] ; i ; i = edge[i].nxt) {
        int v = edge[i].to ; if(v == father) continue ;
        st[++top] = v ;
    }
    sort(st + 1 , st + top + 1 , Cmp) ;
    int l = 1 , r = 0 ;
    for(int v ; l <= top ; l = r + 1) {
        for(r = l ; r <= top ; r ++) {
            if(!Same(st[l] , st[r]))
                break ;
        }
        r -- ;
        v = st[l] ;
        f[u][1] = (f[u][1] * C(f[v][0] + r - l , r - l + 1)) % mod ;
        f[u][0] = (f[u][0] * C(f[v][0] + f[v][1] + r - l , r - l + 1)) % mod ;
    }
    ull tmp = 0 ;
    for(int i = 1 ; i <= top ; i ++)
        tmp = (tmp * Base + (hsh[st[i]] + i) * 20020911uLL) ;
    hsh[u] = tmp ;
}
int main() {
    n = read() ; fac[0] = 1 ; finv[0] = 1 ;
    for(int i = 1 ; i <= n ; i ++) {
        fac[i] = (fac[i - 1] * i) % mod ;
        finv[i] = Fpw(fac[i] , mod - 2) ;
    }
    for(int i = 1 , u , v; i < n ; i ++) {
        u = read() , v = read() ;
        add_edge(u , v) ; add_edge(v , u) ;
    }
    Grt(1 , 1) ;
    for(int i = 1 ; i <= n ; i ++)
        if(sonsz[i] == tmx) 
            rt[++rtnum] = i ;

    int k = rt[1] ;
    for(int i = hea[rt[1]] ; i ; i = edge[i].nxt) {
        int v = edge[i].to ;
        if(v == rt[2]) {
            k = n + 1 ;
            edge[i].to = edge[i ^ 1].to = k ;
            break ;
        }
    }
    if(rtnum > 1) {
        add_edge(k , rt[1]) ;
        add_edge(k , rt[2]) ;
    }
    Dfs(k , k) ;
    if(rtnum == 1) printf("%lld\n",(f[rt[1]][0] + f[rt[1]][1] + mod) % mod) ;
    else if(rtnum == 2) {
        int x = rt[1] , y = rt[2] ;
        if(hsh[x] != hsh[y])
            printf("%lld\n",(f[x][0] * f[y][0] + f[x][0] * f[y][1] + f[x][1] * f[y][0]) % mod) ;
        else printf("%lld\n",(C(f[x][0] + 1 , 2) + f[x][0] * f[y][1]) % mod) ;
    }
    return 0 ;
}
posted @ 2019-01-15 10:07  beretty  阅读(164)  评论(0编辑  收藏  举报