蓝桥杯 2026 省 A 读取指令 题解
Description
给定正整数 \(N, C, W\),定义序列 \(a_1, a_2, \dots, a_N\),其中 \(a_i = C \cdot i\)。 允许选取若干个互不相交的连续子序列,使得这些子序列中所有元素的和恰好等于 \(W\)。 试问满足条件的选取方式是否存在,若存在,请求出选取子序列数量的最小值 \(\text{ans}\)。
Solution
首先能注意到,如果 \(\displaystyle \ C \nmid W\),那么满足条件的选取方式不存在。既然如此,接下来默认 \(W\) 是 \(C\) 的倍数。进而只需讨论 \(C=1\) 的情形,因为 \(C\) 的取值不影响问题结构。
然后注意到,如果 \(\displaystyle W > \frac{N(1+N)}{2}\),那么满足条件的选取方式不存在。于是可只考虑 \(\displaystyle W \in \left[1, \frac{N(N+1)}{2}\right]\) 的情形。
接下来归纳证明当 \(\displaystyle W \in \left[1, \frac{N(N+1)}{2}\right]\) 时,\(\text{ans}\) 非 \(1\) 即 \(2\)。
- \(N=1\) 时,显然 \(\text{ans} \in \{1,2\}\)。
- 假设 \(N=k-1\) 时成立,下证 \(N=k\) 时成立。实则只需证对所有 \(\displaystyle W \in \left[\frac{(k-1)k}{2}+1, \frac{k(k+1)}{2}\right]\),均存在满足条件的选取方式。而这易于构造,在 \([1,k]\) 中挖去至多一个点即可,具体形式从略。
综上得证。
于是问题转化为判断 \(W\) 是否可被表示为一段连续的 \(\le N\) 的正整数之和。
这个问题可以先求前缀和转化为“两数之差”问题,然后使用双指针解决。
Details
原题 \(W\) 可能取 \(0\),故要特判。
开 long long。
Code
#include <bits/stdc++.h>
typedef long long i64;
using namespace std;
const int MAXN = 1e5;
i64 sum[MAXN + 1];
int solve() {
// 输入
i64 n, c, w;
scanf("%lld%lld%lld", &n, &c, &w);
// 特判
if (w % c)
return printf("-1\n");
if (!w)
return printf("0\n");
w /= c;
if (w > n * (n + 1) / 2)
return printf("-1\n");
// 双指针求两数之差
int l = 0, r = 1;
while (r <= n) {
if (sum[r] > sum[l] + w)
++l;
else if (sum[r] < sum[l] + w)
++r;
else
return printf("1\n");
}
return printf("2\n");
}
int main() {
// 预处理前缀和
for (int i = 1; i <= MAXN; ++i)
sum[i] = sum[i - 1] + i;
// 处理询问
int t;
scanf("%d", &t);
while (t--) solve();
return 0;
}
Reflection
本题卡点在于是否知道 \(\text{ans} \in \{1,2\}\) 的结论。如果事先不知道,大胆去猜。
另,注意数据范围。主要关注以下方面:
- 适用的时间复杂度
- 数据是否会溢出
- 是否存在像 \(0\) 这样的特判点

浙公网安备 33010602011771号