fork download
  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. // Hàm trừ hai số lớn
  9. string subtractLargeNumbers(const string& num1, const string& num2) { // num1 >= num2
  10. string result; // Kết quả trừ
  11. int len1 = num1.size();
  12. int len2 = num2.size();
  13. int borrow = 0; // Biến lưu giá trị vay
  14.  
  15. // Đảo ngược chuỗi để dễ dàng trừ từ phải sang trái
  16. string n1 = string(num1.rbegin(), num1.rend());
  17. string n2 = string(num2.rbegin(), num2.rend());
  18.  
  19. for (int i = 0; i < len1; i++) {
  20. int digit1 = n1[i] - '0'; // Lấy chữ số từ num1
  21. int digit2 = (i < len2) ? (n2[i] - '0') : 0; // Lấy chữ số từ num2, nếu không có thì lấy 0
  22.  
  23. // Tính toán kết quả tại vị trí hiện tại
  24. int diff = digit1 - digit2 - borrow;
  25.  
  26. if (diff < 0) {
  27. diff += 10; // Thêm 10 nếu số trừ nhỏ hơn 0
  28. borrow = 1; // Thiết lập phần vay
  29. } else {
  30. borrow = 0; // Không còn vay
  31. }
  32.  
  33. result += to_string(diff); // Thêm chữ số vào kết quả
  34. }
  35.  
  36. // Đảo ngược lại kết quả để có thứ tự đúng
  37. reverse(result.begin(), result.end());
  38.  
  39. // Xóa các số 0 đứng trước nếu có
  40. while (result.size() > 1 && result[0] == '0') {
  41. result.erase(result.begin());
  42. }
  43.  
  44. return result.empty() ? "0" : result; // Nếu kết quả trống, trả về "0"
  45. }
  46.  
  47. // Hàm cộng hai số lớn
  48. string addLargeNumbers(const string& num1, const string& num2) {
  49. string result; // Kết quả cộng
  50. int carry = 0; // Biến lưu giá trị nhớ
  51. int len1 = num1.size();
  52. int len2 = num2.size();
  53. int maxLength = max(len1, len2);
  54.  
  55. // Đảo ngược chuỗi để cộng từ phải sang trái
  56. string n1 = string(num1.rbegin(), num1.rend());
  57. string n2 = string(num2.rbegin(), num2.rend());
  58.  
  59. for (int i = 0; i < maxLength; i++) {
  60. int digit1 = (i < len1) ? (n1[i] - '0') : 0; // Lấy chữ số của num1
  61. int digit2 = (i < len2) ? (n2[i] - '0') : 0; // Lấy chữ số của num2
  62.  
  63. int sum = digit1 + digit2 + carry; // Cộng các chữ số và carry
  64. carry = sum / 10; // Cập nhật giá trị carry
  65. result += to_string(sum % 10); // Thêm chữ số vào kết quả
  66. }
  67.  
  68. // Nếu còn carry thì thêm vào kết quả
  69. if (carry) {
  70. result += to_string(carry);
  71. }
  72.  
  73. // Đảo ngược lại kết quả để có thứ tự đúng
  74. reverse(result.begin(), result.end());
  75. return result;
  76. }
  77.  
  78. // Hàm nhân hai số lớn
  79. string multiplyLargeNumbers(const string& num1, const string& num2) {
  80. int len1 = num1.size();
  81. int len2 = num2.size();
  82.  
  83. // Kết quả có thể có tối đa len1 + len2 chữ số
  84. vector<int> result(len1 + len2, 0);
  85.  
  86. // Duyệt qua từng chữ số của num1 và num2
  87. for (int i = len1 - 1; i >= 0; i--) {
  88. for (int j = len2 - 1; j >= 0; j--) {
  89. int mul = (num1[i] - '0') * (num2[j] - '0'); // Nhân từng chữ số
  90. int sum = mul + result[i + j + 1]; // Cộng với kết quả đã có ở vị trí tương ứng
  91. result[i + j + 1] = sum % 10; // Lưu chữ số đơn vị
  92. result[i + j] += sum / 10; // Lưu chữ số hàng chục (nếu có)
  93. }
  94. }
  95.  
  96. // Chuyển kết quả từ mảng sang chuỗi
  97. string resultStr = "";
  98. for (int num : result) {
  99. if (!(resultStr.empty() && num == 0)) { // Bỏ qua các số 0 ở đầu
  100. resultStr += to_string(num);
  101. }
  102. }
  103.  
  104. return resultStr.empty() ? "0" : resultStr; // Nếu kết quả rỗng thì trả về "0"
  105. }
  106.  
  107. // Hàm đếm số lần xuất hiện của các chữ số từ 0 đến 9
  108. void countDigits(const string& N) {
  109. vector<string> digitCount(10, "0"); // Mảng lưu số lần xuất hiện của các chữ số từ 0 đến 9
  110. string factor = "1"; // Biến để xử lý từng vị trí chữ số
  111. int len = N.length();
  112.  
  113. // Xử lý từng vị trí chữ số từ phải sang trái (đơn vị trở lên)
  114. for (int i = len - 1; i >= 0; i--) {
  115. string lowerDigits = (i < len - 1) ? N.substr(i + 1) : "0"; // Các chữ số bên phải
  116. string higherDigits = (i > 0) ? N.substr(0, i) : "0"; // Các chữ số bên trái
  117.  
  118. // Tính số lần xuất hiện của các chữ số từ 0 đến 9 tại vị trí hiện tại
  119. for (int j = 0; j < 10; j++) {
  120. if (char(j + '0') < N[i]) {
  121. string temp = addLargeNumbers(higherDigits, "1");
  122. temp = multiplyLargeNumbers(temp, factor);
  123. digitCount[j] = addLargeNumbers(digitCount[j], temp);
  124. } else if (char(j + '0') == N[i]) {
  125. string temp = multiplyLargeNumbers(higherDigits, factor);
  126. temp = addLargeNumbers(temp, lowerDigits);
  127. temp = addLargeNumbers(temp, "1");
  128. digitCount[j] = addLargeNumbers(digitCount[j], temp);
  129. } else {
  130. string temp = multiplyLargeNumbers(higherDigits, factor);
  131. digitCount[j] = addLargeNumbers(digitCount[j], temp);
  132. }
  133. }
  134.  
  135. // Chữ số 0 không bao giờ xuất hiện ở vị trí đầu tiên
  136. digitCount[0] = subtractLargeNumbers(digitCount[0], factor);
  137.  
  138. factor = multiplyLargeNumbers(factor, "10"); // Chuyển sang vị trí tiếp theo
  139. }
  140.  
  141. // In ra kết quả
  142. for (int i = 0; i < 10; i++) {
  143. cout << "Digit " << i << ": " << digitCount[i] << endl;
  144. }
  145. }
  146.  
  147. int main() {
  148. string N;
  149. cin >> N;
  150.  
  151. countDigits(N);
  152.  
  153. return 0;
  154. }
  155.  
Success #stdin #stdout 0.01s 5276KB
stdin
123456
stdout
Digit 0: 58985
Digit 1: 93553
Digit 2: 63553
Digit 3: 59553
Digit 4: 59053
Digit 5: 58993
Digit 6: 58986
Digit 7: 58985
Digit 8: 58985
Digit 9: 58985