1 条题解

  • 0
    @ 2026-6-19 10:31:07

    📝 题目大意

    给定 AABB,构造一个长度为 A+BA+B 的整数数列,使得其中恰好有 AA 个正整数、BB 个负整数,所有元素互不相同、非零、绝对值不超过 10910^9,且总和为 00

    💡 解题思路

    1. 题目分析

      • 数据范围 A,B1000A, B \leq 1000 很小,构造空间充裕。
      • 核心要求是总和为 00,即正数之和等于负数之和的绝对值。
      • 可以证明一定存在解,我们只需构造任意一组。
    2. 算法推导: 设 c=max(A,B)(max(A,B)+1)/2c = \max(A, B) \cdot (\max(A, B) + 1) / 2,即 11max(A,B)\max(A, B) 的等差数列和。

      核心思想:让正数部分的总和恰好为 cc,负数部分的总和恰好为 c-c,这样总和自动为 00

      • 正数部分(共 AA 个):先取 1,2,3,,A11, 2, 3, \dots, A-1A1A-1 个自然数,它们的和为 Spos=A(A1)/2S_{pos} = A(A-1)/2。最后一个正数取 cSposc - S_{pos},这样正数总和 = Spos+(cSpos)=cS_{pos} + (c - S_{pos}) = c
      • 负数部分(共 BB 个):先取 1,2,3,,(B1)-1, -2, -3, \dots, -(B-1)B1B-1 个负整数,它们的和为 Sneg=(B1)B/2S_{neg} = -(B-1)B/2。最后一个负数取 (c(Sneg))=(cB(B1)/2)-(c - (-S_{neg})) = -(c - B(B-1)/2),这样负数总和 = Sneg(cB(B1)/2)=cS_{neg} - (c - B(B-1)/2) = -c

      正确性说明

      • 所有数互不相同:正数部分全是正数,负数部分全是负数,正负之间不可能重复。正数内部,前 A1A-1 个是 1A11 \sim A-1,最后一个 cA(A1)/2c - A(A-1)/2 至少为 max(A,B)\max(A, B)(当 max(A,B)=A\max(A, B) = A 时等于 AA,当 max(A,B)=B>A\max(A, B) = B > A 时大于 BB),不会与前 A1A-1 个重复。负数部分同理。
      • 范围合规:max(A,B)1000\max(A, B) \leq 1000c1000×1001/2=500500c \leq 1000 \times 1001 / 2 = 500500,所有数绝对值远小于 10910^9
    3. 边界与细节

      • A=1A = 1 时,正数部分只有一个数 cc(因为 Spos=0S_{pos} = 0),输出 cc 即可。
      • B=1B = 1 时同理,负数部分只有一个数 c-c
      • 注意使用 long long 避免在计算 c=max(A,B)×(max(A,B)+1)/2c = \max(A,B) \times (\max(A,B)+1) / 2 时溢出(虽然 A,B1000A,B \leq 1000int 也够,但 std.cpp 采用了更安全的类型)。

    ⏱️ 复杂度分析

    • 时间复杂度O(A+B)O(A + B),需要依次输出 A+BA+B 个数。
    • 空间复杂度O(1)O(1),仅使用常数个辅助变量。

    💻 标准代码 (C++)

    #include <bits/stdc++.h>
    using namespace std;
    int main(){
        long long a, b, c;  // 使用 long long 防止中间计算溢出
        cin >> a >> b;
        
        // c = max(A, B) 的前缀和,即 1 + 2 + ... + max(A, B)
        c = max(a, b);
        c = c * (c + 1) / 2;
        
        // 输出 A 个正数:前 A-1 个是 1, 2, ..., A-1
        for(int i = 1; i <= a - 1; i++) cout << i << " ";
        // 最后一个正数 = c - (1 到 A-1 的和) = c - A*(A-1)/2,保证正数总和为 c
        cout << c - a * (a - 1) / 2 << " ";
        
        // 输出 B 个负数:前 B-1 个是 -1, -2, ..., -(B-1)
        for(int i = 1; i <= b - 1; i++) cout << -i << " ";
        // 最后一个负数 = -(c - (1 到 B-1 的和)) = -(c - B*(B-1)/2),保证负数总和为 -c
        cout << -(c - b * (b - 1) / 2) << endl;
        
        return 0;
    }
    
    • 1

    信息

    ID
    859
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者