#include <fstream> #include <iostream> #include <cmath> #include <array> #include <string> #include <numeric> #ifdef PERR #include <cassert> #include "perr.h" #endif int const WYKLADNIK = 18; int cymnoz(int a, int b) { int wynik = a * b; while (10 <= wynik) { wynik = (wynik % 10) * (wynik / 10); } return wynik; } using cyfrozakres = std::array< long long, 10 >; cyfrozakres wstaw_z_przodu(int cyfra, cyfrozakres const& cz) { cyfrozakres ncz{}; for (int i = 0; i < 10; ++i) { int d = cymnoz(cyfra, i); ncz[d] += cz[i]; } return ncz; } cyfrozakres operator+(cyfrozakres const& cza, cyfrozakres const& czb) { cyfrozakres cz; for (int i = 0; i < 10; ++i) { cz[i] = cza[i] + czb[i]; } return cz; } struct Rozwiazanie { std::array< // potega std::array< // pierwsza cyfra cyfrozakres, 10 >, WYKLADNIK + 1 > pam{}; Rozwiazanie() { pam[0][0] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; pam[0][1] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}; pam[0][2] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}; pam[0][3] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; pam[0][4] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}; pam[0][5] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}; pam[0][6] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}; pam[0][7] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; pam[0][8] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}; pam[0][9] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; for (int wykl = 1; wykl <= WYKLADNIK; ++wykl) { // do WSZYSTKICH z poprzedniego kroku dopisuje kolejno 0, 1, 2, 3, ... 9 // czyli jesli mam 0 .. 9 to dostane // 00 .. 09 // 10 .. 19 // 20 .. 29 // 30 .. 39 // // zero tez - bo bedzie potrzebne w kolejnych krokach (np 00 -> 100) // trzeba potem poprawic - jak? for (int pierwsza = 0; pierwsza <= 9; ++pierwsza) { for (int poprzednia_pierwsza = 0; poprzednia_pierwsza <= 9; ++poprzednia_pierwsza) { pam[wykl][pierwsza] = pam[wykl][pierwsza] + wstaw_z_przodu(pierwsza, pam[wykl -1][poprzednia_pierwsza]); } #ifdef PERR long long potega = pow(10, wykl); assert(std::accumulate(pam[wykl][pierwsza].begin(), pam[wykl][pierwsza].end(), 0LL) == potega); #endif } } pam[0][0][0] = 0; for (int wykl = 1; wykl <= WYKLADNIK; ++wykl) { long long korekta_na_zera = std::pow(10LL, wykl); // tu zle pam[wykl][0][0] -= (korekta_na_zera - korekta_na_zera/10 +korekta_na_zera/100); } /* for (int i = 0; i < 10; ++i) { perr << " ?? " << i << " = " << pam[1][i]; } */ } }; cyfrozakres licz_pelny(Rozwiazanie const& r, long long zabawa) { cyfrozakres wynik{}; long long wykladnik = static_cast< long long >(std::log10(zabawa) + 1e-9); for (int wyk = 0; wyk < wykladnik; ++wyk) { for (int pc = 0; pc <= 9; ++pc) { wynik = wynik + r.pam[wyk][pc]; } } return wynik; } cyfrozakres licz_czesciowy(Rozwiazanie const& r, long long zabawa) { cyfrozakres wynik{}; if (zabawa < 10) { for (int i = 0; i <= zabawa; ++i) { wynik = wynik + r.pam[0][i]; } return wynik; } long long wykladnik = static_cast< long long >(std::log10(zabawa) + 1e-9); long long potega = std::pow(10, wykladnik); long long pierwsza_cyfra = zabawa / potega; for (int pc = 0; pc < pierwsza_cyfra; ++pc) { wynik = wynik + r.pam[wykladnik][pc]; } cyfrozakres koncowka = wstaw_z_przodu(pierwsza_cyfra, licz_czesciowy(r, zabawa % potega)); wynik = wynik + koncowka; return wynik; } cyfrozakres rozwiaz (Rozwiazanie const& r, long long zabawa) { cyfrozakres wynik = licz_pelny(r, zabawa) + licz_czesciowy(r, zabawa); return wynik; } int main() { Rozwiazanie r; std::istream& WEJ = std::cin; //std::ifstream WEJ("moj.in"); int ile_dni; WEJ >> ile_dni; for (int dzien = 0; dzien < ile_dni; ++dzien) { long long zabawa; WEJ >> zabawa; std::array< long long, 10 > wynik = rozwiaz(r, zabawa); for (int i = 0; i < 10; ++i) { std::string space = (i == 10) ? "" : " "; std::cout << wynik[i] << space; } std::cout << "\n"; } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | #include <fstream> #include <iostream> #include <cmath> #include <array> #include <string> #include <numeric> #ifdef PERR #include <cassert> #include "perr.h" #endif int const WYKLADNIK = 18; int cymnoz(int a, int b) { int wynik = a * b; while (10 <= wynik) { wynik = (wynik % 10) * (wynik / 10); } return wynik; } using cyfrozakres = std::array< long long, 10 >; cyfrozakres wstaw_z_przodu(int cyfra, cyfrozakres const& cz) { cyfrozakres ncz{}; for (int i = 0; i < 10; ++i) { int d = cymnoz(cyfra, i); ncz[d] += cz[i]; } return ncz; } cyfrozakres operator+(cyfrozakres const& cza, cyfrozakres const& czb) { cyfrozakres cz; for (int i = 0; i < 10; ++i) { cz[i] = cza[i] + czb[i]; } return cz; } struct Rozwiazanie { std::array< // potega std::array< // pierwsza cyfra cyfrozakres, 10 >, WYKLADNIK + 1 > pam{}; Rozwiazanie() { pam[0][0] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; pam[0][1] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0}; pam[0][2] = {0, 0, 1, 0, 0, 0, 0, 0, 0, 0}; pam[0][3] = {0, 0, 0, 1, 0, 0, 0, 0, 0, 0}; pam[0][4] = {0, 0, 0, 0, 1, 0, 0, 0, 0, 0}; pam[0][5] = {0, 0, 0, 0, 0, 1, 0, 0, 0, 0}; pam[0][6] = {0, 0, 0, 0, 0, 0, 1, 0, 0, 0}; pam[0][7] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; pam[0][8] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 0}; pam[0][9] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; for (int wykl = 1; wykl <= WYKLADNIK; ++wykl) { // do WSZYSTKICH z poprzedniego kroku dopisuje kolejno 0, 1, 2, 3, ... 9 // czyli jesli mam 0 .. 9 to dostane // 00 .. 09 // 10 .. 19 // 20 .. 29 // 30 .. 39 // // zero tez - bo bedzie potrzebne w kolejnych krokach (np 00 -> 100) // trzeba potem poprawic - jak? for (int pierwsza = 0; pierwsza <= 9; ++pierwsza) { for (int poprzednia_pierwsza = 0; poprzednia_pierwsza <= 9; ++poprzednia_pierwsza) { pam[wykl][pierwsza] = pam[wykl][pierwsza] + wstaw_z_przodu(pierwsza, pam[wykl -1][poprzednia_pierwsza]); } #ifdef PERR long long potega = pow(10, wykl); assert(std::accumulate(pam[wykl][pierwsza].begin(), pam[wykl][pierwsza].end(), 0LL) == potega); #endif } } pam[0][0][0] = 0; for (int wykl = 1; wykl <= WYKLADNIK; ++wykl) { long long korekta_na_zera = std::pow(10LL, wykl); // tu zle pam[wykl][0][0] -= (korekta_na_zera - korekta_na_zera/10 +korekta_na_zera/100); } /* for (int i = 0; i < 10; ++i) { perr << " ?? " << i << " = " << pam[1][i]; } */ } }; cyfrozakres licz_pelny(Rozwiazanie const& r, long long zabawa) { cyfrozakres wynik{}; long long wykladnik = static_cast< long long >(std::log10(zabawa) + 1e-9); for (int wyk = 0; wyk < wykladnik; ++wyk) { for (int pc = 0; pc <= 9; ++pc) { wynik = wynik + r.pam[wyk][pc]; } } return wynik; } cyfrozakres licz_czesciowy(Rozwiazanie const& r, long long zabawa) { cyfrozakres wynik{}; if (zabawa < 10) { for (int i = 0; i <= zabawa; ++i) { wynik = wynik + r.pam[0][i]; } return wynik; } long long wykladnik = static_cast< long long >(std::log10(zabawa) + 1e-9); long long potega = std::pow(10, wykladnik); long long pierwsza_cyfra = zabawa / potega; for (int pc = 0; pc < pierwsza_cyfra; ++pc) { wynik = wynik + r.pam[wykladnik][pc]; } cyfrozakres koncowka = wstaw_z_przodu(pierwsza_cyfra, licz_czesciowy(r, zabawa % potega)); wynik = wynik + koncowka; return wynik; } cyfrozakres rozwiaz (Rozwiazanie const& r, long long zabawa) { cyfrozakres wynik = licz_pelny(r, zabawa) + licz_czesciowy(r, zabawa); return wynik; } int main() { Rozwiazanie r; std::istream& WEJ = std::cin; //std::ifstream WEJ("moj.in"); int ile_dni; WEJ >> ile_dni; for (int dzien = 0; dzien < ile_dni; ++dzien) { long long zabawa; WEJ >> zabawa; std::array< long long, 10 > wynik = rozwiaz(r, zabawa); for (int i = 0; i < 10; ++i) { std::string space = (i == 10) ? "" : " "; std::cout << wynik[i] << space; } std::cout << "\n"; } }; |