• 换根dp+暴力+预处理+记忆化搜索——cf1292C好题!


    /**
    给定一棵树,要求给树边赋值[0,n-2],每个值只能使用一次
        S = mex(u,v), mex(u,v)是u-v路径上没有出现过的编号最小的值
        问使得S最大的赋值方式 
        
    由于很难直接统计答案,所以考虑统计每条边的贡献 
        包含(0)路径的贡献tot1是其左右子树size的乘积 
        包含(0,1)的路径的贡献tot2是其左右子树的size乘积 
        ...依次类推
        显然:只包含(1,2)这样的路径是没有贡献的
    
    那么原问题转化为如何分配[0,n-2],使得最后的乘积和最大
    dp[u][v]表示路径(u,v)的贡献 ,O(n^2)的时间内求完即可
        显然root不同,答案也会不同,所以先预处理出
            size[root][u],表示以root为根时u的儿子大小
             fa[root][u],表示以root为根时u的父亲
        两重循环+记忆化搜索求出所有dp[u][v]  
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define N 3005
    #define ll long long 
    
    vector<int>G[N];
    ll n,dp[N][N],size[N][N],fa[N][N];
    
    void dfs(int u,int pre,int root){
        size[root][u]=1;fa[root][u]=pre;
        for(auto v:G[u]){
            if(v==pre)continue;
            dfs(v,u,root);
            size[root][u]+=size[root][v];
        }
    }
    ll solve(int u,int v){
        if(u==v)return 0;
        if(dp[u][v]!=-1)return dp[u][v];
        dp[u][v]=size[u][v]*size[v][u]
            +max(solve(u,fa[u][v]),solve(v,fa[v][u]));
        return dp[u][v];
    }
    
    int main(){
        cin>>n;
        for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            G[u].push_back(v);
            G[v].push_back(u);
        }
        
        for(int root=1;root<=n;root++)
            dfs(root,0,root);
        
        memset(dp,-1,sizeof dp);
        ll ans=0;
        for(int u=1;u<=n;u++)
            for(int v=1;v<=n;v++)
                ans=max(ans,solve(u,v));    
        cout<<ans<<'
    ';
    } 
     
  • 相关阅读:
    Linux系统目录数和文件数限制
    用十条命令在一分钟内检查Linux服务器性能
    Linux 性能
    vmstat命令
    利用Clonezilla备份还原Linux系统 (转载别人的知识)
    性能,并发,压力--别人所写
    linux -top 命令
    Linux 随写
    接口测试
    Jmeter关联正则表达式提取器
  • 原文地址:https://www.cnblogs.com/zsben991126/p/12264140.html
Copyright © 2020-2023  润新知