洛谷1351 联合权值

原题地址

https://www.luogu.org/problem/show?pid=1351

枚举 数论 贪心

一开始想到的又不是标解,跑了跑发现T了4个点……然后对照题解发现确实太暴力了,只有枚举连个优化都没有……

解题思路

60分算法:

枚举每个点,然后枚举和这个点相连的两个点,求联合权值的最大值,并加入和(ans)中(先乘2再加,因为(i,j)和(j,i)算两对),显然时间复杂度爆了。

100分算法:

①预处理出每个点相连的点中的最大值和次大值,二者的联合权值一定比以该点为中心的两个点的其他情况更优,然后再枚举每个点(仅有一条边相连的除外)中心点,可以求出第一问;

②用数学知识我们可以知道,若a,b,c,d,e,f都与i相连,则以i为中心的所有可行方案的联合权值之和为sum=a*b+a*c+a*d+……+e*f, 其实就是每个点的权值乘以可以联合的节点的所有权值之和, 所有权值之和,所以假设每个节点相连的所有点的权值和为sum[i],则以i为中心点的权值和为ans=a*(sum[i]-a)+b*(sum[i]-b)+……+f*(sum[i]-f),枚举每条边就可以求出最终解了。

参考代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
const long long p=10007;
long longw[200005],r[200005],v[200005],tmp[200005];
long long max1[200005],max2[200005],sum[200005];
int num=0;
 
struct mc
{
     intx,y,ne;
}e[400005];
 
void put(int x,int y)
{
     num++;
     e[num].x=x;
     e[num].y=y;
     e[num].ne=v[x];
     v[x]=num;
}
 
int main()
{
     int n;
     scanf("%d",&n);
     memset(r,0,sizeof(r));
     intx,y;
     for(int i=1;i<n;i++)
     {
         scanf("%d%d",&x,&y);
         put(x,y);
     }
     for(int i=1;i<=n;i++)
     {
         scanf("%d",&w[i]);
        
     }
     memset(max1,0,sizeof(max1));
     memset(max2,0,sizeof(max2));
     memset(sum,0,sizeof(sum));
     for(inti=1;i<n;i++)
     {
         intx=e[i].x;
         inty=e[i].y;
         sum[x]+=w[y];
         sum[y]+=w[x];
         if(w[y]>max1[x])
         {
              max2[x]=max1[x];
              max1[x]=w[y];
         }
         elseif (w[x]>max2[y]) max2[y]=w[x];
         if(w[x]>max1[y])
         {
              max2[y]=max1[y];
              max1[y]=w[x];
         }
         elseif (w[x]>max2[y]) max2[y]=w[x];
     }
     longlong mx=0,ans=0;
     for(int i=1;i<=n;i++)
     {
         if(!max2[i]) continue;
         if(max1[i]*max2[i]>mx) mx=max1[i]*max2[i];
     }
     for(int i=1;i<n;i++)
     {
         intx=e[i].x;
         inty=e[i].y;
         ans=(ans+(sum[x]-w[y])*w[y]%p)%p;
         ans=(ans+(sum[y]-w[x])*w[x]%p)%p;
     }
     cout<<mx<<''<<ans;
     return0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值