P8817 [CSP-S 2022] 假期计划 解题笔记

给一个不用dp的做法

solution

考虑朴素做法。

预处理出 \(f(x)\),表示距离 \(x\) 不超过 \(k\) 的点。

枚举每个景点 \(a\), \(b\), \(c\), \(d\),通过预处理出的 \(f(x)\) 计算是否合法,更新答案。

这样时间复杂度是 \(O(n ^ 4)\) 的,不能通过本题。

考虑优化。

发现 \(a\)\(d\) 比较特殊,只有距离 \(1\)\(k\) 以内的点才有资格当高贵的点 \(a\) 和点 \(b\)

而不是所有点与 \(1\) 的距离都小于 \(k\)

于是改进一下预处理,新定义 \(f(x)\) 表示与点 \(x\) 的距离不超过 \(k\) 且与 \(1\) 的距离也不超过 \(k\) 的点。

注意到我们选择 \(f(x)\) 是选择最大的 \(f(x)\) 对之后的答案一定没有影响,所以选定 \(a\)\(d\) 时可以使用贪心策略,所以处理 \(f(x)\) 时只用保存最大的 \(f(x)\)

如果最大的 \(f(x)\)\(c\) 重合或与 \(b\) 重合怎么办?

考虑最坏情况,前二大的 \(f(x)\) 都与 \(c\) 重合或与 \(b\) 重合,那么我们可以保存前三大的 \(f(x)\),这样即使是最坏情况,也能选出 \(a\)\(d\)

所以总体思路就出来了,暴力枚举 \(b\)\(c\),通过预处理出的 \(f(x)\) 计算 \(a\)\(d\)

预处理复杂度 \(O(n ^ 2)\),枚举 \(b\)\(c\) 的复杂度 \(O(n ^ 2)\),计算 \(a\)\(d\) 的复杂度 \(O(1)\),总时间复杂度为 \(O(n ^ 2)\),足以通过本题。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int QWQ = 2505;
int n, m, k, a[QWQ], dis[QWQ];
int maxx = -2e18;
bool can[QWQ][QWQ];
vector<int> ve[QWQ];
vector<int> qwq[QWQ];
void bfs(int start)
{
	memset(dis, -1, sizeof(dis));
	queue<int> q;
	q.push(start);
	dis[start] = 0;

	while (!q.empty())
	{
		int u = q.front();
		q.pop();

		if (dis[u] > k + 1)
			continue;

		can[start][u] = true;

		for (int i = 0; i < ve[u].size(); i++)
		{
			int to = ve[u][i];
			if (dis[to] == -1)
			{
				dis[to] = dis[u] + 1;
				q.push(to);
			}
		}
	}
}
bool cmp(int x, int y)
{
	return a[x] > a[y];
}
signed main()
{
	cin >> n >> m >> k;
	for (int i = 2; i <= n; i++)
	{
		cin >> a[i];
	}
	for (int i = 1; i <= m; i++)
	{
		int u, v;
		cin >> u >> v;
		ve[u].push_back(v);
		ve[v].push_back(u);
	}
	memset(can, false, sizeof(can));
	for (int i = 1; i <= n; i++)
	{
		bfs(i);
	}
	for (int i = 2; i <= n; i++)
	{
		for (int j = 2; j <= n; j++)
		{
			if (i == j)
				continue;
			if (can[1][j] && can[j][i])
			{
				qwq[i].push_back(j);
			}
		}
		sort(qwq[i].begin(), qwq[i].end(), cmp);
		if (qwq[i].size() > 3)
		{
			qwq[i].resize(3);
		}
	}
	for (int b = 2; b <= n; b++)
	{
		for (int c = 2; c <= n; c++)
		{
			if (b == c || !can[b][c])
				continue;
			for (int i = 0; i < qwq[b].size(); i++)
			{
				int aa = qwq[b][i];
				if (aa == b || aa == c)
					continue;

				for (int qaq = 0; qaq < qwq[c].size(); qaq++)
				{
					int dd = qwq[c][qaq];
					if (dd == aa || dd == b || dd == c)
						continue;
					if (can[1][aa] && can[aa][b] && can[b][c] && can[c][dd] && can[dd][1])
					{
						int total = a[aa] + a[b] + a[c] + a[dd];
						maxx = max(maxx, total);
					}
				}
			}
		}
	}
	cout << maxx << endl;
}
posted @ 2025-10-19 15:40  FurinaQWQ  阅读(14)  评论(0)    收藏  举报