Codeforces Round #525 (Div. 2)后俩题
E:https://codeforces.com/contest/1088/problem/E
dp+贪心
题目大意:选择一个k并且选择k个连通块,
要求sigma a[i]/k最大,k尽量大,
对于给定的一颗树,输出最大的分数,不用约分的形式。
题目意思需要进一步解析,
假定有一个最大的连通块,那么
根据贪心的思想,肯定是选择这个连通块,但
又要求k大,所以把所有大小为这个连通块的dp值都计数一遍,
因为我们知道两个最大的连通块不可能有交集,
如果有,肯定是交集部分就是最大值部分,其余的部分都是零,
那么我们从下往上递归求解的过程中,其实也是一种贪心选取,
在计数完当前位置的dp值后,把该位置置为无穷小防止后面再被选取。
#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int M=3e5+5; const ll INF=1e18; ll ans,cnt,dp[M],a[M]; vector<int>g[M]; void dfs(int u,int f,int sign){ dp[u]=a[u]; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v==f) continue; dfs(v,u,sign); dp[u]+=max(0ll,dp[v]); } if(sign==1){ ans=max(ans,dp[u]); } else if(dp[u]==ans) cnt++,dp[u]=-INF; } int main(){ int n; ans=-INF; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); for(int u,v, i=1;i<n;i++){ scanf("%d%d",&u,&v); g[u].pb(v); g[v].pb(u); } dfs(1,0,1); dfs(1,0,0); printf("%I64d %I64d",cnt*ans,cnt); return 0; }
F:https://codeforces.com/contest/1088/problem/F
题意:给你n个点的权值ai,一棵树,定义dist(a,b)为这棵树上两点的距离,且除了唯一的一个权值最小的点,每个点都必有一个相邻点权值比其小,要你构造一颗新的树,
规定每加一条边u<-->v,w就加au+av+log2( dist(u,v) )* min( au , av )。求出最小的w。
给出的树仅代表他们之间的距离!!!
分析:
类似于MST的做法,考虑每次加入一个点i,贡献为ai+aj*(1+log2(距离))。最小化aj*(log2(距离))
题目有给保证这棵树除了最小值节点,其他节点均存在一条邻边,使得边的另一点的值比它小
所以以最小的点为根向下dfs,维护每个点2^k级祖先,存在这样一个性质:每个点的所属边必然只可能连向它的某个2^k级祖先或者根节点。
因为要在这个点log2(距离)相同的情况下要尽量小
#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int M=5e5+5; const ll INF=1e18; vector<int>g[M]; int root,a[M],dp[21][M]; ll ans; void dfs(int u,int f){ dp[0][u]=f; for(int i=1;i<20;i++){ if(dp[i-1][u]==-1) break; dp[i][u]=dp[i-1][dp[i-1][u]]; } ll deep; ll minn=INF; for(deep=0;deep<20&&dp[deep][u]!=-1;deep++){ minn=min(minn,(deep+1)*a[dp[deep][u]]+a[u]); } minn=min(minn,(deep+1)*a[root]+a[u]); if(f!=-1) ans+=minn; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(v!=f) dfs(v,u); } } int main(){ int n; root=1; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]<a[root]) root=i; } for(int u,v,i=1;i<n;i++){ scanf("%d%d",&u,&v); g[u].pb(v); g[v].pb(u); } memset(dp,-1,sizeof(dp)); dfs(root,-1); printf("%I64d\n",ans); return 0; }