洛谷P10262"亲朋数"是一道经典的算法竞赛训练题目,主要考察选手对数字性质分析和基础算法实现的能力。题目要求找出特定范围内满足"亲朋数"条件的数字,这类题目在NOIP/CSP等竞赛中经常作为中等难度题出现。
亲朋数的定义是:对于一个正整数n,如果存在另一个正整数m,使得n和m的数字组成完全相同(即数字排列不同但包含相同的数字),且n能被m整除,那么n就称为亲朋数。例如122和212就是一对亲朋数,因为122÷212≈0.575(不满足),但244和122满足244÷122=2。
最直观的解法是对于每个数字n,生成所有可能的排列组合,然后检查是否存在一个排列m满足n%m==0。但这种解法的时间复杂度是O(n!),对于较大的n值完全不适用。
优化方向主要有:
采用以下步骤实现高效检查:
cpp复制bool isRelativeFriend(int n, int m) {
int countN[10] = {0};
int countM[10] = {0};
int temp = n;
while(temp > 0) {
countN[temp%10]++;
temp /= 10;
}
temp = m;
while(temp > 0) {
countM[temp%10]++;
temp /= 10;
}
for(int i=0; i<10; i++) {
if(countN[i] != countM[i])
return false;
}
return n % m == 0;
}
完整的解题程序应包括:
cpp复制#include <iostream>
#include <vector>
using namespace std;
vector<int> findRelativeFriends(int L, int R) {
vector<int> result;
for(int n = L; n <= R; n++) {
// 检查n是否是亲朋数
bool found = false;
// 生成所有可能约数并检查
for(int m = 1; m*m <= n && !found; m++) {
if(n % m == 0) {
if(isRelativeFriend(n, m) && m != n) {
found = true;
}
int another = n / m;
if(another != m && isRelativeFriend(n, another)) {
found = true;
}
}
}
if(found) result.push_back(n);
}
return result;
}
设数字位数为d,最大数为N:
cpp复制void test() {
// 基础测试
assert(isRelativeFriend(122, 212) == false);
assert(isRelativeFriend(244, 122) == true);
// 边界测试
assert(findRelativeFriends(1, 10).size() == 0);
assert(findRelativeFriends(100, 200).size() > 0);
// 性能测试
auto result = findRelativeFriends(1, 100000);
cout << "Found " << result.size() << " relative friends" << endl;
}
输入输出优化:在数据量大时使用快速IO
cpp复制ios::sync_with_stdio(false);
cin.tie(nullptr);
常见错误:
调试技巧:
扩展思考:
这类数字性质分析题目在竞赛中常见,掌握亲朋数的解法有助于举一反三。核心思路都是通过数字特征分析减少不必要的计算,结合数学性质进行优化。