#include <iostream> #include <vector> #include <cassert> static const int BASE = 10; class BigNumber; bool incrementWithCarryHelper(std::vector<int> &digits) { bool carry = true; for (int i = (int)digits.size() - 1; i >= 0 && carry; --i) { if (++digits[i] == BASE) digits[i] = 0; else carry = false; } return carry; } std::vector<int> toDigitsVec(const std::string &num) { std::vector<int> ret; for (int i = 0; i < (int)num.size(); ++i) ret.push_back(num[i] - '0'); return ret; } class BigNumber { public: void increment() { bool carry = incrementWithCarryHelper(this->trailingDigits); if (carry && this->zerosInTheMiddle > 0) { --this->zerosInTheMiddle; this->trailingDigits.insert(this->trailingDigits.begin(), 1); carry = false; } if (carry) carry = incrementWithCarryHelper(this->leadingDigits); if (carry) this->leadingDigits.insert(this->leadingDigits.begin(), 1); } int totalDigits() const { return this->leadingDigits.size() + this->zerosInTheMiddle + this->trailingDigits.size(); } int digitAt(int idx) const { if (idx < this->leadingDigits.size()) return this->leadingDigits[idx]; idx -= this->leadingDigits.size(); if (idx < this->zerosInTheMiddle) return 0; idx -= this->zerosInTheMiddle; if (idx < this->trailingDigits.size()) return this->trailingDigits[idx]; assert(false); } BigNumber(const std::vector<int> &leadingDigits, int zeros): leadingDigits(leadingDigits), trailingDigits(), zerosInTheMiddle(zeros) { } private: std::vector<int> leadingDigits; std::vector<int> trailingDigits; int zerosInTheMiddle; friend std::ostream &operator<<(std::ostream &out, const BigNumber &bigNumber); }; void printDigits(std::ostream &out, const std::vector<int> &digits) { for (int i = 0; i < (int)digits.size(); ++i) out << char(digits[i] + '0'); } std::ostream &operator<<(std::ostream &out, const BigNumber &bigNumber) { printDigits(out, bigNumber.leadingDigits); for (int i = 0; i < bigNumber.zerosInTheMiddle; ++i) out << '0'; printDigits(out, bigNumber.trailingDigits); return out; } int comparePrefix(const BigNumber &first, const std::vector<int> &second) { assert((int)second.size() <= first.totalDigits()); for (int i = 0; i < (int)second.size(); ++i) { if (second[i] > first.digitAt(i)) return 1; if (second[i] < first.digitAt(i)) return -1; } return 0; } bool isPrefixOf(const std::vector<int> &prefix, const BigNumber &bigNumber) { if ((int)prefix.size() > bigNumber.totalDigits()) return false; return comparePrefix(bigNumber, prefix) == 0; } std::vector<int> readDigitsVec() { std::string str; std::cin >> str; return toDigitsVec(str); } int main() { int n; std::cin >> n; assert(n >= 1); std::vector<int> currentNum = readDigitsVec(); BigNumber previousFilled(currentNum, 0); long long totalNumFilled = 0; for (int i = 1; i < n; ++i) { currentNum = readDigitsVec(); if ((int)currentNum.size() > previousFilled.totalDigits()) { // easy case: nothing to fill previousFilled = BigNumber(currentNum, 0); } else { const int compareResult = comparePrefix(previousFilled, currentNum); if (compareResult > 0) { // fill with zeros up to previous length const int numZerosToFill = previousFilled.totalDigits() - (int)currentNum.size(); previousFilled = BigNumber(currentNum, numZerosToFill); } else if (compareResult < 0) { // similar case, but we have to add one extra digit const int numZerosToFill = previousFilled.totalDigits() - (int)currentNum.size() + 1; previousFilled = BigNumber(currentNum, numZerosToFill); } else { // try to take previous number incremented, but we have to make sure the result may be constructed by // appending some digits to current - it must be a prefix BigNumber candidate(previousFilled); candidate.increment(); if (isPrefixOf(currentNum, candidate)) { previousFilled = candidate; } else { const int numZerosToFill = previousFilled.totalDigits() - (int)currentNum.size() + 1; previousFilled = BigNumber(currentNum, numZerosToFill); } } } totalNumFilled += previousFilled.totalDigits() - (int)currentNum.size(); // DEBUG //std::cout << "filling "; //printDigits(std::cout, currentNum); //std::cout << " -> " << previousFilled << ", totalNumFilled=" << totalNumFilled << std::endl; } std::cout << totalNumFilled << std::endl; return 0; }
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 | #include <iostream> #include <vector> #include <cassert> static const int BASE = 10; class BigNumber; bool incrementWithCarryHelper(std::vector<int> &digits) { bool carry = true; for (int i = (int)digits.size() - 1; i >= 0 && carry; --i) { if (++digits[i] == BASE) digits[i] = 0; else carry = false; } return carry; } std::vector<int> toDigitsVec(const std::string &num) { std::vector<int> ret; for (int i = 0; i < (int)num.size(); ++i) ret.push_back(num[i] - '0'); return ret; } class BigNumber { public: void increment() { bool carry = incrementWithCarryHelper(this->trailingDigits); if (carry && this->zerosInTheMiddle > 0) { --this->zerosInTheMiddle; this->trailingDigits.insert(this->trailingDigits.begin(), 1); carry = false; } if (carry) carry = incrementWithCarryHelper(this->leadingDigits); if (carry) this->leadingDigits.insert(this->leadingDigits.begin(), 1); } int totalDigits() const { return this->leadingDigits.size() + this->zerosInTheMiddle + this->trailingDigits.size(); } int digitAt(int idx) const { if (idx < this->leadingDigits.size()) return this->leadingDigits[idx]; idx -= this->leadingDigits.size(); if (idx < this->zerosInTheMiddle) return 0; idx -= this->zerosInTheMiddle; if (idx < this->trailingDigits.size()) return this->trailingDigits[idx]; assert(false); } BigNumber(const std::vector<int> &leadingDigits, int zeros): leadingDigits(leadingDigits), trailingDigits(), zerosInTheMiddle(zeros) { } private: std::vector<int> leadingDigits; std::vector<int> trailingDigits; int zerosInTheMiddle; friend std::ostream &operator<<(std::ostream &out, const BigNumber &bigNumber); }; void printDigits(std::ostream &out, const std::vector<int> &digits) { for (int i = 0; i < (int)digits.size(); ++i) out << char(digits[i] + '0'); } std::ostream &operator<<(std::ostream &out, const BigNumber &bigNumber) { printDigits(out, bigNumber.leadingDigits); for (int i = 0; i < bigNumber.zerosInTheMiddle; ++i) out << '0'; printDigits(out, bigNumber.trailingDigits); return out; } int comparePrefix(const BigNumber &first, const std::vector<int> &second) { assert((int)second.size() <= first.totalDigits()); for (int i = 0; i < (int)second.size(); ++i) { if (second[i] > first.digitAt(i)) return 1; if (second[i] < first.digitAt(i)) return -1; } return 0; } bool isPrefixOf(const std::vector<int> &prefix, const BigNumber &bigNumber) { if ((int)prefix.size() > bigNumber.totalDigits()) return false; return comparePrefix(bigNumber, prefix) == 0; } std::vector<int> readDigitsVec() { std::string str; std::cin >> str; return toDigitsVec(str); } int main() { int n; std::cin >> n; assert(n >= 1); std::vector<int> currentNum = readDigitsVec(); BigNumber previousFilled(currentNum, 0); long long totalNumFilled = 0; for (int i = 1; i < n; ++i) { currentNum = readDigitsVec(); if ((int)currentNum.size() > previousFilled.totalDigits()) { // easy case: nothing to fill previousFilled = BigNumber(currentNum, 0); } else { const int compareResult = comparePrefix(previousFilled, currentNum); if (compareResult > 0) { // fill with zeros up to previous length const int numZerosToFill = previousFilled.totalDigits() - (int)currentNum.size(); previousFilled = BigNumber(currentNum, numZerosToFill); } else if (compareResult < 0) { // similar case, but we have to add one extra digit const int numZerosToFill = previousFilled.totalDigits() - (int)currentNum.size() + 1; previousFilled = BigNumber(currentNum, numZerosToFill); } else { // try to take previous number incremented, but we have to make sure the result may be constructed by // appending some digits to current - it must be a prefix BigNumber candidate(previousFilled); candidate.increment(); if (isPrefixOf(currentNum, candidate)) { previousFilled = candidate; } else { const int numZerosToFill = previousFilled.totalDigits() - (int)currentNum.size() + 1; previousFilled = BigNumber(currentNum, numZerosToFill); } } } totalNumFilled += previousFilled.totalDigits() - (int)currentNum.size(); // DEBUG //std::cout << "filling "; //printDigits(std::cout, currentNum); //std::cout << " -> " << previousFilled << ", totalNumFilled=" << totalNumFilled << std::endl; } std::cout << totalNumFilled << std::endl; return 0; } |