题解 NOIP2014 提高组-联合权值
基本思路:以每个点为中转点,则与之相邻的点组成的点对都可产生联合权值,并且全覆盖。
主要总结一下两种求权值和的思路:
思路1(容斥):记与 \(u\) 相邻的点的集合为 \(A\),则点 \(u\) 产生的贡献为
\[ans_u=(\sum_{v \in A}w_i)^2-\sum_{v \in A}w_v \times w_v \]对于每个中转点 \(u\) ,枚举 \(v\) 的同时直接求这两个式子,循环外结算。
void dfs(int u,int f){
ll tot=0,cz=0,cmax=-1,dmax=-1;
for(auto v:g[u]){
tot+=w[v];
cz=(cz+w[v]*w[v]%mod)%mod;
if(w[v]>cmax) dmax=cmax,cmax=w[v];
else if(w[v]>dmax) dmax=w[v];
if(v!=f) dfs(v,u);
}
ans=(ans+tot*tot%mod-cz)%mod;
mx=max(dmax*cmax,mx);
}
思路2(在线统计答案):在枚举到 \(v_i\) 时,考虑先让它和 \(v_{1 \sim i-1}\) 组合,最后输出时将答案乘2即可。
void dfs(int u,int f){
ll tot=0,cmax=-1,dmax=-1;
for(auto v:g[u]){
ans=(ans+tot*w[v])%mod;
tot+=w[v];
if(w[v]>cmax) dmax=cmax,cmax=w[v];
else if(w[v]>dmax) dmax=w[v];
if(v!=f) dfs(v,u);
}
mx=max(dmax*cmax,mx);
}
- 重点记录一下思路2,没有尝试过这种思路。