zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 160 F(ABC160F) Distributing Integers题解

    看到读的人多了还是说一下吧,这个可能不是正解。。。

    ABC160F 链接

    很遗憾,这篇题解并不会有特别详细的分析(因为懒)

    如果没有对每个节点求答案就和TDPC的“木”那题差不多。

    由于需要算每个节点,考虑换根(dp)

    (f_i)(i) 这个子树里放的方案数,(g_i)为这个子树外面放的方案数。

    可得:$$f_i = prodlimits_{j in son_i} C_{rest}^{siz_j} f_j$$其中(rest)为未转移子树中节点的总数,边转移边减。

    [g_i = g_{fa} imes C_{n - siz_{to} - 1}^{n - siz_{x}} imes prodlimits_{j in son_{fa}} C_{rest}^{siz_j} f_j ]

    但是直接转移 (g) 最坏是 (O(n^2)) 的。

    考虑优化:把

    [prodlimits_{j in son_{fa}} C_{rest}^{j} f_j ]

    拆成 (prodlimits_{j in son_{fa}} C_{rest}^{j})(prodlimits_{j in son_{fa}} f_j)

    右边的式子可以先把 (f_j) 全部乘起来,再乘以逆元。

    对左边的式子,可以发现: (cnt_j) 相同时,这个式子的值也相同。所以可以用(map)判重,保证每种只算一次。

    (伪)证:一个节点如果下面一共有(k)个节点,下面最多有约 (sqrt{k}) 个大小互不相同的子树。每个都暴力一下,用去的时间为(O(k))。这样复杂度减小很快,应该很难卡掉。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define mit map<int,int>::iterator
    #define sit set<int>::iterator
    #define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
    #define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
    #define ltype int
    #define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
    #define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
    #define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define mpr make_pair
    #define pb push_back
    #define fastio ios::sync_with_stdio(false)
    const int inf=0x3f3f3f3f,mod=1000000007;
    const double pi=3.1415926535897932,eps=1e-6;
    void chmax(int &x,int y){if(x < y) x = y;}
    void chmin(int &x,int y){if(x > y) x = y;}
    int n,fac[200005],inv[200005],f[200005],g[200005],root,siz[200005],ans[200005];
    vector<int> v[200005];
    int qpow(int x,int y){
        int res = 1;
        while(y){
            if(y&1) res = (ll)res * x % mod;
            x = (ll)x*x%mod;
            y>>=1;
        }
        return res;
    }
    int getinv(int x){
        return qpow(x, mod - 2);
    }
    int dfs1(int x,int fa){
        siz[x]++;
        rap(i,0,v[x].size()){
            int to = v[x][i];
            if(to == fa) continue;
            siz[x] += dfs1(to,x);
        }
        return siz[x];
    }
    int C(int x,int y){
        if(x < y || x < 0 || y < 0) return 0;
        return (ll)fac[x] * inv[y] % mod * inv[x - y] % mod;
    }
    map<ll,int> vals[200005];
    void dfs(int x,int fa){
        int cur = 1,rest = siz[x] - 1;
        rap(i,0,v[x].size()){
            int to = v[x][i];
            if(to == fa) continue;
            dfs(to,x);
            cur = (ll)cur * f[to] % mod * C(rest,siz[to]) % mod;
            rest -= siz[to];
        }
        f[x] = cur;
    }
    void dfs2(int x,int fa){
        ans[x] = (ll) f[x] * g[x] % mod * C(n - 1,siz[x] - 1) % mod;
        ll product = 1;
        rap(i,0,v[x].size()){
            int to = v[x][i];
            if(to == fa) continue;
            product = product * f[to] % mod;
        }
        rap(i,0,v[x].size()){
            int to = v[x][i];
            if(to == fa) continue;
            g[to] = (ll)g[x] * C(n - siz[to] - 1,n - siz[x]) % mod;
            g[to] = (ll)g[to] * product % mod * getinv(f[to]) % mod;
            if(vals[x].find(siz[to]) != vals[x].end()) g[to] = (ll)g[to] * vals[x][siz[to]] % mod;
            else {
                int rest = siz[x] - 1 - siz[to];ll calcing = 1;
                rap(j,0,v[x].size()) if(i != j){
                    int to2 = v[x][j];
                    if(to2 == fa) continue;
                    calcing = (ll) calcing * C(rest, siz[to2]) % mod;
                    rest -= siz[to2];
                }
                g[to] = (ll)g[to] * calcing % mod;
                vals[x][siz[to]] = calcing;
            }
            dfs2(to,x);
        }
    }
    int main()
    {
        scanf("%d",&n);
        rep(i,2,n){
            int t1,t2;
            scanf("%d%d",&t1,&t2);
            v[t1].pb(t2);
            v[t2].pb(t1);
        }
        fac[0] = 1;rep(i,1,n) fac[i] = (ll)fac[i-1] * i % mod;
        rep(i,0,n) inv[i] = getinv(fac[i]);
        rep(i,1,n) if(v[i].size() == 1) {root = i;break;}
        g[root] = 1;
        dfs1(root,0);
        dfs(root,0);
        dfs2(root,0);
        rep(i,1,n) printf("%d
    ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    2015年5月1日 转载--各种变量在内存中的分布
    2015年4月30日 计算两个日期天数,写的代码
    2015年4月29日 dayofweek
    2015年4月28日
    2015年4月28日----高大上的数组,进制准换,最多是35进制
    2015年4月27日---C语言:输出特殊图案,请在c环境中运行,看一看,Very Beautiful!
    2015年4月27日
    《C++ Primer》学习笔记:迭代器介绍
    《C++ Primer》学习笔记:3.3.3其他vector操作
    《C++ Primer》学习笔记:向vector对象添加元素蕴含的编程假定
  • 原文地址:https://www.cnblogs.com/yz-beacon-cwk/p/12591614.html
Copyright © 2011-2022 走看看