zoukankan      html  css  js  c++  java
  • Noip 2014 senior 复赛 联合权值(link)

    Noip 2014 senior 复赛 联合权值(link)

    【问题描述】

    无向连通图G有n个点,n-1条边。点从1到n依次编号,编号为i的点的权值为Wi,每条边的长度均为 1。图上两点(u, v)的距离定义为u点到v点的最短距离。对于图 G 上的点对(u, v),若它们的距离为2,则它们之间会产生的联合权值。

    请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

    【输入】

    输入文件名为 link.in。

    第一行包含1个整数 n。

    接下来n-1行,每行包含2个用空格隔开的正整数u、v,表示编号为u和编号为v的点之间有边相连。

    最后1行,包含n个正整数,每两个正整数之间用一个空格隔开,其中第i个整数表示图 G 上编号为 i 的点的权值为 Wi。

    【输出】

    输出文件名为 link.out。

    输出共 1 行,包含 2 个整数, 之间用一个空格隔开, 依次为图 G 上联合权值的最大值

    和所有联合权值之和。 由于所有联合权值之和可能很大,输出它时要对 10007 取余。

           这道题由于模型是在树上,所以我们想到使用树形DP。定义f(i)表示以i为根的子树中的点对权值乘积之和,g(i)表示以i为根的子树中的点对权值乘积的最大值,sums1(i)表示i结点的儿子的权值之和,sums2(i)表示i结点的儿子的权值平方之和,sumg(i)表示i结点的孙子的权值之和,max1(i)表示结点i儿子权值的最大值,max2(i)表示结点i儿子权值的次大值,max3(i)表示结点i孙子权值的最大值。则有:

          

           所以求解这个问题就比较清晰了。

           还有就是在一个较优算法代码中(枚举,因为没有透彻理解我就不做过多解释了,只给出代码)发现了使用连续4次异或等于( ^= ),通过李兄的详细讲解知道这是swap的意思,只不过不是很稳定。

           算了,还是给出枚举的大致思路吧。

    维护max1(i),max2(i)分别表示与i相连结点最大权值和次大权值,sum1(i)表示与i相连结点权值之和,sum2(i)表示与i相连结点权值平方和。任意长度为2的点对(i,j)有一个中间结点k,中间结点为k的最大权值之积为max1(k)*max2(k),与k相连结点为x1,x2...xm,则权值乘积之和   W_x1*(W_x2+W_x3+…+W_xm)+W_x2*(W_x1+W_x3+…+W_xm)+…+W_xm*(W_x1+W_x2+…+W_xm-1)=sum1(k)*sum1(k)-sum2(k)枚举k,更新答案即可。时间复杂度为O(n),。

    #include<iostream> //dynamic programming
    #include<cstdio>
    #include<algorithm>
    #include<vector>
    #define pi acos(-1)
    #define inf 0x7fffffff
    using namespace std;
    
    #define N 200010
    #define mod 10007
    
    inline long long read(){ 
        long long data=0,w=1; 
        char ch=0; 
        while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); 
        if(ch=='-') w=-1,ch=getchar(); 
        while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); 
        return data*w;
    }
    
    inline void write(long long x)
    {
         if(x<0) putchar('-'),x=-x;
         if(x>9) write(x/10);
         putchar(x%10+'0');
    }
    
    int n;
    long long w[N],maxn[N],sum[N];
    long long ans_max[N],ans_sum[N];
    vector <int> e[N];
    
    inline void Dynamic_Programming(int u,int father)
    {
        for(int i=0;i<e[u].size();i++)
        {
            int v = e[u][i];
            if(v == father) continue;
            Dynamic_Programming(v,u);
            maxn[u] = max(maxn[u],w[v]);
            sum[u] = (sum[u] + w[v]) % mod;
            ans_max[u] = max(ans_max[u],w[u] * maxn[v]);
            ans_max[u] = max(ans_max[u],ans_max[v]);
            ans_sum[u] = (ans_sum[u] + w[u] * sum[v]) % mod;
            ans_sum[u] = (ans_sum[u] + ans_sum[v]) % mod;
        }
        long long aider1 = 0, aider2 = 0;
        for(int i=0;i<e[u].size();i++)
        {
            int v = e[u][i];
            if(v == father) continue;
            ans_max[u] = max(ans_max[u],aider1 * w[v]);
            ans_sum[u] = (ans_sum[u] + aider2 * w[v]) % mod;
            aider1 = max(aider1,w[v]);
            aider2 = (aider2 + w[v]) % mod;
        }
    }
    
    int main()
    {
        n = read();
        for(int i=1;i<n;i++)
        {
            int u = read(), v = read();
            e[u].push_back(v);
            e[v].push_back(u);
        }
        for(int i=1;i<=n;i++)
        {
            w[i] = read();
            w[i] %= mod;
        }
        Dynamic_Programming(1,0);
        write(ans_max[1]);
        putchar(' ');
        write(ans_sum[1] * 2 % mod);
        
        return 0;
    }
    #include<iostream> //enumerate
    #include<cstdio>
    using namespace std;
    
    #define mod 10007
    #define N 200010
    
    inline int read(){ 
        int data=0,w=1; 
        char ch=0; 
        while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar(); 
        if(ch=='-') w=-1,ch=getchar(); 
        while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar(); 
        return data*w;
    }
    
    inline void write(int x)
    {
         if(x<0) putchar('-'),x=-x;
         if(x>9) write(x/10);
         putchar(x%10+'0');
    }
    
    int n,u,v;
    int d[N];
    
    struct Edge{
        int v,next;
    }edge[N << 1];
    
    int cnt,head[N];
    
    inline void addedge(int u,int v)
    {
        edge[++cnt].v = v;
        edge[cnt].next = head[u];
        head[u] = cnt;
    }
    
    int pre[N],father[N];
    int ans_max,ans_sum;
    int visit[N];
    
    void dfs(int u)
    {
        visit[u] = 1;
        int sum = 0,maxn[3] = {0,0,0};
        for(int i=head[u];i;i=edge[i].next)
        {
            if(!visit[edge[i].v])
            {
                dfs(edge[i].v);
                father[edge[i].v] = u;
                sum = (sum  +  d[edge[i].v]) % mod;
                ans_sum = (ans_sum - d[edge[i].v] * d[edge[i].v]) % mod;
                if(maxn[0] != 2) maxn[0]++;
                if(maxn[1] < d[edge[i].v]) maxn[1] = d[edge[i].v];
                if(maxn[2] < maxn[1]) swap(maxn[1],maxn[2]);
            }
        }
        ans_sum = (ans_sum + sum * sum) % mod;
        if(maxn[0] == 2) ans_max = max(ans_max,maxn[1] * maxn[2]);
    }
    
    void work()
    {
        dfs(1);
        for(int i=1;i<=n;i++) pre[i] = father[father[i]];
        for(int i=1;i<=n;i++)
        {
            if(pre[i])
            {
                int aider = d[i] * d[pre[i]];
                ans_max = max(ans_max,aider);
                ans_sum = (ans_sum + aider * 2) % mod;
            }
        }
        if(ans_sum < 0) ans_sum += mod;
        write(ans_max);
        putchar(' ');
        write(ans_sum);
    }
    
    int main()
    {
    //    freopen("link.in","r",stdin);
    //    freopen("link.out","w",stdout);
        
        n = read();
    //    scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            u = read();
            v = read();
    //        scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }
        for(int i=1;i<=n;i++) /*scanf("%d",&d[i]);*/
            d[i] = read();
        work();
        
        return 0;
    }
  • 相关阅读:
    Myeclipse新建 配置Hibernate
    MyEclipse从数据库表反向生成实体类之Hibernate方式(反向工程)
    简单使用JSON,JavaScript读取JSON文本(三)
    简单使用JSON,通过JSON 字符串来创建对象(二)
    简单使用JSON,JavaScript中创建 JSON 对象(一)
    【某deed网测题】D
    【题解】ACMICPC 2015 final L 哈弗曼树
    TC SRM 659 DIV1 500pt 插头DP
    BC#40D GCD值统计
    MS电面3轮
  • 原文地址:https://www.cnblogs.com/sin-mo/p/7191789.html
Copyright © 2011-2022 走看看