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;
    }
  • 相关阅读:
    iOS中Zbar二维码扫描的使用
    SOJ 1135. 飞跃原野
    SOJ 1048.Inverso
    SOJ 1219. 新红黑树
    SOJ 1171. The Game of Efil
    SOJ 1180. Pasting Strings
    1215. 脱离地牢
    1317. Sudoku
    SOJ 1119. Factstone Benchmark
    soj 1099. Packing Passengers
  • 原文地址:https://www.cnblogs.com/sin-mo/p/7191789.html
Copyright © 2011-2022 走看看