逐行提取字符串中的数字形成整数,超过 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@@ |
空串 | 结束程序 |
思路
先看一个最直接的朴素做法:
按题意模拟整套流程:
- 读入一整行字符串;
- 提取其中所有数字字符;
- 如果没有数字,直接结束;
- 如果得到的数超过
40000000,直接输出过大提示; - 否则判断素数;
- 如果是合数,再按升序输出质因数分解。
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、1.5这样的输入,都会先做“提取数字”这一步,所以它们分别会被当作1和15。
正式代码只是在朴素模拟的基础上,把几个关键步骤拆成函数:
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。
提取数字的复杂度是
空间复杂度是
总结
这题是典型的“字符串模拟 + 数论”题。
不要急着看素数判断,先把输入解释规则读清楚:
- 读整行;
- 提取数字;
- 没有数字就结束;
- 超上界就报大;
- 否则再做素数判断和分解。
一图流解析
这张图把本题的建模、关键转移、实现检查和训练方法压缩到一页,适合读完正文后复盘。
