1800*1【Codeforces Round #665 (Div. 2) D】Maximum Distributed Tree

题目链接

链接

翻译

让你给树上的每条边分配一个数字。要求这 \(n-1\) 个数的乘积要等于 \(k\)

分配的 \(1\) 的个数要尽可能少。

这个 \(k\) 质因数分解的时候,每个质因子的指数都是 \(1\),且 \(k\) 是以告诉你它每个质因子的形式给出的。

要求树上任意两点之间的距离和最大。输出这个最大值。

题解

感觉证明做法的正确性会比做法本身难。。

首先解决两点之间距离和这个问题。

可以转换成求树上的所有边,每条边的两边有多少条路径会经过这条边。(也即这条边对最后的路径和的贡献)

有几条路径 \(cnt[i]\) 会经过这条边 \(i\),这条边的权值就要乘上几。

这样,答案就呼之欲出了。我们只要把大的质因子分配到那些 \(cnt\) 大的边上就可以了。

但是会出现 \(m>n-1\) 的情况,对于这种情况,把最大的 \(m-(n-1)\) 个质因子,乘起来,然后再和第 \(m-(n-1)+1\) 大的质因子乘一下就好。

这样就又变成 \(n-1\) 个权值待分配了。

而对于 \(m\lt n-1\) 的情况,不足的部分只能用 \(1\) 补了(没办法避免用这些 \(1\),所以数目肯定是最少的)

代码

#include <bits/stdc++.h>
#define lson l,mid,rt*2
#define rson mid+1,r,rt*2+1
#define LL long long
using namespace std;

const int N = 1e5;
const LL MOD = 1e9+7;

LL p[N+10],dp[N+10],cnt[N*2+10];
int fir[N+10],nex[N*2+10],en[N*2+10],totm,n,m;

void add(int x,int y){
    totm++;
    nex[totm] = fir[x];
    fir[x] = totm;
    en[totm] = y;
}

void dfs(int x,int fa){
    dp[x] = 1;
    for (int i = fir[x];i>0;i = nex[i]){
        int y = en[i];
        if (y == fa){
            continue;
        }
        dfs(y,x);
        dp[x] += dp[y];
        cnt[i] = 1LL*(n-dp[y])*dp[y];
    }
}

int main(){
    // freopen("C://1.cppSourceProgram//rush.txt","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0);
    int T;
    cin >> T;
    while (T--){
        memset(cnt,0,sizeof(cnt));
        totm = 0;
        for (int i = 1;i <= n; i++){
            fir[i] = 0;
        }
        cin >> n;
        for (int i = 1;i <= n - 1; i++){
            int x,y;
            cin >> x >> y;
            add(x,y);
            add(y,x);
        }
        dfs(1,-1);
        sort(cnt+1,cnt+1+totm);
        reverse(cnt+1,cnt+1+totm);
        //从大到小,只有前n-1条边的cnt>0
        totm = n-1;
        cin >> m;
        for (int i = 1;i <= m; i++){
            cin >> p[i];
        }
        sort(p+1,p+1+m);
        reverse(p+1,p+1+m);
        if (m <= n-1){
            //从大到小安排
            LL ans = 0;
            for (int i = 1;i <= m; i++){
                ans = ans + p[i]*cnt[i]%MOD;
                ans%=MOD;
            }
            //剩余的全是 1
            for (int i = m+1;i <= n-1; i++){
                ans = ans + 1*cnt[i];
                ans%=MOD;
            }
            cout << ans << endl;
        }else{
            //如果给的因子数目太多了。。就把最高的 m-(n-1)个合成一个。
            for (int i = 1;i <= m-(n-1);i++){
                p[m-(n-1)+1] = p[m-(n-1)+1]*p[i]%MOD;
            }
            LL ans = 0;
            for (int i = m-(n-1)+1,j = 1; i <= m; i++,j++){
                ans = ans + p[i]*cnt[j]%MOD;
                ans%=MOD;
            }
            cout << ans << endl;
        }
    }
    return 0;
}

posted @ 2020-12-25 18:08  AWCXV  阅读(76)  评论(0编辑  收藏  举报