题目描述
给定一个正整数 nnn,编写程序找到一个非零的倍数 mmm,使得 mmm 的十进制表示仅包含数字 000 和 111。题目保证 nnn 不超过 200200200,并且存在一个对应的 mmm,其十进制表示不超过 100100100 位。
输入格式
输入文件可能包含多个测试用例。每行包含一个 nnn 的值(1≤n≤2001 \leq n \leq 2001≤n≤200)。以一行包含 000 结束输入。
输出格式
对于每个 nnn,输出一行对应的 mmm。mmm 的十进制表示不能超过 100100100 位。如果对于给定的 nnn 有多个解,输出任意一个均可。
样例输入
2
6
19
0
样例输出
10
100100100100100100
111111111111111111
题目分析
问题理解
我们需要找到一个数 mmm,满足:
- mmm 是 nnn 的倍数(m≠0m \neq 0m=0)
- mmm 的十进制表示中只包含字符
0和1 - mmm 的位数不超过 100100100
直接枚举的困难
最直接的想法是枚举所有由 0 和 1 组成的数字,从小到大检查是否能被 nnn 整除。但是,可能的数字数量是 21002^{100}2100 级别,这显然不可行。
关键思路:模运算 + BFS\texttt{BFS}BFS
我们可以利用模运算来避免处理大数,同时使用广度优先搜索(BFS\texttt{BFS}BFS)来按长度递增的顺序搜索解。
核心观察:
- 我们只关心数字模 nnn 的余数
- 如果两个数字模 nnn 的余数相同,那么它们后续添加相同的数字(
0或1)后,余数的变化规律相同 - 因此,对于每个余数,我们只需要保留第一次达到该余数的数字(这保证我们找到的是最小的解)
BFS\texttt{BFS}BFS 状态设计
- 状态:当前数字模 nnn 的余数
- 初始状态:余数为 111(对应数字
1) - 状态转移:
- 在当前数字末尾加
0:新余数 = (当前余数×10) mod n(当前余数 \times 10) \bmod n(当前余数×10)modn - 在当前数字末尾加
1:新余数 = (当前余数×10+1) mod n(当前余数 \times 10 + 1) \bmod n(当前余数×10+1)modn
- 在当前数字末尾加
- 终止条件:找到余数为 000 的状态
算法正确性
- 由于余数范围是 000 到 n−1n-1n−1,最多有 nnn 个不同状态,BFS\texttt{BFS}BFS 会在有限步内结束
- 题目保证存在不超过 100100100 位的解,因此不会无限循环
- BFS\texttt{BFS}BFS 按长度递增搜索,保证找到的是最小的解
复杂度分析
- 时间复杂度:O(n)O(n)O(n),每个余数最多访问一次
- 空间复杂度:O(n)O(n)O(n),用于存储访问标记和队列
代码实现
// Find The Multiple
// UVa ID: 1189
// Verdict: Accepted
// Submission Date: 2025-10-16
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;
string findMultiple(int n) {
// 特殊情况:n=1 时直接返回 "1"
if (n == 1) return "1";
// BFS 队列,存储 (余数, 对应的数字字符串)
queue<pair<int, string>> q;
// 访问标记数组,记录每个余数是否已被访问
vector<bool> visited(n, false);
// 从数字 1 开始搜索
q.push({1 % n, "1"});
visited[1 % n] = true;
while (!q.empty()) {
// 取出队首元素
int rem = q.front().first;
string numStr = q.front().second;
q.pop();
// 如果余数为 0,找到解
if (rem == 0) {
return numStr;
}
// 尝试在当前数字末尾加 0
int newRem = (rem * 10) % n;
if (!visited[newRem]) {
visited[newRem] = true;
q.push({newRem, numStr + "0"});
}
// 尝试在当前数字末尾加 1
newRem = (rem * 10 + 1) % n;
if (!visited[newRem]) {
visited[newRem] = true;
q.push({newRem, numStr + "1"});
}
}
return ""; // 理论上不会执行到这里
}
int main() {
int n;
// 读取输入直到遇到 0
while (cin >> n && n != 0) {
cout << findMultiple(n) << endl;
}
return 0;
}
总结
本题通过将大数问题转化为模运算问题,巧妙地避免了直接处理大数的复杂性。BFS\texttt{BFS}BFS 按长度递增搜索保证了解的最优性,而模运算的状态压缩确保了算法的高效性。这种"余数状态 + BFS\texttt{BFS}BFS"的思路在处理只包含特定数字的倍数问题时非常有效。
1013

被折叠的 条评论
为什么被折叠?



