*P8817 题解
I_am_kunzi · · 个人记录
P8817 题解
先行吐槽:数据过水,一个重大的错误竟然得了
题目大意
给定
题目思路
下面记
首先不能四个点全枚举,不然这题还有啥意思。而且显然贪心是错的,不然这题还有啥意思。
既然边长固定为
观察数据范围可得,我们只能枚举两个点,对于剩下的两个点,我们需要用常数次枚举找到最优答案。
当然枚举两个点也足够了。我们发现,
但我们既然要枚举这两个点,就需要在常数时间内找到
那么我们都能处理出来每个点可到达的点中,可以到达
综上所述,我们需要在枚举每一组 set 动态维护。
然后就做完了。注意最好不要维护分数第四大及以后的值,因为没用,而且可能过不了。
题目代码
没啥好说的,我觉得这题不难理解。
代码缺省源这种东西自己看着来吧。
又附:一开始我把分数放到第二关键字排序,怒提
long long n , m , k;
long long sc[2505]; // score
vector < long long > v[2505];
long long dist[2505][2505];
void bfs(int st)
{
vector < bool > vis(n + 1 , 0);
queue < pair < long long , long long > > q;
q.push(make_pair(st , 0));
while(q.size())
{
pair < long long , long long > a = q.front();
q.pop();
if(vis[a.first])
{
continue;
}
vis[a.first] = 1;
dist[st][a.first] = a.second;
for(int i : v[a.first])
{
q.push(make_pair(i , a.second + 1));
}
}
}
set < pair < long long , long long > > max_get[2505]; // 每个点能到的点中,能回到 1 的点的最大点权
signed main()
{
read(n , m , k);
sc[1] = -LONG_LONG_MAX;
for(int i = 2 ; i <= n ; i++)
{
read(sc[i]);
}
for(int i = 1 ; i <= m ; i++)
{
int x , y;
read(x , y);
v[x].push_back(y);
v[y].push_back(x);
}
memset(dist , 0x3f , sizeof(dist));
for(int i = 1 ; i <= n ; i++)
{
bfs(i);
}
for(int i = 1 ; i <= n ; i++)
{
for(int j = 1 ; j <= n ; j++)
{
if(dist[j][1] <= k + 1 && dist[i][j] <= k + 1)
{
max_get[i].insert(make_pair(sc[j] , j));
}
if(max_get[i].size() > 3)
{
max_get[i].erase(max_get[i].begin());
}
}
}
long long ans = 0;
for(int i = 2 ; i <= n ; i++)
{
for(int j = 2 ; j <= n ; j++)
{
if(dist[i][j] > k + 1 || i == j)
{
continue;
}
for(pair < long long , long long > x : max_get[i])
{
for(pair < long long , long long > y : max_get[j])
{
int p1 = x.second , p2 = y.second;
long long s1 = x.first , s2 = y.first;
if(i == p1 || j == p1 || i == p2 || j == p2 || p1 == p2 || p1 == 1 || p2 == 1)
{
continue;
}
ans = max(ans , s1 + s2 + sc[i] + sc[j]);
}
}
}
}
printnl(ans);
return 0;
};