欲望以提升热忱,毅力以磨平高山!|

XichenOC

园龄:1个月粉丝:4关注:0

📂题解
🔖其他
2025-01-20 19:24阅读: 4评论: 0推荐: 0

P1351 [NOIP2014 提高组] 联合权值

P1351 [NOIP2014 提高组] 联合权值

题目翻译:

给定一个\(n\)个节点,\(n-1\)条边的无向连通图。及一颗无根树。求任意两个相距为\(2\)的点求其联合权值\(w_i \times w_j\),输出所有联合权值的和对\(10007\)取模后的结果和最大值(注意:只有和需要取模,而最大值不需要)

思路:

\(1\).若按照普通算法枚举任意两个点,则复杂度为\(n^2\),一定会\(TLE\)。因此我们分析发现,任意两点间距\(2\),那一定中间有一个点连接它们,这样我就只需要枚举所有连接了两个点的点即可。


\(2.\)那如何求权值和了?我们设一个点连接两个点\(a,b\),则有联合权值等于:

\[2w_aw_b=(w_a+w_b)^2-(w_a^2+w_b^2) \]

设有三个点\(a,b,c\),则:

\[2w_aw_b+2w_aw_c+2w_bw_c=(w_a+w_b+w_c)^2-(w_a^2+w_b^2+w_c^2) \]

以此类推可以发现,任意一点做中间点,那它周围所有点的联合权值和等于和的平方减去平方和(注意取模)


\(3.\)求最大值只需要在每个中间点周围点的权值最大和第二大的联合权值求最大即可

完整代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
const int P=10007;
vector<int>e[N];
int w[N];
signed main(){
    int n;
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    int maxn=-2e9,ans=0;
    for(int i=1;i<=n;i++){
        if(e[i].size()>1){
            int sum=0,sub=0;
            priority_queue<int>q;
            for(auto ed:e[i]){
                sum+=w[ed];
                sum%=P;
                sub+=w[ed]*w[ed]%P;
                sub%=P;
                q.push(w[ed]);
            }
            ans=(ans+(sum*sum)%P+P-sub)%P;
            ans%=P;
            int now=q.top();
            q.pop(),now*=q.top();
            maxn=max(maxn,now);
        }
    }
    cout<<maxn<<" "<<ans;
}

本文作者:XichenOC

本文链接:https://www.cnblogs.com/XichenOC/p/18682379

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   XichenOC  阅读(4)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起