Codeforces Round #525 (Div. 2)E. Ehab and a component choosing problem
E. Ehab and a component choosing problem
题目链接:https://codeforces.com/contest/1088/problem/E
题意:
给出一个数,找出k个连通块,使得连通块里面点的和除以k最大。当选择不同数量的连通块有相同的最大值时,要求输出k最大的情况。
题解:
由于这个不等式average(x1,x2,x3...xn)<=max(x1,x2,...xn)成立(当且仅当x1=x2=...xn时,等号成立),而题目所求正好是连通块里面点和的平均值。
我们要让average(x1,x2,x3...xn)最大,一是尽量满足等号成立的条件,二是尽量让连通块里面的权和最大。
由于题目中要求k尽量最大。
所以我们可以进行两次dfs,第一次找出最大的连通块,第二次看看有多少个连通块等于之前找到的最大值,并且更新k的值以及所有点的权值和。
求最大连通块的时候用到最大连续子段和的技巧,负数就舍去,当儿子为正数才更新值。
代码如下:
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #define INF 9999999999 using namespace std; const int N = 3e5+5 ; typedef long long ll; int a[N],head[N],vis[N]; int n,tot,k; struct Edge{ int u,v,next; }e[N<<1]; ll dp[N]; ll ans=-INF; void adde(int u,int v){ e[++tot].u=u;e[tot].v=v;e[tot].next=head[u];head[u]=tot; e[++tot].u=v;e[tot].v=u;e[tot].next=head[v];head[v]=tot; } void dfs(int node,int f){ dp[node]=a[node]; vis[node]=1; for(int i=head[node];i!=-1;i=e[i].next){ int v=e[i].v; if(!vis[v]){ vis[v]=1; dfs(v,f); if(dp[v]>0) dp[node]+=dp[v]; } } if(!f) ans=max(ans,dp[node]); else{ if(dp[node]==ans){ k++; dp[node]=0; } } } int main(){ scanf("%d",&n); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1,u,v;i<=n-1;i++){ scanf("%d%d",&u,&v); adde(u,v); } dfs(1,0); memset(vis,0,sizeof(vis)); dfs(1,1); cout<<ans*k<<" "<<k<<endl; return 0; }
重要的是自信,一旦有了自信,人就会赢得一切。