Pagini recente » Monitorul de evaluare | Cod sursa (job #3357158)
#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;
}