Informatică, întrebare adresată de ionutg38, 9 ani în urmă

Numerele naturale nenule se scriu într-un şir astfel: 12345678910111213141516.... Fiind date n perechi de poziţii din şir de forma (p,q), cu p≤q, să se calculeze suma cifrelor din şir situate pe poziţiile de la p la q.

Date de intrare
Fișierul de intrare sumo.in conține pe prima linie numărul n, iar pe următoarele n linii câte o pereche de numere naturale (p,q), numere naturale separate prin spații.

Date de ieșire
Fișierul de ieșire sumo.out va conține pe fiecare linie de la 1 la n câte un număr reprezentând suma cifrelor din şir corespunzătoare fiecărei perechi (p,q) din fişierul de intrare.

Restricții și precizări
1 ≤ n ≤ 100.000
1 ≤ p ≤ q ≤ 2.000.000.000



Exemplu
sumo.in

3
1 5
7 18
22 26
sumo.out

15
35
16
Explicație
De la poziţia 1 la 5 avem cifrele 12345 iar suma lor este 15, de la poziţia 7 la 18 avem cifrele 789101112131 iar suma lor este 35, iar de la poziţia 22 la 26 avem cifrele 16171 iar suma lor este 16.
Exemplul 2
sumo.in
20
26 79
50 150
44 77
46 94
44 71
43 98
7 130
37 141
21 89
49 151
8 95
36 138
23 71
49 63
32 105
14 138
35 101
28 75
34 118
21 86

sumo.out
189
483
127
197
109
227
511
471
264
492
315
457
177
51
291
518
263
165
351
243

Răspunsuri la întrebare

Răspuns de blindseeker90
4
#include <iostream>
#include <fstream>
using namespace std;

struct numar_prop{
int numar_curent;
int pozitie_curenta;
int nr_cifre;
};


struct numar_prop cifra_curenta(int n){
struct numar_prop np;
int rez=0,nr_cifre=1,nr_numere=9;
while(n>=nr_numere*nr_cifre){
n=n-nr_numere*nr_cifre;
rez=rez+nr_numere;
nr_numere=nr_numere*10;
nr_cifre++;
}
np.numar_curent=n/nr_cifre;
np.pozitie_curenta=n%nr_cifre;
if(np.pozitie_curenta==0){
np.pozitie_curenta=nr_cifre;
}
else{
np.numar_curent++;
}
np.numar_curent=np.numar_curent+rez;
np.nr_cifre=nr_cifre;
return np;

}

int obtine_nr_cifre(int n){
int nr_cifre=0;;
while(n>0){
n=n/10;
nr_cifre++;
}
return nr_cifre;
}
//poz este pozitia de la care incepe suma de cifre
//este numerotata de la 1 la nr_cifre
//dir da directia de adunare a cifrelor: dir=0, dreapta stanga, dir=1, stanga dreapta
int suma_cifre(int n,int nr_cifre,int poz,int dir){
int s=0,poz_ocupate=0;
if(dir==0){
while(poz_ocupate<nr_cifre-poz+1){
s=s+n%10;
n=n/10;
poz_ocupate++;
}
}
else{
while(n>0){
if(poz_ocupate>nr_cifre-poz-1){
s=s+n%10;
}
n=n/10;
poz_ocupate++;
}
}

return s;
}
int suma_cifre_interval(int p,int q){
struct numar_prop np_p,np_q;
int i,s=0;
np_p=cifra_curenta(p);
np_q=cifra_curenta(q);
s=s+suma_cifre(np_p.numar_curent,np_p.nr_cifre,np_p.pozitie_curenta,0);

for(i=np_p.numar_curent+1;i<np_q.numar_curent;i++){
s=s+suma_cifre(i,obtine_nr_cifre(i),1,0);
}
s=s+suma_cifre(np_q.numar_curent,np_q.nr_cifre,np_q.pozitie_curenta,1);
return s;
}
int main(){    
    int n,i; 
    ifstream fis("sumo.in");
    ofstream fos("sumo.out");
fis>>n;
    int p[n],q[n];
for(i=0;i<n;i++){
     fis>>p[i]>>q[i];
     fos<<suma_cifre_interval(p[i],q[i])<<endl;
}
 
return 0;
}

ionutg38: Multumesc! Trebuie doar sa optimizez algoritmul pentru ca la jumatate din teste depaseste limita de timp.
ionutg38: Indicatiile pentru rezolvare sunt urmatoarele:
ionutg38: Pentru fiecare pereche (p,q) se caută numărul x a cărui cifră este pe poziţia p şi numărul y a cărui cifră este pe poziţia q. Se află suma cifrelor numerelor de la 1 la x şi de la 1 la y, iar prin scădere se află suma cifrelor din secvenţa de numere de la x+1 la y, ajustând această sumă cu cifrele din x şi y care sunt sau nu între poziţiile p şi q.
blindseeker90: Da asa e. Ce prostovan am fost. Cred ca iti dai seama cum trebuie sa-l ajustezi. Eu iau toate numerele de la p la q succesiv si le calculez suma cifrelor.
ionutg38: Si mie mi se intampla des sa fac asa. Oricum iti multumesc!
ionutg38: Poti sa-l ajustezi si sa-mi trimiti? [email protected]
ionutg38: Am inteles rezolvarea dar m-as cam incurca daca incerc sa-l ajustez eu.
Alte întrebări interesante