Cod sursa(job #3339062)

Utilizator parus_majorParus Major parus_major Data 5 februarie 2026 22:25:31
Problema Pascal Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.67 kb
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <climits>
#include <unordered_set>

using namespace std;

ifstream fin("pascal.in");
ofstream fout("pascal.out");

const int MAXN = 5000002;

int N, D, ans, digit_size;
unordered_set<int> invalid_numbers;
int digits[30];

void back(int lv, int value, int prime) {
    if (lv == -1) {
        invalid_numbers.insert(value);
        return;
    }

    for (int i = 0; i <= digits[lv]; ++i) {
        back(lv - 1, value * prime + i, prime);
    }
}

void compute(int prime, int generate_negatives) {
    int x = N;
    ans = 1;

    digit_size = 0;
    while (x) {
        digits[digit_size] = x % prime;
        ans = ans * (1 + digits[digit_size]);
        ++digit_size;
        x /= prime;
    }
    if (digit_size == 0) ++digit_size;

    if (generate_negatives) {
        back(digit_size - 1, 0, prime);
    } 
}
int main() {
    fin >> N >> D;

    if (D == 2 || D == 3 || D == 5) {
        // Lucas theorem. Comb(N, i) is divisible by a prime p, iff at least one digit in the prime-base representation of N is smaller than the equivalent in i.
        // Therefore, the only numbers that aren't divisible by p, are the ones that have smaller or equal digits in prime-base.
        // Solution: Simply generate all numbers that have smaller digits and put them into a set. 
        compute(D, false);

        fout << N + 1 - ans;

        return 0;
    }

    if (D == 4) {
        for (int i = 0; i <= N; ++i) {
            // Kummer's theorem. The largest K such that p^k divides Comb(N, i) = number of carries when adding i and N-i.
            
            // The number of carries when adding two numbers in base 2 is equivalent to counting number of 1s in the (x + y) ^ (x ^ y) representation.
            // (x + y) = correct sum
            // (x ^ y) = binary addition without carries
            // xor-ing these shows us where the carries actually are located. 
            int carries = N ^ i ^ (N - i);
            // We only care that there are at least 2.
            if (carries > (carries & (-carries))) {
                ++ans;
            }
        }
        fout << ans;
        return 0;
    }

    if (D == 6) {
        // Same as D = 2,3,5 case, just that we invalidate all numbers that either are not divisible by 2 or by 3.

        // Possible optimization is to check whether you would be generating too many numbers and instead generate the correct ones. Too much work though.
        compute(2, true);
        compute(3, true);

        fout << N + 1 - invalid_numbers.size();
        return 0;
    }

    return 0;
}