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;
}
View Code

 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;
}
View Code

 

posted @ 2019-11-06 14:26  starve_to_death  阅读(144)  评论(0编辑  收藏  举报