解一元二次方程的烦恼

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

逐行提取字符串中的数字形成整数,超过 4e7 直接报大,否则做素数判断并按升序输出质因数分解。

OJ: luogu

题目 ID: P1619

难度:普及-

标签:字符串模拟数论

日期: 2026-06-18 21:50

题意

这题的输入不是一个“正常整数”,而是一行任意字符串。
每次都要先输出 Enter the number=,然后读入一行,把其中所有数字字符按原顺序提取出来,拼成一个十进制整数。

如果这一行里没有任何数字,就直接结束程序。
否则对提取出来的数做判断:

  • 若大于 40000000,输出 Prime? No!The number is too large!
  • 若是素数,输出 Prime? Yes!
  • 若不是素数,输出 Prime? No!
  • 如果它还是一个大于 1 的合数,再输出它的质因数分解

下面这张表最容易帮我们看懂“输入到底怎么解释”:

原字符串 提取后的数字 含义
1.5 15 15 处理
-1 1 1 处理
1234###24#@13#@¥!1 123424131 超过上界,直接报大
halt@@ 空串 结束程序

思路

先看一个最直接的朴素做法:

按题意模拟整套流程:

  1. 读入一整行字符串;
  2. 提取其中所有数字字符;
  3. 如果没有数字,直接结束;
  4. 如果得到的数超过 40000000,直接输出过大提示;
  5. 否则判断素数;
  6. 如果是合数,再按升序输出质因数分解。
cpp
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;

string s;

string extract_digits(const string &src) {
    string digits;
    for (char ch : src) {
        if (ch >= '0' && ch <= '9') {
            digits += ch;
        }
    }
    return digits;
}

string normalize_number_string(const string &digits) {
    int pos = 0;
    while (pos < (int) digits.size() && digits[pos] == '0') {
        pos++;
    }
    if (pos == (int) digits.size()) {
        return "0";
    }
    return digits.substr(pos);
}

bool is_too_large(const string &num) {
    const string LIMIT = "40000000";
    if ((int) num.size() > (int) LIMIT.size()) {
        return true;
    }
    if ((int) num.size() < (int) LIMIT.size()) {
        return false;
    }
    return num > LIMIT;
}

int string_to_int(const string &num) {
    int value = 0;
    for (char ch : num) {
        value = value * 10 + (ch - '0');
    }
    return value;
}

// 朴素素性判断:从 2 一直试到 n-1,只适合小数据对拍。
bool is_prime_bruteforce(int n) {
    if (n <= 1) {
        return false;
    }
    for (int d = 2; d < n; d++) {
        if (n % d == 0) {
            return false;
        }
    }
    return true;
}

string factorize_to_string(int n) {
    int x = n;
    string res = to_string(n) + "=";
    bool first = true;

    for (int p = 2; p <= x; p++) {
        if (x % p != 0) {
            continue;
        }
        int cnt = 0;
        while (x % p == 0) {
            x /= p;
            cnt++;
        }
        if (!first) {
            res += "*";
        }
        first = false;
        res += to_string(p) + "^" + to_string(cnt);
    }

    return res;
}

bool solve_one(const string &line) {
    string digits = extract_digits(line);
    if (digits.empty()) {
        return false;
    }

    string num = normalize_number_string(digits);

    if (is_too_large(num)) {
        cout << "Prime? No!\n";
        cout << "The number is too large!\n\n";
        return true;
    }

    int value = string_to_int(num);
    if (is_prime_bruteforce(value)) {
        cout << "Prime? Yes!\n\n";
        return true;
    }

    cout << "Prime? No!\n";
    if (value > 1) {
        cout << factorize_to_string(value) << '\n';
    }
    cout << '\n';
    return true;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    while (true) {
        cout << "Enter the number=\n";
        if (!getline(cin, s)) {
            break;
        }
        if (!solve_one(s)) {
            break;
        }
    }

    return 0;
}

这题真正容易错的是审题,不是算法。

最关键的两个点是:

  1. 结束条件不是某个固定单词,而是“这一行完全提取不到数字”;
  2. -11.5 这样的输入,都会先做“提取数字”这一步,所以它们分别会被当作 115

正式代码只是在朴素模拟的基础上,把几个关键步骤拆成函数:

  • extract_digits():提取数字;
  • normalize_number_string():去掉前导零;
  • is_too_large():先用字符串判断是否超过 40000000
  • is_prime():试除判断素数;
  • factorize_to_string():输出质因数分解。

代码

cpp
#include <bits/stdc++.h>
using namespace std;

string s;

string extract_digits(const string &src) {
    string digits;
    for (char ch : src) {
        if (ch >= '0' && ch <= '9') {
            digits += ch;
        }
    }
    return digits;
}

string normalize_number_string(const string &digits) {
    int pos = 0;
    while (pos < (int) digits.size() && digits[pos] == '0') {
        pos++;
    }
    if (pos == (int) digits.size()) {
        return "0";
    }
    return digits.substr(pos);
}

bool is_too_large(const string &num) {
    const string LIMIT = "40000000";
    if ((int) num.size() > (int) LIMIT.size()) {
        return true;
    }
    if ((int) num.size() < (int) LIMIT.size()) {
        return false;
    }
    return num > LIMIT;
}

int string_to_int(const string &num) {
    int value = 0;
    for (char ch : num) {
        value = value * 10 + (ch - '0');
    }
    return value;
}

bool is_prime(int n) {
    if (n <= 1) {
        return false;
    }
    for (int d = 2; 1LL * d * d <= n; d++) {
        if (n % d == 0) {
            return false;
        }
    }
    return true;
}

string factorize_to_string(int n) {
    int x = n;
    string res = to_string(n) + "=";
    bool first = true;

    for (int p = 2; 1LL * p * p <= x; p++) {
        if (x % p != 0) {
            continue;
        }
        int cnt = 0;
        while (x % p == 0) {
            x /= p;
            cnt++;
        }
        if (!first) {
            res += "*";
        }
        first = false;
        res += to_string(p) + "^" + to_string(cnt);
    }

    if (x > 1) {
        if (!first) {
            res += "*";
        }
        res += to_string(x) + "^1";
    }

    return res;
}

bool solve_one(const string &line) {
    string digits = extract_digits(line);
    if (digits.empty()) {
        return false;
    }

    string num = normalize_number_string(digits);

    if (is_too_large(num)) {
        cout << "Prime? No!\n";
        cout << "The number is too large!\n\n";
        return true;
    }

    int value = string_to_int(num);
    if (is_prime(value)) {
        cout << "Prime? Yes!\n\n";
        return true;
    }

    cout << "Prime? No!\n";
    if (value > 1) {
        cout << factorize_to_string(value) << '\n';
    }
    cout << '\n';
    return true;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    while (true) {
        cout << "Enter the number=\n";
        if (!getline(cin, s)) {
            break;
        }
        if (!solve_one(s)) {
            break;
        }
    }

    return 0;
}

复杂度

设提取出的整数为 N,输入行长度为 len
提取数字的复杂度是 O(len)O(len),素性判断与质因数分解的复杂度是 O(N)O(\sqrt{N})
空间复杂度是 O(len)O(len)

总结

这题是典型的“字符串模拟 + 数论”题。

不要急着看素数判断,先把输入解释规则读清楚:

  1. 读整行;
  2. 提取数字;
  3. 没有数字就结束;
  4. 超上界就报大;
  5. 否则再做素数判断和分解。

一图流解析

这张图把本题的建模、关键转移、实现检查和训练方法压缩到一页,适合读完正文后复盘。

一图流解析