特別な数の和 - P8680 [蓝桥杯 2019 省 B]

P8680 [蓝桥杯 2019 省 B] 特別な数の和

問題説明

数値の桁に2、0、1、9が含まれる数字(先頭の0は除く)に興味があるとします。1から40までの範囲において、このような数は1、2、9、10から32、39、40であり、合計28個あります。それらの総和は574です。

n以下の範囲で、このような数の総和を求めてください。

入力形式

一行に整数nが与えられます。

出力形式

条件に合う数の総和を一行に出力してください。

入力例

40

出力例

574

制約

  • 20%のテストケース:1 ≤ n ≤ 10
  • 50%のテストケース:1 ≤ n ≤ 100
  • 80%のテストケース:1 ≤ n ≤ 1000
  • すべてのテストケース:1 ≤ n ≤ 10000

解法

最もシンプルな解法は全探索です。各数値について、2、0、1、9のいずれかが含まれているかどうかを判定します。

全探索による実装

#include <cstdio>
bool check(int num) {
    int digit;
    while(num) {
        digit = num % 10;
        if(digit == 2 || digit == 0 || digit == 9 || digit == 1)
            return true;
        else
            num /= 10;
    }
    return false;
}
int main() {
    int n, total = 0;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        if(check(i))
            total += i;
    }
    printf("%d\n", total);
    return 0;
}
#include <bits/stdc++.h>
using namespace std;
int main() {
    int n;
    cin >> n;
    long long sum = 0;
    for(int i = 1; i <= n; i++) {
        int temp = i;
        while(temp != 0) {
            int digit = temp % 10;
            if(digit == 2 || digit == 0 || digit == 1 || digit == 9) {
                sum += i;
                break;
            }
            temp /= 10;
        }
    }
    cout << sum << endl;
    return 0;
}

効率的な解法

数のパターンには一定の規則があります。例えば、10個の連続した数字をグループとして扱い、それぞれのグループの末尾の数字だけを確認することで、計算量を削減できます。

#include <cstdio>
bool hasSpecialDigit(int num) {
    int digit;
    while(num) {
        digit = num % 10;
        if(digit == 2 || digit == 0 || digit == 9 || digit == 1)
            return true;
        else
            num /= 10;
    }
    return false;
}
int main() {
    int n, result = 0, groupBase, remainder;
    scanf("%d", &n);
    for(int i = 1; i < n && n >= 10; i += 10) {
        if(hasSpecialDigit(i / 10))
            result += i * 10 + 35;
        else
            result += i * 4 + 8;
    }
    groupBase = (n / 10) * 10;
    if(hasSpecialDigit(n / 10)) {
        for(int i = groupBase; i <= n; ++i)
            result += i;
    } else {
        remainder = n % 10;
        if(remainder < 9) {
            if(remainder < 2) {
                if(remainder < 1)
                    result += groupBase;
                else
                    result += groupBase * 2 + 1;
            } else
                result += groupBase * 3 + 3;
        } else
            result += groupBase * 4 + 12;
    }
    printf("%d", result);
    return 0;
}

タグ: 蓝桥杯 数学 模拟 枚举 数位处理

8月10日 22:33 投稿