Cod sursa(job #3357158)

Utilizator parus_majorParus Major parus_major Data 6 iunie 2026 18:00:16
Problema Cifre Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.65 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
#include <string>

using namespace std;

// Combinări de n luate câte k
long long C[15][15];

void precomputeCombinations() {
    for (int i = 0; i <= 10; ++i) {
        C[i][0] = 1;
        for (int j = 1; j <= i; ++j) {
            C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
        }
    }
}

// Calculează în câte moduri putem forma un număr de 'len' cifre (care poate începe cu 0)
// astfel încât să aibă cel puțin 'needed' cifre egale cu C
long long countWays(int len, int needed, int C_digit) {
    if (needed <= 0) {
        // Dacă nu mai avem nevoie de nicio cifră C, putem pune orice pe pozițiile rămase
        long long total = 1;
        for (int i = 0; i < len; ++i) total *= 10;
        return total;
    }
    if (len < needed) return 0;

    long long ans = 0;
    // i reprezintă numărul EXACT de cifre egale cu C pe care le plasăm în spațiile libere
    for (int i = needed; i <= len; ++i) {
        long long combinations = C[len][i];
        long long rest = 1;
        for (int j = 0; j < len - i; ++j) {
            rest *= 9; // restul cifrelor pot fi orice în afară de C
        }
        ans += combinations * rest;
    }
    return ans;
}

// Returnează câte numere din intervalul [0, X] au cel puțin K cifre egale cu C
long long countValid(long long X, int C_digit, int K) {
    if (X < 0) return 0;
    if (X == 0) return (C_digit == 0 && K <= 1) || (C_digit != 0 && K == 0) ? 1 : 0;

    string s = to_string(X);
    int num_digits = s.length();
    long long total_valid = 0;

    // 1. Numărăm valorile valide cu lungime STRICT mai mică decât a lui X
    // (Așa evităm problema zerourilor nesemnificative când C = 0)
    for (int len = 1; len < num_digits; ++len) {
        for (int first_digit = 1; first_digit <= 9; ++first_digit) {
            int current_C = (first_digit == C_digit) ? 1 : 0;
            total_valid += countWays(len - 1, K - current_C, C_digit);
        }
    }

    // 2. Numărăm valorile cu exact aceeași lungime ca a lui X, mergând pe prefixe
    int prefix_C_count = 0;
    for (int i = 0; i < num_digits; ++i) {
        int current_digit = s[i] - '0';

        // Prima cifră nu poate fi 0 dacă lungimea e aceeași
        int start_digit = (i == 0) ? 1 : 0;

        for (int d = start_digit; d < current_digit; ++d) {
            int extra_C = (d == C_digit) ? 1 : 0;
            total_valid += countWays(num_digits - 1 - i, K - (prefix_C_count + extra_C), C_digit);
        }

        if (current_digit == C_digit) {
            prefix_C_count++;
        }
    }

    // Verificăm dacă însuși numărul X este valid
    if (prefix_C_count >= K) {
        total_valid++;
    }

    // Cazul special pentru numărul 0 (deoarece bucla de lungimi pornește de la 1 cifră, dar prima cifră e setată de la 1..9)
    if (C_digit == 0 && K <= 1) {
        total_valid++; // Îl punem și pe 0 la socoteală
    } else if (C_digit != 0 && K == 0) {
        total_valid++;
    }

    return total_valid;
}

int main() {
    ifstream fin("cifre.in");
    ofstream fout("cifre.out");

    long long A, B;
    int C_digit, K;

    if (!(fin >> A >> B >> C_digit >> K)) return 0;

    precomputeCombinations();

    long long valid_B = countValid(B, C_digit, K);
    long long valid_A = countValid(A - 1, C_digit, K);
    long long total_valid = valid_B - valid_A;

    long long total_numbers = B - A + 1;
    double probability = (double)total_valid / total_numbers;

    fout << fixed << setprecision(4) << probability << "\n";

    return 0;
}