藍橋杯2021年省赛B組 C/C++ 問題解説

問題A:空間計算

メモリ空間の計算問題。256MBをバイト単位で表現し、各データが32ビット(4バイト)の場合の要素数を求める。

計算式:256 × 1024 × 1024 × 8 ÷ 32 = 67108864

問題B:カードの数字

0から9までの数字カードが各2021枚ずつある。1から順に数字を書いていくとき、何まで書けるかを求める問題。

#include <iostream>
using namespace std;

int main() {
    int cards[10];
    for (int i = 0; i < 10; i++) {
        cards[i] = 2021;
    }
    
    int num;
    for (num = 1; num <= 50000; num++) {
        int temp = num;
        bool enough = true;
        while (temp > 0) {
            int digit = temp % 10;
            cards[digit]--;
            if (cards[digit] < 0) {
                enough = false;
                break;
            }
            temp /= 10;
        }
        if (!enough) break;
    }
    cout << num - 1 << endl;
    return 0;
}

答え:3181

問題C:直線の本数

20×21のグリッド上の点を通る異なる直線の本数を求める。2点を通る直線の方程式を求め、重複を排除してカウントする。

#include <iostream>
using namespace std;

struct Line {
    int a, b, c;
};

bool isSameLine(int x1, int y1, int x2, int y2, Line& line) {
    return (line.b * x1 + line.a * y1 + line.c == 0) &&
           (line.b * x2 + line.a * y2 + line.c == 0);
}

int main() {
    Line lines[50000];
    int count = 0;
    
    for (int x1 = 0; x1 <= 19; x1++) {
        for (int y1 = 0; y1 <= 20; y1++) {
            for (int x2 = x1 + 1; x2 <= 19; x2++) {
                for (int y2 = 0; y2 <= 20; y2++) {
                    bool exists = false;
                    int a = y2 - y1;
                    int b = x1 - x2;
                    int c = x2 * y1 - x1 * y2;
                    
                    for (int k = 0; k < count; k++) {
                        if (lines[k].a * b == lines[k].b * a &&
                            lines[k].a * c == lines[k].c * a) {
                            exists = true;
                            break;
                        }
                    }
                    
                    if (!exists) {
                        lines[count].a = a;
                        lines[count].b = b;
                        lines[count].c = c;
                        count++;
                    }
                }
            }
        }
    }
    cout << count << endl;
    return 0;
}

答え:40257

問題D:約数の組

与えられた数値nについて、a × b × c = n を満たす正の整数の組の個数を求める。

#include <iostream>
#include <cmath>
using namespace std;

int main() {
    long long n = 2021041820210418;
    long long result = 0;
    long long cubeRoot = pow(n, 1.0/3) + 1;
    
    for (long long a = 1; a <= cubeRoot; a++) {
        if (n % a != 0) continue;
        long long remainder = n / a;
        
        for (long long b = a; b * b <= remainder; b++) {
            if (remainder % b != 0) continue;
            long long c = remainder / b;
            
            if (a == b && b == c) {
                result += 1;
            } else if (a == b || b == c) {
                result += 3;
            } else {
                result += 6;
            }
        }
    }
    cout << result << endl;
    return 0;
}

問題F:時刻表示

1970年1月1日からの経過ミリ秒をHH:MM:SS形式で表示する。

#include <iostream>
#include <cstdio>
using namespace std;

int main() {
    long long milliseconds;
    cin >> milliseconds;
    
    long long totalSeconds = milliseconds / 1000;
    int seconds = totalSeconds % 60;
    int minutes = (totalSeconds / 60) % 60;
    int hours = (totalSeconds / 3600) % 24;
    
    printf("%02d:%02d:%02d\n", hours, minutes, seconds);
    return 0;
}

問題G:天秤の計量

N個の分銅を使って測定できる異なる重さの総数を求める。分銅は天秤の両側に配置可能。

#include <iostream>
#include <cmath>
using namespace std;

bool measurable[100005];
int weights[105];

int main() {
    int n;
    cin >> n;
    
    int maxWeight = 0;
    for (int i = 0; i < n; i++) {
        cin >> weights[i];
        maxWeight += weights[i];
    }
    
    measurable[0] = true;
    
    for (int i = 0; i < n; i++) {
        for (int j = maxWeight; j >= -maxWeight; j--) {
            int idx = j + maxWeight;
            if (measurable[idx]) {
                measurable[idx + weights[i]] = true;
                measurable[abs(j - weights[i]) + maxWeight] = true;
            }
        }
    }
    
    int count = 0;
    for (int i = 1; i <= maxWeight; i++) {
        if (measurable[i + maxWeight]) count++;
    }
    cout << count << endl;
    return 0;
}

問題H:パスカルの三角形

パスカルの三角形を左から右、上から下の順に並べた数列で、与えられた数値Nが最初に出現する位置を求める。

#include <iostream>
using namespace std;

long long comb(int n, int r) {
    if (r > n - r) r = n - r;
    long long result = 1;
    for (int i = 0; i < r; i++) {
        result = result * (n - i) / (i + 1);
    }
    return result;
}

int main() {
    long long n;
    cin >> n;
    
    long long pos = 1;
    for (int row = 1; row <= 2000; row++) {
        for (int col = 1; col <= row; col++) {
            if (comb(row - 1, col - 1) == n) {
                cout << pos << endl;
                return 0;
            }
            pos++;
        }
    }
    
    long long k = 1;
    while (k * (k + 1) / 2 < n) k++;
    cout << n * (n + 1) / 2 + 2 << endl;
    return 0;
}

問題I:列のソート操作

初期列(1, 2, ..., n)に対し、m回の部分ソート操作を行った後の列を求める。

#include <iostream>
#include <algorithm>
using namespace std;

int arr[100005];

bool descending(int a, int b) {
    return a > b;
}

int main() {
    int n, m;
    cin >> n >> m;
    
    for (int i = 1; i <= n; i++) {
        arr[i] = i;
    }
    
    for (int i = 0; i < m; i++) {
        int type, pos;
        cin >> type >> pos;
        
        if (type == 0) {
            sort(arr + 1, arr + pos + 1, descending);
        } else {
            sort(arr + pos, arr + n + 1);
        }
    }
    
    for (int i = 1; i <= n; i++) {
        cout << arr[i];
        if (i < n) cout << " ";
    }
    cout << endl;
    return 0;
}

問題J:括弧列

不完全な括弧列を完成させるために必要な最小限の括弧追加の組み合わせ総数を求める。動的計画法を用いて解く。

タグ: C++ アルゴリズム 動的計画法 数論 全探索

6月5日 23:06 投稿