You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

274 lines
6.7 KiB

  1. #include <algorithm>
  2. #include <chrono>
  3. #include <deque>
  4. #include <functional>
  5. #include <iomanip>
  6. #include <iostream>
  7. #include <sstream>
  8. #include <vector>
  9. #define MAXNUM 4000001
  10. class Date {
  11. std::string date;
  12. int year, month, day, total;
  13. void dateToInt() {
  14. year = stoi(date.substr(0, 4));
  15. month = stoi(date.substr(5, 2));
  16. day = stoi(date.substr(8, 2));
  17. total = year * 400 + month * 31 + day;
  18. }
  19. public:
  20. Date() {
  21. date = "1970-01-01";
  22. dateToInt();
  23. }
  24. explicit Date(const std::string &d) {
  25. date = d;
  26. dateToInt();
  27. }
  28. Date(const Date &d) {
  29. date = d.date, year = d.year, month = d.month, day = d.day,
  30. total = d.total;
  31. }
  32. Date(Date &&d) {
  33. date = std::move(d.date);
  34. year = d.year, month = d.month, day = d.day, total = d.total;
  35. }
  36. Date &operator=(Date d) {
  37. date = d.date, year = d.year, month = d.month, day = d.day,
  38. total = d.total;
  39. return *this;
  40. }
  41. bool isLeap(int year) {
  42. if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) return true;
  43. return false;
  44. }
  45. int maxDay(int month, int year) {
  46. switch (month) {
  47. case 4:
  48. case 6:
  49. case 9:
  50. case 11:
  51. return 30;
  52. break;
  53. case 2:
  54. return (isLeap(year) ? 29 : 28);
  55. break;
  56. default:
  57. return 31;
  58. }
  59. }
  60. std::string getDate() { return date; }
  61. int getTotal() { return total; }
  62. void goNextDay() {
  63. day++;
  64. if (day > maxDay(month, year)) day = 1, month++;
  65. if (month > 12) month = 1, year++;
  66. total = year * 400 + month * 31 + day;
  67. std::stringstream yearss, monthss, dayss;
  68. yearss << std::setfill('0') << std::setw(4) << year;
  69. monthss << std::setfill('0') << std::setw(2) << month;
  70. dayss << std::setfill('0') << std::setw(2) << day;
  71. date = yearss.str() + "-" + monthss.str() + "-" + dayss.str();
  72. }
  73. // prefix ++ operator for getting the next day
  74. Date &operator++() {
  75. goNextDay();
  76. return *this;
  77. }
  78. Date operator++(int) {
  79. Date res(*this);
  80. goNextDay();
  81. return res;
  82. }
  83. operator int() const { return total; }
  84. };
  85. class Transaction {
  86. public:
  87. Date date;
  88. double money;
  89. operator int() { return int(date); }
  90. };
  91. // countingsort. Linear complexity. Works only for whole numbers, but can be
  92. // modified to work with negative integers as well. It is perfect for the task,
  93. // since it allows to sort the numbers and to not corrupt the initial order
  94. template <typename T>
  95. void countingsort(T arr[], size_t n) {
  96. int c[MAXNUM];
  97. T temp[n + 1];
  98. std::fill(c, c + MAXNUM, 0);
  99. for (size_t i = 0; i < n; ++i) c[(arr[i])]++;
  100. for (size_t i = 1; i < MAXNUM; ++i) c[i] += c[i - 1];
  101. for (size_t i = n; i-- > 0;) {
  102. temp[c[int(arr[i])]] = arr[i];
  103. c[int(arr[i])]--;
  104. }
  105. for (size_t i = 0; i < n; ++i) {
  106. arr[i] = temp[i + 1];
  107. }
  108. }
  109. // merge sort. time complexity O(n*logn) in the worst case
  110. template <typename T>
  111. void mergesortlr(T arr[], size_t l, size_t r) {
  112. if (r - l < 2 || r < l) return;
  113. size_t m = (l + r) / 2;
  114. mergesortlr<T>(arr, l, m);
  115. mergesortlr<T>(arr, m, r);
  116. size_t i = 0, j = 0, k = 0;
  117. T temp[r - l];
  118. while (i < m - l && j < r - m) {
  119. if (arr[l + i] < arr[m + j])
  120. temp[k++] = arr[l + i++];
  121. else
  122. temp[k++] = arr[m + j++];
  123. }
  124. while (i < m - l) temp[k++] = arr[l + i++];
  125. while (j < r - m) temp[k++] = arr[m + j++];
  126. for (size_t i = l; i < r; ++i) arr[i] = temp[i - l];
  127. }
  128. template <typename T>
  129. void mergesort(T arr[], size_t sz) {
  130. mergesortlr<T>(arr, 0, sz);
  131. }
  132. // test a sorting function
  133. template <typename T>
  134. void testsort(std::function<void(T arr[], size_t sz)> test, size_t sz) {
  135. srand(time(NULL));
  136. int a[sz], b[sz];
  137. for (size_t i = 0; i < sz; ++i) a[i] = b[i] = rand() % 30000;
  138. using std::chrono::duration;
  139. using std::chrono::duration_cast;
  140. using std::chrono::high_resolution_clock;
  141. using std::chrono::milliseconds;
  142. // executing test sort
  143. auto t1 = high_resolution_clock::now();
  144. test(a, sz);
  145. auto t2 = high_resolution_clock::now();
  146. auto ms_int = duration_cast<milliseconds>(t2 - t1);
  147. std::cout << "Test sort time: " << ms_int.count() << "ms\n";
  148. // executing std::sort
  149. t1 = high_resolution_clock::now();
  150. std::sort(b, b + sz);
  151. t2 = high_resolution_clock::now();
  152. ms_int = duration_cast<milliseconds>(t2 - t1);
  153. std::cout << "std::sort time: " << ms_int.count() << "ms\n";
  154. // Checking correctness of the test sort
  155. bool correct = 1;
  156. for (size_t i = 0; i < sz; ++i) {
  157. if (a[i] != b[i]) {
  158. correct = 0;
  159. break;
  160. }
  161. }
  162. if (correct)
  163. std::cout << "Test sort works properly...\n";
  164. else
  165. std::cout << "Test sort failed...\n";
  166. }
  167. int main() {
  168. #ifdef DEBUG
  169. std::cout << "Testing countingsort:\n";
  170. testsort<int>(&mergesort<int>, 10000);
  171. std::cout << "\nTesting countingsort:\n";
  172. testsort<int>(&countingsort<int>, 10000);
  173. Date feb("2020-02-01"), mar("2020-03-10");
  174. while (feb != mar) {
  175. std::cout << feb.getDate() << '\n';
  176. feb++;
  177. }
  178. #endif
  179. size_t n, d;
  180. std::cin >> n >> d;
  181. Transaction transactions[n];
  182. for (size_t i = 0; i < n; ++i) {
  183. std::string datestr;
  184. char c;
  185. double money;
  186. std::cin >> datestr >> c >> money;
  187. transactions[i].date = Date(datestr);
  188. transactions[i].money = money;
  189. }
  190. countingsort(transactions, n);
  191. #ifdef DEBUG
  192. for (size_t i = 0; i < n; ++i)
  193. std::cout << transactions[i].date.getDate() << ' '
  194. << transactions[i].money << '\n';
  195. #endif
  196. int ans = 0;
  197. // median
  198. double mid = 0;
  199. // using deque as a queue to iterate through it efficiently
  200. std::deque<double> q;
  201. Date today(transactions[0].date);
  202. for (size_t i = 0; i < n; ++today) {
  203. double sum = 0;
  204. while (transactions[i].date.getTotal() <= today.getTotal()) {
  205. sum += transactions[i++].money;
  206. if (sum >= mid * 2.0 && q.size() == d) ans++;
  207. if (i >= n)
  208. break;
  209. }
  210. q.push_back(sum);
  211. if (q.size() > d) q.pop_front();
  212. std::vector<double> v;
  213. for (const auto &it : q) v.push_back(it);
  214. if (v.size() == d) {
  215. mergesort(&v[0], d);
  216. if (d % 2 == 0)
  217. mid = (v[(d - 1) / 2] + v[d / 2]) / 2.0;
  218. else
  219. mid = v[d / 2];
  220. }
  221. }
  222. std::cout << ans << '\n';
  223. return 0;
  224. }