题解:洛谷 AT_abc466_c Count Close Pairs
【题目来源】
洛谷:AT_abc466_c [ABC466C] Count Close Pairs
【题目描述】
本题是一道 交互式问题(你编写的程序与评测程序通过标准输入输出进行交互的问题)。
在数轴上,点 \(1\) , \(2\) , \(\ldots\) , \(N\) 按此顺序 从左到右排列。
最初,你只会得到整数 \(N\)。
之后,你可以向评测程序进行最多 \({2N}\) 次以下提问:
- 选择满足 \(1 \leq i < j \leq N\) 的整数 \(i,j\) ,询问点 \(i\) 和点 \(j\) 之间的距离是否不超过 \(1\)。
请输出距离不超过 \(1\) 的点对数量,即满足 \(1\leq i<j\leq N\) 且点 \(i\) 和点 \(j\) 之间的距离不超过 \(1\) 的整数对 \((i,j)\) 的数量。
【输入输出】
首先,从标准输入接收表示点数的整数 \(N\)。
\(N\)
接着,你可以向评测程序重复提问,最多 \(2N\) 次。
提问请按以下格式输出到标准输出。其中, \(i,j\) 必须是满足 \(1 \leq i<j \leq N\) 的整数。
? \(i\) \(j\)
作为对此提问的响应,标准输入会给出以下两种回复之一:
Yes
No
其中,Yes 表示点 \(i\) 和点 \(j\) 之间的距离不超过 \(1\),No 表示点 \(i\) 和点 \(j\) 之间的距离大于 \(1\)。
当得出问题的答案 \(X\) 后,请按以下格式输出答案。随后,请立即结束程序。
! \(X\)
【核心思想】
-
问题分析:数轴上有 \(N\) 个按顺序排列的点,具体坐标未知。通过最多 \(2N\) 次交互询问判断点对 \((i,j)\) 距离是否 \(\leq 1\),求满足条件的点对总数。这是一个交互式双指针问题,核心在于利用距离单调性,通过双指针扫描高效统计满足条件的点对,同时严格控制询问次数在 \(2N\) 以内。
-
算法选择:
- 双指针(Two Pointers):维护区间 \([l, r]\),利用单调性——若 \((l, r)\) 距离 \(> 1\),则对于固定 \(l\),所有 \(r' > r\) 的距离也 \(> 1\);若 \((l, r)\) 距离 \(\leq 1\),则 \(r\) 可以右移扩大区间
- 交互式贪心:每次询问后根据回答调整指针,确保每个点作为左端点或右端点最多被询问 \(2\) 次
-
关键步骤:
- 初始化:\(l \leftarrow 1\),\(r \leftarrow 2\),\(ans \leftarrow 0\)
- 双指针扫描(\(r \leq N\)):
- 询问 \((l, r)\) 的距离是否 \(\leq 1\)
- 若回答
No(距离 \(> 1\)):- 区间 \([l, r-1]\) 内所有点与 \(l\) 的距离均 \(\leq 1\),累加 \(ans \leftarrow ans + (r - l - 1)\)
- \(l \leftarrow l + 1\)(左端点右移)
- 若 \(l = r\),则 \(r \leftarrow r + 1\)
- 若回答
Yes(距离 \(\leq 1\)):- \(r \leftarrow r + 1\)(右端点右移)
- 处理剩余区间:当 \(r > N\) 时,区间 \([l, N]\) 内所有点对距离均 \(\leq 1\),累加 \(ans \leftarrow ans + \sum_{i=l}^{N-1} (N - i)\)
- 输出答案:
! ans
-
时间/空间复杂度:
- 时间复杂度:\(O(N)\),双指针过程中 \(l\) 和 \(r\) 均最多移动 \(N\) 次
- 空间复杂度:\(O(1)\),仅使用常数额外空间
- 询问次数:最多 \(2N\) 次,满足题目限制
-
双指针与交互式策略的核心思想:
- 单调性利用:点按顺序排列,若 \((l, r)\) 距离 \(> 1\),则对于固定 \(l\),所有 \(r' > r\) 的距离也必然 \(> 1\)。因此一旦得到
No,即可确定以 \(l\) 为左端点的所有有效点对都在 \([l, r-1]\) 内 - 指针移动的不变性:维护区间 \([l, r]\) 满足——\(l\) 与 \([l, r-1]\) 内所有点距离均 \(\leq 1\),而 \(l\) 与 \(r\) 的距离 \(> 1\)(或 \(r > N\))。每次
No时可一次性统计 \(l\) 的所有有效点对 - 询问次数控制:每个点最多作为左端点被询问 \(1\) 次(\(l\) 右移时),最多作为右端点被询问 \(1\) 次(\(r\) 右移时),总计不超过 \(2N\) 次
- 剩余区间公式化:当 \(r\) 超出范围后,\([l, N]\) 内所有点对距离均 \(\leq 1\),直接通过公式计算,无需额外询问
- 适用于有序序列上的区间统计、交互式信息获取类问题
- 单调性利用:点按顺序排列,若 \((l, r)\) 距离 \(> 1\),则对于固定 \(l\),所有 \(r' > r\) 的距离也必然 \(> 1\)。因此一旦得到
【算法标签】
普及 #双指针
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n; // n: 数轴上的点数
int l = 1, r = 2; // l: 当前区间的左端点; r: 当前区间的右端点
int ans; // ans: 距离不超过 1 的点对数量
string s; // s: 评测程序的回复("Yes" 或 "No")
int main()
{
cin >> n; // 读入点数 N
while (r <= n) // 双指针扫描所有可能的点对
{
cout << "? " << l << " " << r << endl; // 询问点 l 和点 r 的距离是否不超过 1
cin >> s; // 读入评测程序的回复
if (s == "No") // 如果距离超过 1
{
ans += r - l - 1; // 区间 [l, r) 内的所有点与 l 的距离都不超过 1,累加这些点对
l++; // 左端点右移,缩小当前区间
if (l == r) // 如果左右端点重合
++r; // 右端点右移,扩大区间
}
else // 如果距离不超过 1
++r; // 右端点右移,扩大当前区间
}
for (int i = l; i < n; i++) // 处理剩余区间内的点对
ans += n - i; // 累加从 i 出发到 n 的所有点对
cout << "! " << ans << endl; // 输出最终答案
return 0;
}
浙公网安备 33010602011771号