三连击(升级版)

GitHub跳转原题关系图返回列表

枚举比例倍数生成三个三位数,再检查拼接后的 9 个数字是否恰好是 1 到 9。

OJ: luogu

题目 ID: P1618

难度:入门

标签:枚举字符串python

日期: 2026-07-15 21:30

题意

把数字 1..9 分成三组,组成三个三位数。要求这三个三位数的比例为 A:B:C,按第一个数升序输出所有方案。无解输出 No!!!

思路

如果三个数比例为 A:B:C,它们一定可以写成:

text
A * times, B * times, C * times

因此可以枚举倍数 times。为了让第一个数和第三个数都是三位数,倍数范围可以压缩为:

text
ceil(100 / A) .. floor(999 / C)

对每个倍数,拼接三个数的十进制表示。如果拼接后长度为 9,并且数字集合正好是 {1,2,...,9},说明每个数字恰好出现一次且没有 0

A = 0 时,第一个数只能是 0,不可能是三位数,所以直接无解。

Python 知识

  • f"{x}{y}{z}" 可以把三个整数拼接成一个字符串。
  • set(digits) == set("123456789") 用集合检查是否只包含 1..9
  • 同时检查 len(digits) == 9,可以排除重复数字导致集合相同但长度不对的情况。
  • (100 + a - 1) // a 是整数上取整写法。

参考笔记:

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/math_tools.md
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/collections_toolkit.md

代码

python
a, b, c = map(int, input().split())

answers = []

if a != 0:
    left = (100 + a - 1) // a
    right = 999 // c

    for times in range(left, right + 1):
        x = a * times
        y = b * times
        z = c * times
        digits = f"{x}{y}{z}"
        if len(digits) == 9 and set(digits) == set("123456789"):
            answers.append((x, y, z))

if answers:
    for answer in answers:
        print(*answer)
else:
    print("No!!!")
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */
#include <bits/stdc++.h>
using namespace std;

int a, b, c;

int main() {
    cin >> a >> b >> c;
    if (a == 0) { cout << "No!!!" << endl; return 0; }
    bool found = false;
    int left = (100 + a - 1) / a;   // 上取整, 保证 x 至少三位数
    int right = 999 / c;            // 保证 z 最多三位数
    for (int t = left; t <= right; t++) {
        int x = a * t, y = b * t, z = c * t;
        int cnt[10] = {0};
        cnt[x/100]++; cnt[x/10%10]++; cnt[x%10]++;
        cnt[y/100]++; cnt[y/10%10]++; cnt[y%10]++;
        cnt[z/100]++; cnt[z/10%10]++; cnt[z%10]++;
        bool ok = true;
        for (int d = 1; d <= 9; d++)
            if (cnt[d] != 1) { ok = false; break; }
        if (!ok || cnt[0] > 0) continue;
        found = true;
        cout << x << " " << y << " " << z << endl;
    }
    if (!found) cout << "No!!!" << endl;
    return 0;
}

复杂度

倍数范围最多几百个,时间复杂度可以看作 O(1)O(1)。空间复杂度为输出方案数量。

总结

这题不要直接枚举所有三位数三元组。抓住比例关系后,只需要枚举一个倍数,再做数字合法性检查。