Problem 21 Amicable numbers
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 10000 + 10;
int work(int n) {
int factorSum[N];
for(int i = 1; i <= n; i++) {
for(int j = i*2; j <= n; j += i) {
factorSum[j] += i;
}
}
int ans = 0;
for(int i = 1; i < n; i++) {
if(i >= factorSum[i]) {//避免重复取亲和数对
continue;
}
if(factorSum[i] <= n && factorSum[factorSum[i]] == i) {
ans += i + factorSum[i];
}
}
return ans;
}
int main() {
printf("%d\n", work(10000));
return 0;
}
Problem 22 Names scores
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
typedef long long LL;
int score(string name) {
int ans = 0;
for(int i = 0; i < name.size(); i++) {
ans += tolower(name[i]) - 'a' + 1;
}
return ans;
}
LL work(vector<string> &names) {
sort(names.begin(), names.end());
LL ans = 0;
for(int i = 0; i < names.size(); i++) {
ans += score(names[i]) * (i + 1);
}
return ans;
}
int main() {
vector<string> names;
ifstream fin("./../p022_names.txt");
string str;
fin >> str;
int l = 0, r = 0;
while(l < str.size()) {
while(l < str.size() && str[l] != '\"') {
l++;
}
r = l + 1;
while(r < str.size() && isalpha(str[r])) {
r++;
}
names.emplace_back(str.substr(l+1, r - l - 1));
l = r + 1;
}
printf("%lld\n", work(names));
return 0;
}
Problem 23 Non-abundant sums
思路:
用素数筛法的思想求出每个数字的真因子之和,于是根据每个数字的真因子之和就可以判断这个数字是不是盈数,然后用盈数两两求和标记可以表示成两个盈数的数字,剩下未标记的就是符合题目要求的数字了,计算其个数。
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N = 30000 + 10;
int work(int n) {
int factSum[N];
for(int i = 1; i <= n; i++) {
for(int j = 2*i; j <= n; j += i) {
factSum[j] += i;
}
}
int arr[N];
int k = 0;
for(int i = 1; i <= n; i++) {
if(factSum[i] > i) {
arr[k++] = i;
}
}
bool vis[N];
fill(vis, vis + n + 1, false);
for(int i = 0; i < k; i++) {
for(int j = 0; j < k; j++) {
if(arr[i] + arr[j] > n) {
continue;
}
vis[arr[i]+arr[j]] = true;
}
}
int ans = 0;
for(int i = 0; i <= n; i++) {
if(! vis[i]) {
ans += i;
}
}
return ans;
}
int main() {
printf("%d\n", work(28123));
return 0;
}
Problem 24 Lexicographic permutations
思路:
康托逆展开
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 100 + 10;
LL fact[N];
void init(int n) {
fact[0] = 1;
for(int i = 1; i <= n; i++) {
fact[i] = fact[i-1] * i;
}
}
vector<int> work(vector<int> arr, LL k) {
k -= 1;
vector<int> ans;
for(int i = arr.size(); i >= 1; i--) {
int a = k / fact[i-1];
k %= fact[i-1];
ans.emplace_back(arr[a]);
arr.erase(arr.begin() + a);
sort(arr.begin(), arr.end());
}
return ans;
}
int main() {
init(10);
vector<int> arr = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
vector<int> ans = work(arr, 1000000);
for(int i = 0; i < ans.size(); i++) {
printf("%d", ans[i]);
}
printf("\n");
return 0;
}
Problem 25 1000-digit Fibonacci number
思路:
高精度加法求斐波那契数列
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1000 + 10;
void add(char *num1, char *num2, char *sum) {
int len1 = strlen(num1), len2 = strlen(num2);
int len = 0;
reverse(num1, num1 + len1);
reverse(num2, num2 + len2);
int carry = 0;
for(int i = 0; i < len1 || i < len2; i++) {
carry += i < len1 ? num1[i]-'0' : 0;
carry += i < len2 ? num2[i]-'0' : 0;
sum[len++] = carry % 10 + '0';
carry /= 10;
}
if(carry) {
sum[len++] = carry + '0';
}
sum[len] = '\0';
reverse(num1, num1 + len1);
reverse(num2, num2 + len2);
reverse(sum, sum + len);
}
int main() {
char num1[N], num2[N], sum[N];
num1[0] = '0', num1[1] = '\0';
num2[0] = '1', num2[1] = '\0';
int cnt = 1;
while(true) {
add(num1, num2, sum);
++cnt;
if(strlen(sum) >= 1000) {
break;
}
memcpy(num1, num2, sizeof(num2));
memcpy(num2, sum, sizeof(sum));
}
printf("%d\n", cnt);
return 0;
}