プログラミングコンテスト模擬試験問題集

1. 約数の個数

2. 最大部分行列問題

総当たり法による解法

#include <iostream>
using namespace std;

// 部分行列の合計を計算
int grid[40][30]; 
long long maxSum;

int main() {
    // 30x20のグリッドを読み込む
    for(int row = 1; row <= 30; row++) {
        for(int col = 1; col <= 20; col++) {
            cin >> grid[row][col];
        }
    }
    
    // 5x5の部分行列の合計を計算
    for(int startRow = 1; startRow <= 26; startRow++) {
        for(int startCol = 1; startCol <= 16; startCol++) {
            long long currentSum = 0;
            for(int offsetRow = 0; offsetRow < 5; offsetRow++) {
                for(int offsetCol = 0; offsetCol < 5; offsetCol++) {
                    currentSum += grid[startRow + offsetRow][startCol + offsetCol];
                }
            }
            maxSum = max(maxSum, currentSum);
        }
    }
    
    cout << maxSum << endl;
    return 0;
}

3. 奇数の出現回数

#include <iostream>
using namespace std;

int digitCount[100000+10];

int main() {
    string inputStr;
    cin >> inputStr;
    
    // 文字列を数字配列に変換
    for(int index = 0; index < inputStr.size(); index++) {
        digitCount[index] = inputStr[index] - '0';
    } 
    
    int oddCount = 0;
    for(int index = 0; index < inputStr.size(); index++) {
        if(digitCount[index] % 2 == 1) {
           oddCount++;
        }
    }
    
    cout << oddCount << endl;
    return 0;
}

4. 最大のY字形

#include <iostream>
using namespace std;

char matrix[1000+10][1000+10];

int main() {
    int rows, cols;
    cin >> rows >> cols;
    int maxSize = 0;
    
    // 行列の読み込み
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < cols; j++) {
            cin >> matrix[i][j];
        }
    }
    
    // Y字形の探索
    for(int centerY = 1; centerY < rows-1; centerY++) {
        for(int centerX = 1; centerX < cols-1; centerX++) {
           int currentSize = 0; 
           // 可能な最大サイズを計算
           int maxPossibleSize = min(min(centerY, rows-centerY-1), min(centerX, cols-centerX-1));
           
           for(int size = 1; size <= maxPossibleSize; size++) {
               // Y字形の各部分が同じ文字かチェック
               if(matrix[centerY][centerX] == matrix[centerY-size][centerX-size] && 
                  matrix[centerY][centerX] == matrix[centerY-size][centerX+size] && 
                  matrix[centerY][centerX] == matrix[centerY+size][centerX]) {
                   currentSize++;
               } else {
                   break;
               }
           } 
           maxSize = max(maxSize, currentSize);
        }
    }
    
    cout << maxSize << endl;
    return 0;
}

5. 区間カウント

#include <iostream>
using namespace std;

int main() {
    int validPairs = 0;
    
    // 効率的な計算方法
    for(int firstNum = 0; firstNum <= 90; firstNum++) {
        for(int secondNum = firstNum + 10; secondNum <= 100; secondNum++) {
            validPairs++;
        }
    }
    
    cout << validPairs;
    return 0;
}

6. 最小ステップ数

#include <iostream>
using namespace std;

int main() {
    int targetValue;
    cin >> targetValue;
    int steps = 0;
    
    // 3で割り切れる場合は割る、そうでなければ1ステップ余分に必要
    if(targetValue % 3 == 0) {
        steps = targetValue / 3;
    } else {
        steps = targetValue / 3 + 1;
    }
    
    cout << steps << endl;
    return 0;
}

7. 階段の登り方

動的計画法による解法。dp[i] = dp[i-a] + dp[i-b] + dp[i-c]; i段目にはi-a段目からa段で登る、i-b段目からb段で登る、i-c段目からc段で登る方法がある。

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

long long ways[1000000+10];
const int MOD = 1000000007;

int main() {
    int totalSteps;
    cin >> totalSteps;
    int stepA, stepB, stepC;
    cin >> stepA >> stepB >> stepC;
    
    // 初期化:0段目にいる方法は1通り
    ways[0] = 1;
    
    for(int currentStep = 1; currentStep <= totalSteps; currentStep++) {
        if(currentStep >= stepA) {
            ways[currentStep] += ways[currentStep - stepA];
        }
        if(currentStep >= stepB) {
            ways[currentStep] += ways[currentStep - stepB];
        }
        if(currentStep >= stepC) {
            ways[currentStep] += ways[currentStep - stepC];
        }
        
        // オーバーフロー防止のためMODで割る
        ways[currentStep] %= MOD;
    }
    
    cout << ways[totalSteps] << endl;
    return 0;
}

8. 大きな数の剰余計算

大きな数の剰余を計算する効率的な方法

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

int main() {
    string bigNumber = "12345678901234567890123456789012345678901234567890";
    long long remainder = 0;
    int divisor = 2023;
    
    // 文字列を左から右へ処理して剰余を計算
    for(int digitIndex = 0; digitIndex < bigNumber.size(); digitIndex++) {
        remainder = (remainder * 10 + (bigNumber[digitIndex] - '0')) % divisor;
    }
    
    cout << remainder << endl;
    return 0;
}

9. 極大値と極小値

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

int main() {
    int dataSize;
    cin >> dataSize;
    vector<int> numbers(dataSize);
    
    // データの読み込み
    for(int i = 0; i < dataSize; i++) {
        cin >> numbers[i];
    }
    
    int maxLocalMin = 0;
    int minLocalMax = 100000;
    
    // 極値の探索
    for(int i = 1; i < dataSize-1; i++) {
        // 極小値のチェック
        if(numbers[i] < numbers[i+1] && numbers[i] < numbers[i-1]) {
            maxLocalMin = max(maxLocalMin, numbers[i]);
        }
        // 極大値のチェック
        if(numbers[i] > numbers[i+1] && numbers[i] > numbers[i-1]) {
            minLocalMax = min(minLocalMax, numbers[i]);
        }
    }
    
    cout << maxLocalMin << " " << minLocalMax << endl;
    return 0;
}

10. 左右の文字数が等しい位置

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

int main() {
    string input;
    cin >> input;
    
    int leftCount = 0, rightCount = 0;
    long long equalPositions = 0;
    
    // 左から右へ処理
    for(int i = 0; i < input.size(); i++) {
        // 左側の'L'の数をカウント
        if(input[i] == 'L') {
            leftCount++;
        }
        
        // 右側の'R'の数をカウント
        if(input[input.size()-1-i] == 'R') {
            rightCount++;
        }
        
        // 左側の'L'の数と右側の'R'の数が等しい位置をカウント
        if(leftCount == rightCount) {
            equalPositions++;
        }
    }

    cout << equalPositions << endl;
    return 0;
}

11. 桁の和が特定の値となる素数

#include <iostream>
using namespace std;

// 素数判定関数
bool isPrime(int number) {
    if(number <= 1) return false;
    if(number == 2) return true;
    if(number % 2 == 0) return false;
    
    for(int divisor = 3; divisor * divisor <= number; divisor += 2) {
        if(number % divisor == 0) {
            return false;
        }
    }
    return true;
}

// 桁の和を計算する関数
int digitSum(int number) {
    int sum = 0;
    while(number > 0) {
        sum += number % 10;
        number /= 10;
    }
    return sum;
}

int main() {
    int primeCount = 0;
    
    // 100から1000000までの数をチェック
    for(int num = 100; num < 1000000; num++) {
        if(isPrime(num) && digitSum(num) == 23) {
            primeCount++;
        }
    }
    
    cout << primeCount << endl;
    return 0;
}

タグ: C++ アルゴリズム 動的計画法 数値処理 文字列処理

8月10日 22:56 投稿