Cod sursa(job #980277)

Utilizator vendettaSalajan Razvan vendetta Data 4 august 2013 14:40:08
Problema Cifre Scor 60
Compilator cpp Status done
Runda Arhiva de probleme Marime 3.5 kb
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>

using namespace std;

ifstream f("cifre.in");
ofstream g("cifre.out");

#define Cifmax 12

int cifra[Cifmax];
int dp[Cifmax][Cifmax];
int A, B, C, K;

void citeste(){
    f >> A >> B >> C >> K;
}

void desc(int X){
    int x2 = X; int cnt = 0;
    for(; x2!=0; x2/=10){
        ++cnt;
    }
    for(int i=cnt; X!=0; --i){
        cifra[i] = X % 10; X /= 10;
    }
    cifra[0] = cnt;

    //for(int i=0; i<=cifra[0]; ++i) cout << cifra[i] << " "; cout << "\n";
}

void faDinamica(int tip){
    for(int i=0; i<Cifmax; ++i){
        for(int j=0; j<Cifmax; ++j) dp[i][j] = 0;
    }

    if (tip > 0){// iau in considerare
        if (C != 0){
            dp[1][1] = 1;
            dp[1][0] = 8; // mai raman opt numere care nu contin cifra C ( pe 0 nu il pot pune)
        }else {// e chiara 0 cifra cautata => nu il pot puine => dp[1][0] = 9;
            dp[1][0] = 9;
        }
    }else {// pot pune 0 de la inceput
        dp[1][1] = 1;
        dp[1][0] = 9; // mai raman 9 numare ( ca l-am scos pe ala care il contine pe C);
    }
    for(int i=2; i<cifra[0]; ++i){
        for(int j=0; j<i; ++j){// o cifra poate aparea maxim de i-1 ori pt ca lungimea acum e abia i
            dp[i][j] += (dp[i-1][j] * 9); // adica la numerele cu j cifre de tipul C pun cifre care nu sunt la fel cu C
            dp[i][j+1] += dp[i-1][j];
        }
    }
}

void baga(int poz, int cnt, int &Rez){
    // cnt = de cate ori apare cifra C in numarul X de la inceput pana la a poz-a cifra(fara poz)
    if (poz == cifra[0]){
        if (cnt >= K) Rez += cifra[poz] + 1;// adica acum le pot pune pe toate
        else if (cnt + 1 == K && C <= cifra[poz]) Rez += 1;// cnda pun chiar C
        return;
    }
    if (C == 0 && poz == 1) baga(poz+1, cnt, Rez);// nu am ce face nu am voie sa il pun pe 0
    int deUnde = 0;
    if (poz == 1) deUnde = 1;
    for(int i=deUnde; i<cifra[poz]; ++i){// pun cifra i
        if (i == C){
            for(int j=K-1-cnt; j<Cifmax; ++j) Rez += dp[cifra[0]-poz][j];
        }else {
            for(int j=K-cnt; j<Cifmax; ++j) Rez += dp[cifra[0]-poz][j];
        }
    }
    if (cifra[poz] == C) baga(poz+1, cnt+1, Rez);
    else baga(poz+1, cnt, Rez);
}

int rezolva(int X){
    if (X < 10 && C <= X) return 1;
    if (X < 10) return 0;
    // dp[i][j] = numarul de numere de lungime i care au cifra C de j ori
    // afla(B) - afla(A-1)
    // odata le numar pe alea de lungimea < decat lungimea numarului curent
    // iar apoi cand le numar pe alea de lungime = lungimea numarului o sa am nevoie de aceeasi dinamica doar ca in asta nu o sa fiu atent
    // la cazul cand primda pun 0
    desc(X); // fac un vector cifra[] in care am puse cifrele lui X; iar in cifra[0] = cate cifre are X
    int Rez = 0;
    faDinamica(1);// cazul cand iau in considerare cazul cu 1
    for(int i=1; i<cifra[0]; ++i){
        for(int j=K; j<Cifmax; ++j) Rez += dp[i][j];// lungime i si cifra C apare de j ori (j >= K);
    }
    //cout << Rez << "\n";
    faDinamica(0);// cazul cand nu iau in considerare cazul cu 0
    // acum le numar pe alea de aceeasi lungime cu X
    baga(1, 0, Rez);
    //cout << Rez << "\n";
    return Rez;
}

int main(){
    citeste();
    int cazFavor = rezolva(B) - rezolva(A-1);
    int cazTotale = B - A + 1;
    g << fixed << setprecision(4) << (double)cazFavor / (double)cazTotale << "\n";
    //rezolva(B);

    f.close();
    g.close();

    return 0;
}