This commit is contained in:
Zengtudor 2025-08-09 12:27:50 +08:00
parent 191d5c1b12
commit 8f1e2bd8c2
3 changed files with 202 additions and 1 deletions

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
/build /build
/.cache /.cache
/test.* /test.*
*.in
*.ans

116
src/8/9/809maze.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <iostream>
#include <vector>
#include <algorithm>
// OI/ACM风格常用宏定义和快读
#define FAST_IO std::ios_base::sync_with_stdio(false); std::cin.tie(NULL);
#define FOR(i, start, end) for (int i = (start); i < (end); ++i)
// 为了代码简洁使用pair表示坐标
using pii = std::pair<int, int>;
int T, n, m;
std::vector<std::vector<int>> a;
std::vector<pii> pos; // pos[v] = {row, col} 存储稀有度为v的坐标
// 检查是否存在一条路径其开心程度至少为k
// 即,是否存在一条路径,收集了所有稀有度 < k 的宝物
bool check(int k) {
if (k == 0) { // 开心值为0总是可以达成的除非n=m=1且a[0][0]=0但题目定义d=1
return true;
}
if (k > n * m) { // 不可能达成比n*m还大的开心值
return false;
}
std::vector<pii> must_visit;
// 收集所有必须访问的点的坐标(稀有度 0, 1, ..., k-1
for (int i = 0; i < k; ++i) {
must_visit.push_back(pos[i]);
}
// 检查起点(0,0)是否在必须访问的列表中
// 如果a[0][0]的稀有度 >= k则 (0,0) 不在must_visit中需要手动加入
if (a[0][0] >= k) {
must_visit.push_back({0, 0});
}
// 同样,检查终点(n-1,m-1)
if (a[n - 1][m - 1] >= k) {
must_visit.push_back({n - 1, m - 1});
}
// 按照坐标排序:行优先,列其次
// 这是路径在网格中前进的自然顺序
std::sort(must_visit.begin(), must_visit.end());
// 移除因重复添加(0,0)或(n-1,m-1)而产生的重复点
must_visit.erase(std::unique(must_visit.begin(), must_visit.end()), must_visit.end());
// 检查排序后的点集是否构成一个合法的路径片段序列
// 即 p_i 的坐标必须不大于 p_{i+1} 的坐标
for (size_t i = 0; i + 1 < must_visit.size(); ++i) {
pii current = must_visit[i];
pii next = must_visit[i + 1];
if (current.first > next.first || current.second > next.second) {
// 如果后一个点的行或列小于前一个点,则无法从 current 到达 next
return false;
}
}
// 还需要确保路径的起点和终点是(0,0)和(n-1,m-1)
if (must_visit.empty() || must_visit.front() != pii{0, 0} || must_visit.back() != pii{n - 1, m - 1}) {
// 如果排序后,起点不是(0,0)或终点不是(n-1,m-1),则路径不完整
return false;
}
return true;
}
void solve() {
std::cin >> n >> m;
a.assign(n, std::vector<int>(m));
pos.assign(n * m, {0, 0});
// 读入数据并预处理pos数组
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
std::cin >> a[i][j];
pos[a[i][j]] = {i, j};
}
}
// 二分搜索答案
int low = 0, high = n * m, ans = 0;
while (low <= high) {
int mid = low + (high - low) / 2;
if (check(mid)) {
// 如果check(mid)成功说明开心程度mid是可以达到的
// 我们尝试寻求更高的开心程度
ans = mid;
low = mid + 1;
} else {
// 如果check(mid)失败说明开心程度mid无法达到
// 必须降低目标
high = mid - 1;
}
}
std::cout << ans << "\n";
}
int main() {
// 题目输入为文件,实际比赛中需要取消注释
// freopen("maze.in", "r", stdin);
// freopen("maze.out", "w", stdout);
FAST_IO;
std::cin >> T;
while (T--) {
solve();
}
return 0;
}

83
src/8/9/809slope.cpp Normal file
View File

@ -0,0 +1,83 @@
#include <iostream>
#include <vector>
#include <algorithm>
#include <iomanip>
struct Point {
long long x, y;
};
int N, K;
std::vector<Point> points;
// 判定函数:使用 O(N^2) DP 检查是否存在长度至少为 K 的子序列,
// 使得任意两点斜率不小于 C
bool check(double C) {
// 1. 计算每个点的转换值 z[i] = y[i] - C * x[i]
std::vector<double> z(N);
for (int i = 0; i < N; ++i) {
z[i] = static_cast<double>(points[i].y) - C * static_cast<double>(points[i].x);
}
// 2. O(N^2) DP 求解最长非递减子序列 (LNDS)
std::vector<int> dp(N);
int max_len = 0; // 记录 LNDS 的全局最大长度
for (int i = 0; i < N; ++i) {
dp[i] = 1; // 初始化 dp[i] = 1
for (int j = 0; j < i; ++j) {
if (z[j] <= z[i]) {
dp[i] = std::max(dp[i], dp[j] + 1);
}
}
max_len = std::max(max_len, dp[i]);
}
// 3. 判断最长长度是否满足要求
return max_len >= K;
}
int main() {
// 开启快速 I/O
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
// --- 【关键修正】 ---
// 从输入中直接读取 N 和 K
std::cin >> N >> K;
points.resize(N);
for (int i = 0; i < N; ++i) {
std::cin >> points[i].x >> points[i].y;
}
// 如果 K=1问题没有意义选任意一个点都行斜率可以认为是无穷大。
// 但题目要求选 "不同" 的两个点,所以 K 至少为 2。
// 如果 K<2直接退出或按题意处理。这里我们假设 K>=2。
if (K < 2) {
// 根据题目具体要求处理,这里简单退出
return 0;
}
// 二分答案的范围
double low = -2e9, high = 2e9;
// 进行足够多次数的二分以保证精度
for (int iter = 0; iter < 100; ++iter) {
// --- 【写法优化】 ---
// 使用更稳健的 mid 计算方式
double mid = low + (high - low) / 2.0;
if (check(mid)) {
// mid 可行,答案可能更大,尝试提高下界
low = mid;
} else {
// mid 不可行,答案必须更小,降低上界
high = mid;
}
}
// 输出结果,设置精度
std::cout << std::fixed << std::setprecision(10) << low << std::endl;
return 0;
}