力技で問いた結果のログから規則性を調べて改良してみました。
前よりは格段に速いですが、計算で求めてはいないので、
めちゃくちゃ速いというわけでは無いです。
#include <iostream> #include <math.h> using namespace std; void f(unsigned long long n, unsigned long long sum[]) { for (unsigned long long i = n; i > 0; i /= 10) { unsigned long long k = i % 10; // 0 の桁は数えない if (k > 0) { sum[k]++; } } } int main(int argc, char *args[]) { const unsigned long long ten_billion = 10000000000ULL; unsigned long long total = 0; unsigned long long pattern[10][500]; int pidx[10]; unsigned long long sum[10]; for (int d = 0; d < 10; d++) { sum[d] = 0; pidx[d] = 0; for (int i = 0; i < 500; i++) { pattern[d][i] = 0; } } for (unsigned long long n = 1; n <= ten_billion; n++) { f(n, sum); // d = 1 のものは total に加算 if (n <= 1111111110ULL && n == sum[1]) { total += n; // cout << "[N]d=1" << " n=" << n << " total=" << total << endl; } for (int d = 2; d <= 9; d++) { // 出現パターンを記録する(total には加算しない) if (n == sum[d]) { // cout << "[P]d=" << d << " n=" << n << " total=" << total << endl; pattern[d][pidx[d]] = n; pidx[d]++; } } } // 見つけたパターンを元に 100 億増し毎に total へ加算 for (unsigned long long d = 2; d <= 9; d++) { for (int i = 0; pattern[d][i] > 0; i++) { for (unsigned long long n = 0; n * ten_billion + pattern[d][i] < d * ten_billion; n++) { // cout << "ADD d=" << d << " val=" << n * ten_billion + pattern[d][i] << endl; total += n * ten_billion + pattern[d][i]; } } } cout << "total= " << total << endl; return 0; }
事務所 PC は遅くて使い物になりませんが、仕事用 Linux マシン (CentOS)があったので、こいつの Docker コンテナ内でこっそり作業していましたw
64ビットマシンなのでそれなりですが性能はいまいちです。同じ処理で 4 分ぐらいかかります。
結果
$ time ./problem-156 total= 21295121502550 real 2m55.890s user 2m55.828s sys 0m0.015s