cogs1804 联合权值 dp
填坑……链接:http://cogs.pro/cogs/problem/problem.php?pid=1804
题意:给出一棵树,定义两个距离为2的点权值乘积为这两个点产生的联合权值,求出整棵树最大联合权值及联合权值之和。
实际上早就做过……现在重做旧题感觉还是很有必要……
我们可以枚举每一个点作为可以产生联合权值的两点的中点,对于这个点来说,他周围的点权值之和就是
\sum\limits_{i=1}^N(\sum\limits_{u,v \in adj_i, u \neq v} W_u \times W_v)
然后对于每一个中点,他做出的贡献也就可以表示成
S_i = \sum_{j \in adj_i} (W_j \times (\sum_{k \in adj_i} W_k) - W_j)
然后大力化简可得
S_i ={ (\sum_{j \in adj_i} W_j)} ^ 2 - \sum_{j \in adj_i} W_j^2
这也就是我们需要的求和式子。
至于最大的嘛……直接找到最大的和次大的相乘比较就可以了……
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 const int mod=10007,maxn=200005; 7 struct node 8 { 9 int from,to,next; 10 }edge[maxn<<1]; 11 int head[maxn],tot,n,weight[maxn]; 12 void addedge(int u,int v) 13 { 14 edge[++tot]=(node){u,v,head[u]};head[u]=tot; 15 } 16 int haha() 17 { 18 freopen("linkb.in","r",stdin); 19 freopen("linkb.out","w",stdout); 20 scanf("%d",&n); 21 for(int i=1;i<n;i++) 22 { 23 int x,y;scanf("%d%d",&x,&y); 24 addedge(x,y);addedge(y,x); 25 } 26 for(int i=1;i<=n;i++)scanf("%d",&weight[i]); 27 int maxx=0;long long sum=0; 28 for(int i=1;i<=n;i++) 29 { 30 int firmax=0,secmax=0;long long sigma=0,pow2sigma=0; 31 for(int j=head[i];j;j=edge[j].next) 32 { 33 int v=edge[j].to; 34 if(weight[v]>firmax)secmax=firmax,firmax=weight[v]; 35 else secmax=max(secmax,weight[v]); 36 sigma=(sigma+weight[v]);pow2sigma=(pow2sigma+weight[v]*weight[v])%mod; 37 } 38 maxx=max(maxx,firmax*secmax); 39 sum=(sum+sigma*sigma-pow2sigma)%mod; 40 } 41 printf("%d %lld",maxx,sum); 42 } 43 int sb=haha(); 44 int main(){;}
只要是活着的东西,就算是神我也杀给你看。