Codeforces Global Round 23 D

D. Paths on the Tree

思考问题我们发现我们路径总是可以走到底的 而不会中途中断
而且对于每一个分叉点 也就是每个儿子至少都会有当前还剩的k/儿子数
取余剩下的我们可以分给其他点
这样我们就可以想出一个比较暴力的状态
dp[u][k]表示u节点有k条路径经过的max
我们转移的时候显然是可以考虑一个背包选一些儿子多加一条边
但是我们这里也可以直接贪心的让每个边都不加然后对比他加了一条谁增长的更多就选谁
这样肯定是合法的 而且增加的每个边都不会互相产生冲突 正确性显然
然后这里状态的数量看起来是nk的
但其实不然 k 最大是1e9
但是每次k都会被/一次
也就是最坏至多log个状态

int n,k,s[N],f[N];
vector<int>son[N];
map<int,int>dp[N];
int dfs(int u,int k){
    if(dp[u].count(k))return dp[u][k];
    int res=k*s[u];
    if(son[u].empty())return dp[u][k]=res;
    vector<int>more;
    int p=k/son[u].size(),s=k%son[u].size();
    for(auto v:son[u]){
        res+=dfs(v,p);
        if(s)more.push_back(dfs(v,p+1)-dfs(v,p));
    }
    sort(all(more),greater<>());
    for(int i=0;i<s;i++)res+=more[i];
    return dp[u][k]=res;
}
void solve(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)son[i].clear(),dp[i].clear();
    for(int i=2;i<=n;i++){
        cin>>f[i];
        son[f[i]].push_back(i);
    }
    for(int i=1;i<=n;i++){
        cin>>s[i];
    }
    cout<<dfs(1,k)<<endl;
}
posted @ 2022-11-23 02:00  ycllz  阅读(31)  评论(0)    收藏  举报