蓝桥杯 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\}\) 的结论。如果事先不知道,大胆去猜。

另,注意数据范围。主要关注以下方面:

  1. 适用的时间复杂度
  2. 数据是否会溢出
  3. 是否存在像 \(0\) 这样的特判点
posted @ 2026-04-13 19:47  SHUddol  阅读(1)  评论(0)    收藏  举报