zoukankan      html  css  js  c++  java
  • [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
    ",(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
    ",(f[x][0] * f[y][0] + f[x][0] * f[y][1] + f[x][1] * f[y][0]) % mod) ;
            else printf("%lld
    ",(C(f[x][0] + 1 , 2) + f[x][0] * f[y][1]) % mod) ;
        }
        return 0 ;
    }
    
  • 相关阅读:
    ApacheCN 所有教程/文档集已备份到 Coding
    固态硬盘寿命天梯榜 2021.7
    一个垃圾佬的自我修养(一)工作站篇
    Java 向上转型
    记一次chromedriver与浏览器版本不匹配导致的问题(mac版本)
    关于C# 里面的axWindowsMediaPlayer的使用
    WCHAR的相关操作 范例 , 同时也是产生创建Sqlserver语句新表的 Sql
    C++ Win32 sokcet2.0版本 TCP 服务器
    C++ WIN 32 socket 2.0版本 TCP客户端
    数据库和传感器糅合 数据部分程序 正常运行
  • 原文地址:https://www.cnblogs.com/beretty/p/10270399.html
Copyright © 2011-2022 走看看