zoukankan      html  css  js  c++  java
  • [bzoj3162]独钓寒江雪_树hash_树形dp

    独钓寒江雪

    题目链接https://www.lydsy.com/JudgeOnline/problem.php?id=3162


    题解

    首先,如果没有那个本质相同的限制这就是个傻逼题。

    直接树形dp就好。

    那么如果加上那个限制呢?

    我们发现,无论最后怎么本质相同,树的重心一定不变。

    故此,从重心开始去重即可。

    参考:https://www.cnblogs.com/zhoushuyu/p/9295759.html

    代码

    #include <bits/stdc++.h>
    
    #define N 500010 
    
    using namespace std;
    
    const int mod = 1000000007 ;
    
    char *p1, *p2, buf[100000];
    
    typedef unsigned long long ll;
    
    ll bs1 = 20021214 ;
    
    ll bs2 = 20030315 ;
    
    #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1 ++ )
    
    int rd() {
        int x = 0;
        char c = nc();
        while (c < 48) {
            c = nc();
        }
        while (c > 47) {
            x = (((x << 2) + x) << 1) + (c ^ 48), c = nc();
        }
        return x;
    }
    
    int n, inv[N], to[N << 1], nxt[N << 1], head[N], tot, sz[N], w[N], root, rt1, rt2, flag, f[2][N], tmp[N];
    
    ll hs[N];
    
    inline void add(int x, int y) {
        to[ ++ tot] = y;
        nxt[tot] = head[x];
        head[x] = tot;
    }
    
    void getroot(int p, int fa) {
        sz[p] = 1;
        w[p] = 0;
        for (int i = head[p]; i; i = nxt[i]) {
            if(to[i] != fa) {
                getroot(to[i], p);
                sz[p] += sz[to[i]];
                w[p] = max(w[p], sz[to[i]]);
            }
        }
        w[p] = max(w[p], n - sz[p]);
        if (w[p] < w[root]) {
            root = p;
        }
    }
    
    int C(int n, int m) {
        int re = 1;
        for (int i = n - m + 1; i <= n; i ++ ) {
            re = (ll)re * i % mod;
        }
        for (int i = 1; i <= m; i ++ ) {
            re = (ll)re * inv[i] % mod;
        }
        return re;
    }
    
    inline bool cmp(int i, int j) {
        return hs[i] < hs[j];
    }
    
    void dfs(int p, int fa) {
        sz[p] = f[0][p] = f[1][p] = 1;
        for (int i = head[p]; i; i = nxt[i]) {
            if (to[i] != fa) {
                dfs(to[i], p);
                sz[p] += sz[to[i]];
            }
        }
        int len = 0;
        for (int i = head[p]; i; i = nxt[i]) {
            if (to[i] != fa) {
                tmp[ ++ len] = to[i];
            }
        }
        sort(tmp + 1, tmp + len + 1, cmp);
        for (int i = 1, j = 1; i <= len; i = j) {
            while (j <= len && hs[tmp[j]] == hs[tmp[i]]) {
                j ++ ;
            }
            f[0][p] = (ll)f[0][p] * C(f[0][tmp[i]] + f[1][tmp[i]] + j - i - 1, j - i) % mod;
            f[1][p] = (ll)f[1][p] * C(f[0][tmp[i]] + j - i - 1, j - i) % mod;
        }
        hs[p] = bs2 * len + sz[p];
        for (int i = 1; i <= len; i ++ ) {
            hs[p] = (hs[p] * bs1) ^ hs[tmp[i]];
        }
    }
    
    int main() {
        n = rd();
        inv[0] = inv[1] = 1;
        for (int i = 2; i <= n; i ++ ) {
            inv[i] = (ll)inv[mod % i] * (mod - mod / i) % mod;
        }
        for (int i = 1; i < n; i ++ ) {
            int x = rd(), y = rd();
            add(x, y), add(y, x);
        }
        w[0] = n;
        getroot(1, 0);
        getroot(root, 0);
        for (int i = head[root], last = 0; i; last = i, i = nxt[i]) {
            if (sz[to[i]] * 2 == n) {
                n ++ ;
                if (i == head[root]) {
                    head[root] = nxt[i];
                }
                else {
                    nxt[last] = nxt[i];
                }
                for (int j = head[to[i]], lst = 0; j; lst = j, j = nxt[j]) {
                    if (to[j] == root) {
                        if (j == head[to[i]]) {
                            head[to[i]] = nxt[j];
                        }
                        else {
                            nxt[lst] = nxt[j];
                        }
                        break;
                    }
                }
                add(n, root);
                add(root, n);
                add(n, to[i]);
                add(to[i], n);
                rt1 = root;
                rt2 = to[i];
                root = n;
                flag = 1;
                break;
            }
        }
        dfs(root, 0);
        if (!flag) {
            cout << (f[0][root] + f[1][root]) % mod << endl ;
        }
        else if (hs[rt1] == hs[rt2]) {
            cout << (f[0][root] - C(f[1][rt1] + 1, 2) + mod) % mod;
        }
        else {
            cout << ((ll)f[0][rt1] * f[0][rt2] + (ll)f[0][rt1] * f[1][rt2] + (ll)f[1][rt1] * f[0][rt2]) % mod << endl ;
        }
    }
    

    小结:树hash的时候,如果一个模数担心过不去,像我一样开两个就好了233

  • 相关阅读:
    VC++6.0 自定义按钮,无标题对话框的拖动方法
    完整的使用线程池的多线程C/S Socket类
    树形控件Tree Control
    关闭数据执行保护
    VC++开发垃圾文件清理软件(下)
    用完成端口开发大响应规模的Winsock应用程序
    去掉右键多余显卡菜单
    自动登陆系统
    查询数据库中所有表名和表中所有字段名
    单行编辑框文本垂直居中(包含计算字体高度)
  • 原文地址:https://www.cnblogs.com/ShuraK/p/11421253.html
Copyright © 2011-2022 走看看