Xenon's Attack on the Gangs Codeforces Round #614 (Div. 2)

Xenon’s Attack on the Gangs
题意: 给你一棵树,将0~n-2一一赋值给n-1条边,则S最大可能取值
S = ∑ 1 ≤ u < v ≤ n m e x ( u , v ) S=\sum_{1\le u< v\le n}mex(u,v) S=1u<vnmex(u,v)
mex(u,v)表示u到v的路径中未出现的最小非负数
思路: 这里推荐一个视频题解,个人觉得讲得非常好 qscqesze
S = ∑ 1 ≤ u < v ≤ n m e x ( u , v ) = ∑ 1 ≤ x ≤ n ( ∑ m e x ( u , v ) = x x ) = ∑ 1 ≤ x ≤ n ( ∑ m e x ( u , v ) ≥ x 1 ) S=\sum_{1\le u< v\le n}mex(u,v)=\sum_{1\le x\le n}(\sum_{mex(u,v)=x}x)=\sum_{1\le x \le n}(\sum_{mex(u,v)\ge x}1) S=1u<vnmex(u,v)=1xn(mex(u,v)=xx)=1xn(mex(u,v)x1)
所以我们只需要考虑每条边的贡献即可,每条边要有贡献。
首先我们可以看0所在的边的两个端点u,v,则0的贡献为size[v][u]*size[u][v],接着看1,我们发现只有将0,1连接在一起贡献才会尽可能的大,所以我们要使得[0,m]分布在一条链上。所以我们可以对这棵树进行dp,dp[u][v]表示以u,v为端点的链

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=3e3+5;

vector<int>G[N];
int fa[N][N],sz[N][N];
ll dp[N][N],ans;

void dfs(int u,int f,int root){
    sz[root][u]=1;
    fa[root][u]=f;
    for(auto v: G[u]){
        if(v==f)
            continue;
        dfs(v,u,root);
        sz[root][u]+=sz[root][v];
    }
}

ll sl(int x,int y){
    if(x==y)
        return 0;
    if(dp[x][y]!=-1)
        return dp[x][y];
    dp[x][y]=1ll*sz[y][x]*sz[x][y]+max(sl(fa[y][x],y),sl(x,fa[x][y]));
    return dp[x][y];
}

int main(){
#ifdef Mizp
    freopen("in.txt","r",stdin);
#endif
    std::ios::sync_with_stdio(0);
    int n;
    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 i=1;i<=n;i++){
        dfs(i,0,i);
    }
    memset(dp,-1,sizeof dp);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            ans=max(ans,sl(i,j));
        }
    }
    cout<<ans<<endl;
    return 0;
}

你可能感兴趣的:(codeforces,DP)