zoukankan      html  css  js  c++  java
  • Luogu P1351 联合权值

    gate

    第一反应是树形dp,讨论兄弟和爷爷两种情况。想了想觉得不够优雅就去看了题解…

    优雅的做法是枚举中间点!

    设当前点为x,x所连的点为(a,b,c,...)

    对于求最大值,只要每次记录x连接的最大的两个点,并检查更新答案即可。

    因为求有序点对,所以(a,b)(b,a)都会被算一次。

    那么x的最终贡献即为$2ab+2ac+2bc+...$

    它等价于$(a+b+c+...)^2 - (a^2+b^2+c^2...)$

    注意:取模的时候因为有减法,必须保证答案为正数。

    代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    using namespace std;
    
    const int maxn = 4e5+10;
    const int mod = 10007;
    int n,x,y,m1,m2,s1,s2;
    int w[maxn],head[maxn],to[maxn],nxt[maxn];
    int M,ans,cnt;
    
    void add(int x,int y) {
        to[++cnt] = y;
        nxt[cnt] = head[x];
        head[x] = cnt;
    }
    
    int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n-1; i++) {
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        for(int i = 1; i <= n; i++)
            scanf("%d",&w[i]);
        for(int k = 1; k <= n; k++) {
            m1 = m2 = s1 = s2 = 0;
            for(int i = head[k]; i; i = nxt[i]) {
                int v = to[i];
                if(w[v] > m1) {
                    m2 = m1;
                    m1 = w[v];
                } else if(w[v] > m2) m2 = w[v];
                s1 = (s1 + w[v]) %mod;
                s2 = (s2 + w[v]*w[v]) %mod;
            }
            M = max(M,m1*m2);
            ans = (ans + (s1*s1%mod) %mod - s2 + mod)%mod;
        }
        printf("%d %d",M,ans);
        return 0;
    }
    View Code
  • 相关阅读:
    C++中迭代器失效的问题
    怎么转载别人的博客
    Linux下模拟实现shell
    Linux下的文件描述符与文件指针及其区别
    智能指针
    C++模板(下)
    C++中的模板(上)
    僵尸进程和孤儿进程
    Linux下的atexit函数
    多线程练习
  • 原文地址:https://www.cnblogs.com/mogeko/p/11635526.html
Copyright © 2011-2022 走看看