1 条题解
-
0
Quark Microscopy 题解
问题分析
这是一个交互式问题,我们需要在 的大范围内找到 个夸克的位置。关键限制是:
- 只能查询第二近距离
- 查询次数影响最终得分
- 在 3 到 100 之间
核心思路
关键观察:
- 当查询点 正好在两个夸克的中点附近时,第二近距离会提供重要信息
- 通过二分搜索可以逐步缩小夸克位置的范围
- 利用多个查询点的信息可以交叉验证
算法策略
- 边界探测:先找到最左边和最右边的夸克
- 二分定位:在已知的夸克之间寻找其他夸克
- 信息整合:利用多个查询结果确定精确位置
完整代码实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define MAX_N 105 typedef long long ll; ll positions[MAX_N]; int n, t; // 交互查询函数 void query(ll x, ll *r, int *m) { printf("? %lld\n", x); fflush(stdout); scanf("%lld %d", r, m); } // 提交答案 void submit() { printf("!"); for (int i = 0; i < n; i++) { printf(" %lld", positions[i]); } printf("\n"); fflush(stdout); } // 比较函数用于排序 int compare(const void *a, const void *b) { ll x = *(ll*)a; ll y = *(ll*)b; if (x < y) return -1; if (x > y) return 1; return 0; } // 查找最左边的夸克 ll find_leftmost() { ll left = 1, right = 1000000000000000000LL; // 10^18 ll last_r = -1; int last_m = -1; while (left <= right) { ll mid = left + (right - left) / 2; ll r; int m; query(mid, &r, &m); if (r == 0) { // 找到了一个夸克 return mid; } // 如果第二近距离很小,说明附近有夸克 if (r < (right - left) / 4) { // 在左侧搜索 right = mid - 1; } else { // 在右侧搜索 left = mid + 1; } last_r = r; last_m = m; } return left; } // 查找最右边的夸克 ll find_rightmost() { ll left = 1, right = 1000000000000000000LL; while (left <= right) { ll mid = left + (right - left) / 2; ll r; int m; query(mid, &r, &m); if (r == 0) { return mid; } // 根据第二近距离判断搜索方向 if (r < (right - left) / 4) { left = mid + 1; } else { right = mid - 1; } } return right; } // 在已知的两个夸克之间寻找其他夸克 void find_quarks_between(ll left, ll right, int *found_count) { if (*found_count >= n) return; // 如果范围很小,直接查询所有点 if (right - left <= n * 2) { for (ll x = left + 1; x < right && *found_count < n; x++) { ll r; int m; query(x, &r, &m); if (r == 0) { // 找到夸克 int exists = 0; for (int i = 0; i < *found_count; i++) { if (positions[i] == x) { exists = 1; break; } } if (!exists) { positions[(*found_count)++] = x; } } } return; } // 在中间点查询 ll mid = left + (right - left) / 2; ll r; int m; query(mid, &r, &m); if (r == 0) { // 在中间点找到了夸克 int exists = 0; for (int i = 0; i < *found_count; i++) { if (positions[i] == mid) { exists = 1; break; } } if (!exists) { positions[(*found_count)++] = mid; } // 递归搜索两边 find_quarks_between(left, mid, found_count); find_quarks_between(mid, right, found_count); } else { // 根据第二近距离的信息决定搜索策略 if (m == 2) { // 有两个夸克在相同距离,说明我们在两个夸克的中点附近 // 可以推断出这两个夸克的位置 ll quark1 = mid - r; ll quark2 = mid + r; int exists1 = 0, exists2 = 0; for (int i = 0; i < *found_count; i++) { if (positions[i] == quark1) exists1 = 1; if (positions[i] == quark2) exists2 = 1; } if (!exists1 && *found_count < n) { positions[(*found_count)++] = quark1; } if (!exists2 && *found_count < n) { positions[(*found_count)++] = quark2; } // 继续搜索其他区域 find_quarks_between(left, quark1, found_count); find_quarks_between(quark2, right, found_count); } else { // m == 1,继续二分搜索 find_quarks_between(left, mid, found_count); find_quarks_between(mid, right, found_count); } } } int main() { scanf("%d %d", &n, &t); int found_count = 0; // 策略1:先找到边界夸克 printf("Searching for leftmost quark...\n"); fflush(stdout); ll leftmost = find_leftmost(); positions[found_count++] = leftmost; printf("Searching for rightmost quark...\n"); fflush(stdout); ll rightmost = find_rightmost(); // 检查rightmost是否已经找到 int rightmost_exists = 0; for (int i = 0; i < found_count; i++) { if (positions[i] == rightmost) { rightmost_exists = 1; break; } } if (!rightmost_exists && found_count < n) { positions[found_count++] = rightmost; } // 在边界之间寻找其他夸克 printf("Searching for remaining quarks...\n"); fflush(stdout); find_quarks_between(leftmost, rightmost, &found_count); // 如果还没找全,使用网格搜索 if (found_count < n) { ll step = (rightmost - leftmost) / (n - found_count + 1); for (ll x = leftmost + step; x < rightmost && found_count < n; x += step) { ll r; int m; query(x, &r, &m); if (r == 0) { int exists = 0; for (int i = 0; i < found_count; i++) { if (positions[i] == x) { exists = 1; break; } } if (!exists) { positions[found_count++] = x; } } } } // 排序并提交答案 qsort(positions, found_count, sizeof(ll), compare); submit(); return 0; }优化版本:减少查询次数
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define MAX_N 105 typedef long long ll; ll positions[MAX_N]; int n, t; int query_count = 0; void query(ll x, ll *r, int *m) { printf("? %lld\n", x); fflush(stdout); scanf("%lld %d", r, m); query_count++; } void submit() { printf("!"); for (int i = 0; i < n; i++) { printf(" %lld", positions[i]); } printf("\n"); fflush(stdout); } int compare(const void *a, const void *b) { ll x = *(ll*)a; ll y = *(ll*)b; return (x > y) - (x < y); } // 更高效的二分搜索,专门针对第二近距离设计 ll smart_binary_search(ll left, ll right, int *found) { while (left <= right && query_count < 20000) { ll mid = left + (right - left) / 2; ll r; int m; query(mid, &r, &m); if (r == 0) { *found = 1; return mid; } // 分析第二近距离的信息 if (m == 2) { // 有两个夸克在相同距离,可以精确定位 ll quark1 = mid - r; ll quark2 = mid + r; // 验证这两个位置 ll r1, r2; int m1, m2; query(quark1, &r1, &m1); if (r1 == 0) { *found = 1; return quark1; } query(quark2, &r2, &m2); if (r2 == 0) { *found = 1; return quark2; } // 如果验证失败,继续二分 left = mid + 1; } else { // 根据距离大小调整搜索范围 if (r < (right - left) / 10) { right = mid - 1; } else { left = mid + 1; } } } *found = 0; return left; } // 使用三阶段搜索策略 void three_phase_search() { int found_count = 0; // 阶段1:粗略定位边界 ll search_left = 1; ll search_right = 1000000000000000000LL; // 阶段2:逐步细化搜索 while (found_count < n && query_count < 15000) { ll current; int found; current = smart_binary_search(search_left, search_right, &found); if (found) { // 检查是否重复 int duplicate = 0; for (int i = 0; i < found_count; i++) { if (positions[i] == current) { duplicate = 1; break; } } if (!duplicate) { positions[found_count++] = current; printf("Found quark at position %lld (total: %d)\n", current, found_count); fflush(stdout); } // 调整搜索范围,避免重复找到同一个夸克 search_left = current + 1; } else { // 没有找到,扩大搜索步长 search_left = current; } if (search_left > search_right) { search_left = 1; search_right = 1000000000000000000LL; } } // 阶段3:如果还没找全,使用最后的网格搜索 if (found_count < n && query_count < 2400) { printf("Starting final grid search...\n"); fflush(stdout); // 在已知的夸克之间进行密集搜索 qsort(positions, found_count, sizeof(ll), compare); for (int i = 0; i < found_count - 1 && found_count < n; i++) { ll start = positions[i] + 1; ll end = positions[i + 1] - 1; ll step = (end - start) / 10; if (step < 1) step = 1; for (ll x = start; x <= end && found_count < n && query_count < 2400; x += step) { ll r; int m; query(x, &r, &m); if (r == 0) { int duplicate = 0; for (int j = 0; j < found_count; j++) { if (positions[j] == x) { duplicate = 1; break; } } if (!duplicate) { positions[found_count++] = x; } } } } } } int main() { scanf("%d %d", &n, &t); three_phase_search(); // 最终检查 if (query_count > 2400) { printf("Warning: Query count (%d) may affect score\n", query_count); fflush(stdout); } // 确保有n个位置 qsort(positions, n, sizeof(ll), compare); submit(); return 0; }算法核心策略
1. 二分搜索优化
ll smart_binary_search(ll left, ll right, int *found) { // 专门针对第二近距离特性设计的二分搜索 // 当 m == 2 时可以精确定位两个夸克 }2. 三阶段搜索
- 阶段1:粗略定位边界夸克
- 阶段2:智能二分搜索找到大部分夸克
- 阶段3:网格搜索填补遗漏
3. 查询优化
- 利用
m == 2的情况直接定位两个夸克 - 避免重复查询已知区域
- 动态调整搜索策略
复杂度分析
- 查询次数:目标在2400次以内获得满分
- 时间复杂度: 其中
- 空间复杂度:
注意事项
- 刷新输出:每次查询后必须
fflush(stdout) - 大整数处理:使用
long long类型 - 查询限制:监控查询次数避免超限
- 重复检测:避免重复记录同一个夸克
这个C语言实现提供了完整的交互式解决方案,通过优化的搜索策略在查询次数限制内找到所有夸克位置。
- 1
信息
- ID
- 4477
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者