①完全数
ある数字nと、nのproper divisors(自分以外の約数)の和が等しいとき、nを完全数(perfect number)と呼ぶ。「博士が愛した数式」という小説にも出てきました。
例えば、6は完全数。6 = 1+2+3。
②婚約数
ある数pとqは、以下の2つの条件をともに満たすとき婚約数(betrothed number)とよばれる。準友愛数ともよばれる。
- pと、qの1以外のproper divisorsの和が等しい
- qと、pの1以外のproper divisorsの和が等しい
一番小さな婚約数は、(48, 75)。
48 = 3 + 5 + 15 + 25
75 = 2 + 3 + 4 + 6 + 8+ 12 + 16 + 24
③友愛数
ある数pとqは、以下の2つの条件をともに満たすとき友愛数(amicable number)とよばれる。
- pと、qのproper divisorsの和が等しい
- qと、pのproper divisorsの和が等しい
一番小さな友愛数は、220、284。
220 = 1 + 2 + 4 + 71 + 142
284 = 1 + 2+ 4 + 5 + 10 + 11 + 20 + 22 + 44 + 55 + 110
完全数、婚約数、友愛数を単純探索で列挙して遊んでみる。
約数はメモっておいて、婚約数、友愛数を場合は、逆引き用のテーブルを作っておけば、O(n log n)で探索できる。
- #include <iostream>
- #include <vector>
- #include <map>
- #define MAX_NUM 100000
- using namespace std;
- vector<int> divisors[MAX_NUM+1];
- map<int, vector<int> > calcTable;
- vector<int> getPerfectNumber() {
- vector<int>ret;
- for (int x = 1; x <= MAX_NUM; x++) {
- int y = 0;
- for (int i = 0; i < divisors[x].size(); i++)
- y += divisors[x][i];
- y -= x;
- if (x == y)
- ret.push_back(x);
- }
- return ret;
- }
- vector<pair<int, int> > doit(bool excludeOne) {
- map<int, vector<int> > table;
- for (int x = 1; x <= MAX_NUM; x++) {
- int y = 0;
- for (int i = 0; i < divisors[x].size(); i++)
- y += divisors[x][i];
- y -= (x+excludeOne);
- table[y].push_back(x);
- }
- vector<pair<int, int> >ret;
- for (int x = 1; x <= MAX_NUM; x++) {
- if (!table.count(x))
- continue;
- int xs = 0;
- for (int i = 0; i < divisors[x].size(); i++)
- xs += divisors[x][i];
- xs -= (x+excludeOne);
- for (int i = 0; i < table[x].size(); i++) {
- int y = table[x][i];
- if (y == xs && x < y)
- ret.push_back(make_pair(x, y));
- }
- }
- return ret;
- }
- vector<pair<int, int> > getbetrothedNumber() {
- return doit(true);
- }
- vector<pair<int, int> > getAmicableNumber() {
- return doit(false);
- }
- int main() {
- // store each number's divisors
- for (int i = 1; i <= MAX_NUM; i++) {
- for (int j = 1; j*j<=i; j++) {
- if (i % j == 0) {
- divisors[i].push_back(j);
- if (j*j != i)
- divisors[i].push_back(i/j);
- }
- }
- }
- vector<int>nums;
- vector<pair<int, int> >pairs;
- // Perfect Numbers
- nums = getPerfectNumber();
- cout << "Perfect Numbers:" << endl;
- for (int i = 0; i < nums.size(); i++)
- cout << nums[i] << endl;
- cout << endl;
- nums.clear();
- // Betrothed Numbers
- pairs = getbetrothedNumber();
- cout << "Betrothed Numbers:" << endl;
- for (int i = 0; i < pairs.size(); i++)
- cout << pairs[i].first << ", " << pairs[i].second << endl;
- cout << endl;
- pairs.clear();
- // Amicable Numbers
- pairs = getAmicableNumber();
- cout << "Amicable Numbers:" << endl;
- for (int i = 0; i < pairs.size(); i++)
- cout << pairs[i].first << ", " << pairs[i].second << endl;
- cout << endl;
- pairs.clear();
- return 0;
- }