http://codeforces.com/contest/1293/problem/E
On another floor of the A.R.C. Markland-N, the young man Simon “Xenon” Jackson, takes a break after finishing his project early (as always). Having a lot of free time, he decides to put on his legendary hacker “X” instinct and fight against the gangs of the cyber world.
His target is a network of n small gangs. This network contains exactly n−1 direct links, each of them connecting two gangs together. The links are placed in such a way that every pair of gangs is connected through a sequence of direct links.
By mining data, Xenon figured out that the gangs used a form of cross-encryption to avoid being busted: every link was assigned an integer from 0 to n−2 such that all assigned integers are distinct and every integer was assigned to some link. If an intruder tries to access the encrypted data, they will have to surpass S password layers, with S being defined by the following formula:
S=∑1≤u<v≤nmex(u,v)
Here, mex(u,v) denotes the smallest non-negative integer that does not appear on any link on the unique simple path from gang u to gang v.
Xenon doesn’t know the way the integers are assigned, but it’s not a problem. He decides to let his AI’s instances try all the passwords on his behalf, but before that, he needs to know the maximum possible value of S, so that the AIs can be deployed efficiently.
Now, Xenon is out to write the AI scripts, and he is expected to finish them in two hours. Can you find the maximum possible S before he returns?
思路:首先,如果一条边的权值为0,那么所有经过这条边的路径权值都会加1,如果再将其相邻的一条边的权值赋为1,则所有经过这0,1两条边的路径权值都会再加上1,而其他路径不会有贡献,即只有连续的一条链有贡献(链的赋值为0,1,…,x)
现可以枚举所有链,设这条链为u,u1,…,v1,v,设长度为x,每条边的赋值有0,1,…,x-1,经过整条链增加的贡献很容易算出来,现考虑将链长缩短,有两种方式,即x-1赋给边(u,u1)或者(v,v1),对这两种赋值方法的贡献取max即可,可以每次将结果记录下来,复杂度为O(
n
2
n^2
n2)
#include<bits/stdc++.h>
#define ll long long
#define MAXN 3005
using namespace std;
ll dp[MAXN][MAXN],sz[MAXN][MAXN];
int fa[MAXN][MAXN],head[MAXN],tot;
struct edge
{
int v,nxt;
}edg[MAXN << 1];
inline void addedg(int u,int v)
{
edg[tot].v = v;
edg[tot].nxt = head[u];
head[u] = tot++;
}
int n,rt;
inline void dfs(int u,int f)
{
int v;
sz[rt][u] = 1;
fa[rt][u] = f;
for(int i = head[u];i != -1;i = edg[i].nxt)
{
v = edg[i].v;
if(v != f)
{
dfs(v,u);
sz[rt][u] += sz[rt][v];
}
}
}
inline ll solve(int u,int v)
{
if(dp[u][v] != -1) return dp[u][v];
if(u == v) return 0;
return dp[u][v] = sz[u][v] * sz[v][u] + max(solve(u,fa[u][v]),solve(v,fa[v][u]));
}
inline void init()
{
tot = 0;
memset(head,-1,sizeof(head));
memset(dp,-1,sizeof(dp));
}
int main()
{
while(~scanf("%d",&n))
{
init();
int u,v;
for(int i = 1;i < n;++i)
{
scanf("%d%d",&u,&v);
addedg(u,v);
addedg(v,u);
}
for(int i = 1;i <= n;++i)
rt = i,dfs(i,i);
ll ans = 0;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= n;++j)
ans = max(ans,solve(i,j));
printf("%lld\n",ans);
}
return 0;
}