mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-08-21 10:42:07 +00:00
update
This commit is contained in:
parent
191d5c1b12
commit
8f1e2bd8c2
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
/build
|
||||
/.cache
|
||||
/test.*
|
||||
*.in
|
||||
*.ans
|
116
src/8/9/809maze.cpp
Normal file
116
src/8/9/809maze.cpp
Normal 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
83
src/8/9/809slope.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user