Advertisement
Galebickosikasa

Untitled

Jun 5th, 2021
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.20 KB | None | 0 0
  1. #include <cmath>
  2. #include <cstdint>
  3. #include <ctime>
  4. #include <exception>
  5. #include <iostream>
  6. #include <iterator>
  7. #include <memory>
  8. #include <numeric>
  9. #include <optional>
  10. #include <sstream>
  11. #include <string>
  12. #include <system_error>
  13. #include <type_traits>
  14. #include <unordered_map>
  15. #include <vector>
  16.  
  17. using namespace std;
  18.  
  19. template<typename It>
  20. class Range {
  21. public:
  22. Range(It begin, It end) : begin_(begin), end_(end) {}
  23. It begin() const { return begin_; }
  24. It end() const { return end_; }
  25. size_t size() const { return distance(begin_, end_); }
  26.  
  27. private:
  28. It begin_;
  29. It end_;
  30. };
  31.  
  32. pair<string_view, optional<string_view>> SplitTwoStrict(string_view s, string_view delimiter = " ") {
  33. const size_t pos = s.find(delimiter);
  34. if (pos == s.npos) {
  35. return {s, nullopt};
  36. } else {
  37. return {s.substr(0, pos), s.substr(pos + delimiter.length())};
  38. }
  39. }
  40.  
  41. pair<string_view, string_view> SplitTwo(string_view s, string_view delimiter = " ") {
  42. const auto [lhs, rhs_opt] = SplitTwoStrict(s, delimiter);
  43. return {lhs, rhs_opt.value_or("")};
  44. }
  45.  
  46. string_view ReadToken(string_view& s, string_view delimiter = " ") {
  47. const auto [lhs, rhs] = SplitTwo(s, delimiter);
  48. s = rhs;
  49. return lhs;
  50. }
  51.  
  52. int ConvertToInt(string_view str) {
  53. // use std::from_chars when available to get rid of string copy
  54. size_t pos;
  55. const int result = stoi(string(str), &pos);
  56. if (pos != str.length()) {
  57. std::stringstream error;
  58. error << "string " << str << " contains " << (str.length() - pos) << " trailing chars";
  59. throw invalid_argument(error.str());
  60. }
  61. return result;
  62. }
  63.  
  64. template <typename Number>
  65. void ValidateBounds(Number number_to_check, Number min_value, Number max_value) {
  66. if (number_to_check < min_value || number_to_check > max_value) {
  67. std::stringstream error;
  68. error << number_to_check << " is out of [" << min_value << ", " << max_value << "]";
  69. throw out_of_range(error.str());
  70. }
  71. }
  72.  
  73. struct MoneyState {
  74. double earned = 0.0;
  75. double spent = 0.0;
  76.  
  77. double ComputeIncome() const {
  78. return earned - spent;
  79. }
  80.  
  81. MoneyState& operator+=(const MoneyState& other) {
  82. earned += other.earned;
  83. spent += other.spent;
  84. return *this;
  85. }
  86.  
  87. MoneyState operator+(const MoneyState& other) const {
  88. return MoneyState(*this) += other;
  89. }
  90.  
  91. MoneyState operator*(double factor) const {
  92. return {earned * factor, spent * factor};
  93. }
  94. };
  95.  
  96. ostream& operator<<(ostream& stream, const MoneyState& state) {
  97. return stream << "{+" << state.earned << ", -" << state.spent << "}";
  98. }
  99.  
  100. struct IndexSegment {
  101. size_t left;
  102. size_t right;
  103.  
  104. size_t length() const {
  105. return right - left;
  106. }
  107. bool empty() const {
  108. return length() == 0;
  109. }
  110.  
  111. bool Contains(IndexSegment other) const {
  112. return left <= other.left && other.right <= right;
  113. }
  114. };
  115.  
  116.  
  117. class Date {
  118. public:
  119. static Date FromString(string_view str) {
  120. const int year = ConvertToInt(ReadToken(str, "-"));
  121. const int month = ConvertToInt(ReadToken(str, "-"));
  122. ValidateBounds(month, 1, 12);
  123. const int day = ConvertToInt(str);
  124. ValidateBounds(day, 1, 31);
  125. return {year, month, day};
  126. }
  127.  
  128. // Weird legacy, can't wait for std::chrono::year_month_day
  129. time_t AsTimestamp() const {
  130. std::tm t;
  131. t.tm_sec = 0;
  132. t.tm_min = 0;
  133. t.tm_hour = 0;
  134. t.tm_mday = day_;
  135. t.tm_mon = month_ - 1;
  136. t.tm_year = year_ - 1900;
  137. t.tm_isdst = 0;
  138. return mktime(&t);
  139. }
  140.  
  141. private:
  142. int year_;
  143. int month_;
  144. int day_;
  145.  
  146. Date(int year, int month, int day)
  147. : year_(year), month_(month), day_(day)
  148. {}
  149. };
  150.  
  151. int ComputeDaysDiff(const Date& date_to, const Date& date_from) {
  152. const time_t timestamp_to = date_to.AsTimestamp();
  153. const time_t timestamp_from = date_from.AsTimestamp();
  154. static constexpr int SECONDS_IN_DAY = 60 * 60 * 24;
  155. return (timestamp_to - timestamp_from) / SECONDS_IN_DAY;
  156. }
  157.  
  158. static const Date START_DATE = Date::FromString("2000-01-01");
  159. static const Date END_DATE = Date::FromString("2100-01-01");
  160. static const size_t DAY_COUNT = ComputeDaysDiff(END_DATE, START_DATE);
  161.  
  162. size_t ComputeDayIndex(const Date& date) {
  163. return ComputeDaysDiff(date, START_DATE);
  164. }
  165.  
  166. IndexSegment MakeDateSegment(const Date& date_from, const Date& date_to) {
  167. return {ComputeDayIndex(date_from), ComputeDayIndex(date_to) + 1};
  168. }
  169.  
  170.  
  171. class BudgetManager : public vector<MoneyState> {
  172. public:
  173. BudgetManager() : vector(DAY_COUNT) {}
  174. auto MakeDateRange(const Date& date_from, const Date& date_to) const {
  175. const auto segment = MakeDateSegment(date_from, date_to);
  176. return Range(begin() + segment.left, begin() + segment.right);
  177. }
  178. auto MakeDateRange(const Date& date_from, const Date& date_to) {
  179. const auto segment = MakeDateSegment(date_from, date_to);
  180. return Range(begin() + segment.left, begin() + segment.right);
  181. }
  182. };
  183.  
  184.  
  185. struct Request;
  186. using RequestHolder = unique_ptr<Request>;
  187.  
  188. struct Request {
  189. enum class Type {
  190. COMPUTE_INCOME,
  191. EARN,
  192. SPEND,
  193. PAY_TAX
  194. };
  195.  
  196. Request(Type type) : type(type) {}
  197. static RequestHolder Create(Type type);
  198. virtual void ParseFrom(string_view input) = 0;
  199. virtual ~Request() = default;
  200.  
  201. const Type type;
  202. };
  203.  
  204. const unordered_map<string_view, Request::Type> STR_TO_REQUEST_TYPE = {
  205. {"ComputeIncome", Request::Type::COMPUTE_INCOME},
  206. {"Earn", Request::Type::EARN},
  207. {"Spend", Request::Type::SPEND},
  208. {"PayTax", Request::Type::PAY_TAX},
  209. };
  210.  
  211. template <typename ResultType>
  212. struct ReadRequest : Request {
  213. using Request::Request;
  214. virtual ResultType Process(const BudgetManager& manager) const = 0;
  215. };
  216.  
  217. struct ModifyRequest : Request {
  218. using Request::Request;
  219. virtual void Process(BudgetManager& manager) const = 0;
  220. };
  221.  
  222. struct ComputeIncomeRequest : ReadRequest<double> {
  223. ComputeIncomeRequest() : ReadRequest(Type::COMPUTE_INCOME) {}
  224. void ParseFrom(string_view input) override {
  225. date_from = Date::FromString(ReadToken(input));
  226. date_to = Date::FromString(input);
  227. }
  228.  
  229. double Process(const BudgetManager& manager) const override {
  230. const auto range = manager.MakeDateRange(date_from, date_to);
  231. return accumulate(begin(range), end(range), MoneyState{}).ComputeIncome();
  232. }
  233.  
  234. Date date_from = START_DATE;
  235. Date date_to = START_DATE;
  236. };
  237.  
  238. template <int SIGN>
  239. struct AddMoneyRequest : ModifyRequest {
  240. static_assert(SIGN == -1 || SIGN == 1);
  241.  
  242. AddMoneyRequest() : ModifyRequest(SIGN == 1 ? Type::EARN : Type::SPEND) {}
  243. void ParseFrom(string_view input) override {
  244. date_from = Date::FromString(ReadToken(input));
  245. date_to = Date::FromString(ReadToken(input));
  246. value = ConvertToInt(input);
  247. }
  248.  
  249. void Process(BudgetManager& manager) const override {
  250. const auto date_range = manager.MakeDateRange(date_from, date_to);
  251. const double daily_value = value * 1.0 / size(date_range);
  252. const MoneyState daily_change =
  253. SIGN == 1
  254. ? MoneyState{.earned = daily_value}
  255. : MoneyState{.spent = daily_value};
  256. for (auto& money : date_range) {
  257. money += daily_change;
  258. }
  259. }
  260.  
  261. Date date_from = START_DATE;
  262. Date date_to = START_DATE;
  263. size_t value = 0;
  264. };
  265.  
  266. struct PayTaxRequest : ModifyRequest {
  267. PayTaxRequest() : ModifyRequest(Type::PAY_TAX) {}
  268. void ParseFrom(string_view input) override {
  269. date_from = Date::FromString(ReadToken(input));
  270. date_to = Date::FromString(ReadToken(input));
  271. percentage = ConvertToInt(input);
  272. }
  273.  
  274. void Process(BudgetManager& manager) const override {
  275. for (auto& money : manager.MakeDateRange(date_from, date_to)) {
  276. money.earned *= 1 - percentage / 100.0;
  277. }
  278. }
  279.  
  280. Date date_from = START_DATE;
  281. Date date_to = START_DATE;
  282. uint8_t percentage = 0;
  283. };
  284.  
  285. RequestHolder Request::Create(Request::Type type) {
  286. switch (type) {
  287. case Request::Type::COMPUTE_INCOME:
  288. return make_unique<ComputeIncomeRequest>();
  289. case Request::Type::EARN:
  290. return make_unique<AddMoneyRequest<+1>>();
  291. case Request::Type::SPEND:
  292. return make_unique<AddMoneyRequest<-1>>();
  293. case Request::Type::PAY_TAX:
  294. return make_unique<PayTaxRequest>();
  295. default:
  296. return nullptr;
  297. }
  298. }
  299.  
  300. template <typename Number>
  301. Number ReadNumberOnLine(istream& stream) {
  302. Number number;
  303. stream >> number;
  304. string dummy;
  305. getline(stream, dummy);
  306. return number;
  307. }
  308.  
  309. optional<Request::Type> ConvertRequestTypeFromString(string_view type_str) {
  310. if (const auto it = STR_TO_REQUEST_TYPE.find(type_str);
  311. it != STR_TO_REQUEST_TYPE.end()) {
  312. return it->second;
  313. } else {
  314. return nullopt;
  315. }
  316. }
  317.  
  318. RequestHolder ParseRequest(string_view request_str) {
  319. const auto request_type = ConvertRequestTypeFromString(ReadToken(request_str));
  320. if (!request_type) {
  321. return nullptr;
  322. }
  323. RequestHolder request = Request::Create(*request_type);
  324. if (request) {
  325. request->ParseFrom(request_str);
  326. };
  327. return request;
  328. }
  329.  
  330. vector<RequestHolder> ReadRequests(istream& in_stream = cin) {
  331. const size_t request_count = ReadNumberOnLine<size_t>(in_stream);
  332.  
  333. vector<RequestHolder> requests;
  334. requests.reserve(request_count);
  335.  
  336. for (size_t i = 0; i < request_count; ++i) {
  337. string request_str;
  338. getline(in_stream, request_str);
  339. if (auto request = ParseRequest(request_str)) {
  340. requests.push_back(move(request));
  341. }
  342. }
  343. return requests;
  344. }
  345.  
  346. vector<double> ProcessRequests(const vector<RequestHolder>& requests) {
  347. vector<double> responses;
  348. BudgetManager manager;
  349. for (const auto& request_holder : requests) {
  350. if (request_holder->type == Request::Type::COMPUTE_INCOME) {
  351. const auto& request = static_cast<const ComputeIncomeRequest&>(*request_holder);
  352. responses.push_back(request.Process(manager));
  353. } else {
  354. const auto& request = static_cast<const ModifyRequest&>(*request_holder);
  355. request.Process(manager);
  356. }
  357. }
  358. return responses;
  359. }
  360.  
  361. void PrintResponses(const vector<double>& responses, ostream& stream = cout) {
  362. for (const double response : responses) {
  363. stream << response << endl;
  364. }
  365. }
  366.  
  367.  
  368. int main() {
  369. cout.precision(25);
  370. const auto requests = ReadRequests();
  371. const auto responses = ProcessRequests(requests);
  372. PrintResponses(responses);
  373.  
  374. return 0;
  375. }
  376.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement