题解:洛谷 P4956 Davor

【题目来源】

洛谷:P4956 [COCI 2017/2018 #6] Davor - 洛谷

【题目描述】

在征服南极之后,Davor 开始了一项新的挑战。下一步是在西伯利亚、格林兰、挪威的北极圈远征。他将在 \(2018\)\(12\)\(31\) 日开始出发,在这之前需要一共筹集 \(n\) 元钱。他打算在每个星期一筹集 \(x\) 元,星期二筹集 \(x+k\) 元,……,星期日筹集 \(x+6k\) 元,并连续筹集 \(52\) 个星期。其中 \(x,k\) 为正整数,并且满足 \(1\le x\le 100\)

现在请你帮忙计算 \(x,k\) 为多少时,能刚好筹集 \(n\) 元。

如果有多个答案,输出 \(x\) 尽可能大,\(k\) 尽可能小的。注意 \(k\) 必须大于 \(0\)

【输入】

The first line of input contains the integer \(N(1456\le N\le 145600)\), the number from the task.

【输出】

The first line of output must contain the value of \(X(0\lt x\le 100)\), and the second the value of \(K(K\gt 0)\).

【输入样例】

1456

【输出样例】

1
1

【核心思想】

  1. 问题分析:Davor 需要在 52 周内筹集 \(n\) 元,每周一到周日每天筹集的金额分别为 \(x, x+k, \dots, x+6k\)。其中 \(x\)\(1 \le x \le 100\))和 \(k\)(正整数)为未知数。需要找到一组 \((x, k)\),使得 52 周的总筹集金额恰好等于 \(n\)。若有多个解,选择 \(x\) 最大、\(k\) 最小的那组。本质是基于等差数列求和公式的整数方程求解

  2. 算法选择

    • 数学推导 + 枚举:首先推导每周筹集金额为 \(7x + 21k\),52 周总金额为 \(52(7x + 21k) = n\)。等式两边除以 52 得 \(7x + 21k = n/52\)。因此 \(n\) 必须能被 52 整除。令 \(M = n / 52\),则 \(7x + 21k = M\),即 \(x + 3k = M/7\),所以 \(M\) 必须能被 7 整除。最终可令 \(T = n / (52 \times 7)\),则 \(x + 3k = T\)
    • 枚举 \(x\)(优先保证 \(x\) 最大):由 \(x + 3k = T\)\(k = (T - x) / 3\)。因为要优先使 \(x\) 最大,所以从 \(x = \min(100, T-3)\) 向下枚举,找到第一个使 \((T - x)\) 能被 3 整除且 \(k > 0\)\(x\) 即可。
  3. 关键步骤

    • 读入与整除性检查:读入 \(n\),若 \(n\) 不能被 \(52 \times 7 = 364\) 整除,则无解(但题目保证有解)。计算 \(T = n / 364\),即 \(x + 3k = T\)
    • 枚举 \(x\)\(x\) 的范围是 \(1 \le x \le 100\),且 \(x < T\)(因为 \(k > 0\))。从 \(x = \min(100, T-3)\) 开始向下递减枚举:
      • \((T - x) \% 3 == 0\),则 \(k = (T - x) / 3\),且 \(k > 0\),满足条件。
      • 输出 \(x\)\(k\) 并结束。
    • 输出:先输出 \(x\),再输出 \(k\),各占一行。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(100)\),枚举 \(x\) 最多 100 次,常数级。
    • 空间复杂度:\(O(1)\)
  5. 数学化简与枚举

    • 总和公式:一周总额为 \(\sum_{i=0}^{6} (x + i k) = 7x + 21k\)。52 周总额为 \(52(7x + 21k) = n\)。除以 \(52\)\(7x + 21k = n/52\),再除以 7 得 \(x + 3k = n/364\)。因此 \(n\) 必须为 364 的倍数。
    • 贪心策略:由于要求 \(x\) 尽可能大、\(k\) 尽可能小,而 \(x + 3k\) 为定值,\(x\) 最大时 \(k\) 自然最小。所以从 \(x\) 的上界向下枚举,找到的第一个可行解即为最优解。
    • 边界处理\(x\) 最大不能超过 100,且必须保证 \(T - x \ge 3\)(因为 \(k \ge 1\)),所以枚举起点为 \(\min(100, T-3)\)
    • 适用场景:适用于具有线性约束的整数变量枚举问题,核心是通过数学推导减少变量,再按优先级枚举。

【算法标签】

普及- #模拟

【代码详解】

#include <bits/stdc++.h>  // 包含标准库头文件(万能头文件)
using namespace std;      // 使用标准命名空间

/**
 * 主函数 - 程序入口
 * @return 程序执行状态码(0表示成功)
 */
int main()
{
    int n, x, k, ans;    // 定义变量:总金额n,钢笔单价x,圆珠笔数量k,结果ans

    cin >> n;            // 输入总金额

    // 方法一(已被注释掉):
    // 数学方法计算钢笔和圆珠笔的数量
    // n /= 52;
    // n /= 7;  // n = x + 3k
    // x = n - 3;
    // if (x > 100) x = 100;
    // for (int i = x; i >= 0; i--) {
    //     if ((n - i) % 3 == 0) {
    //         cout << i << endl << (n - i) / 3;
    //         break;
    //     }
    // }

    // 方法二:
    n /= 52;             // 计算总购买数量(钢笔+圆珠笔)

    // 从最大可能的钢笔数量开始遍历(100支)
    for (x = 100; x >= 0; x--)
    {
        // 检查剩余金额是否能购买整数数量的圆珠笔
        if ((n - x * 7) % 21 == 0 && (n - x * 7) > 0)
        {
            // 输出钢笔数量和圆珠笔数量
            cout << x << endl << (n - x * 7) / 21;
            break;
        }
    }

    return 0;            // 程序正常结束
}

【运行结果】

1456
1
1
posted @ 2026-08-30 09:18  团爸讲算法  阅读(13)  评论(0)    收藏  举报