diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 723ef36..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.idea \ No newline at end of file diff --git a/1st module/mod1_a.cpp b/1st module/mod1_a.cpp deleted file mode 100644 index 1c2dbeb..0000000 --- a/1st module/mod1_a.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - - -void prefix_function (std::string& s, std::vector& pi) { - int n = s.length(); - - for (int i=1; i 0 && s[i] != s[j]) - j = pi[j-1]; - - if (s[i] == s[j]) - ++j; - - pi[i] = j; - } -} - -int main() { - std::string s, pattern; - std::cin >> pattern; - std::cin >> s; - s = pattern + '#' + s; - int n = s.length(); - - std::vector pi (n, 0); - prefix_function(s, pi); - - for (int i=2*pattern.length(); i -#include - -const int alphabet = 26; - -char new_character(std::string& s, std::vector& pi, int index) { - std::vector available_symbols(alphabet, true); - - while (index > 0) { - index = pi[index - 1]; - available_symbols[s[index] - 'a'] = false; - } - - for (int i = 0; i < alphabet; ++i) { - if (available_symbols[i]) { - return 'a' + i; - } - } - -} - -std::string buildFromPrefix(std::vector& pi) { - std::string s = ""; - for(int i = 0; i pi; - int tmp; - - while(std::cin >> tmp){ - pi.push_back(tmp); - } - - std::cout << buildFromPrefix(pi); - - return 0; -} diff --git a/2nd module/mod2_a.cpp b/2nd module/mod2_a.cpp deleted file mode 100644 index a783556..0000000 --- a/2nd module/mod2_a.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Дана строка длины n. Найти количество ее различных подстрок. Используйте суффиксный массив. - * Построение суффиксного массива выполняйте за O(n log n). - * Вычисление количества различных подстрок выполняйте за O(n). -*/ -#include -#include - - -void sufix_array(std::string& s, int alphabet, std::vector& suffs) { - int n = s.size(); - int cnt_len = (n > alphabet ? n : alphabet); - std::vector cnt(cnt_len, 0); - std::vector classes(n, 0); - - for (int i = 0; i < n; ++i) { // карманная сортировка подсчетом - ++cnt[s[i] - '\0']; - } - for (int i = 1; i < alphabet; ++i) // считаем границы - cnt[i] += cnt[i-1]; - // suffs будет хранить индексы начал отсортированных подстрок текущей длины - for (int i = 0; i < n; ++i) { - suffs[--cnt[s[i] - '\0']] = i; - } - - int class_numb = 0; - char last_char = '$'; - // каждому суффиксу длины 1 сопоставляем класс - for (int i = 0; i < n; ++i) { - if (s[suffs[i]] != last_char){ - last_char = s[suffs[i]]; - ++class_numb; - } - classes[suffs[i]] = class_numb; - } - - - - - // нулевая итерация завершена - // сортируем подстроки длиной 2 * cur_len = 2^k - int cur_len = 1; - std::vector sorted_by2(n, 0); - std::vector new_classes(n, 0); - while (cur_len <= n){ - // сортируем по второй половине подстроки - for (int i = 0; i < n; ++i){ - sorted_by2[i] = (suffs[i] + n - cur_len) % n; - } - // сортируем по первой половине - // сортировка устойчивая, значит получим целиком отсортированные подстроки - for (int i = 0; i < cnt_len; ++i){ // обнуляем cnt - cnt[i] = 0; - } - - for (int i = 0; i < n; ++i){ - ++cnt[classes[sorted_by2[i]]]; - } - - for (int i = 1; i < cnt_len; ++i) // считаем границы - cnt[i] += cnt[i-1]; - - - for (int i = n - 1; i >= 0; --i){ - suffs[--cnt[classes[sorted_by2[i]]]] = sorted_by2[i]; - } - - class_numb = 0; - for (int i = 1; i < n; ++i){ - int mid1 = (suffs[i] + cur_len) % n; - int mid2 = (suffs[i - 1] + cur_len) % n; - if (classes[suffs[i]] != classes[suffs[i - 1]] or classes[mid1] != classes[mid2]) - ++class_numb; - new_classes[suffs[i]] = class_numb; - } - for (int i = 0; i < n; ++i){ - classes[i] = new_classes[i]; - } - cur_len *= 2; - } -} - -void lcp_array(std::string& s, std::vector& suffs, std::vector& lcp){ - int n = s.length(); - int k = 0; - std::vector pos(n); - for(int i = 0; i < n; ++i) pos[suffs[i]] = i; // pos = suffs^-1 - - for(int i = 0; i < n; ++i){ - if (k > 0) --k; - if (pos[i] == n - 1){ - k = 0; - lcp[n - 1] = -1; - }else{ - int j = suffs[pos[i] + 1]; - while ((i + k > j + k ? i + k : j + k) < n and s[i + k] == s[j + k]) - ++k; - lcp[pos[i]] = k; - } - } -} - -int find_substrings(std::string& s){ - s += "$"; - - std::vector p(s.size(), 0); - std::vector lcp(s.size(), 0); - sufix_array(s, 256, p); - lcp_array(s, p, lcp); - - int ans = 0; - for (int i = 0; i < s.size(); ++i) { - //std::cout << p[i] << "|" << lcp[i] << " \n"; - ans += s.size() - 1 - p[i] - lcp[i]; - } - return --ans; -} - -int main() { - std::string s; - std::cin >> s; - - std::cout << find_substrings(s); - return 0; -} diff --git a/2nd module/mod2_c.cpp b/2nd module/mod2_c.cpp deleted file mode 100644 index f02c1f5..0000000 --- a/2nd module/mod2_c.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Заданы две строки s, t и целое число k. - * Рассмотрим множество всех таких непустых строк, которые встречаются как подстроки в s и t одновременно. - * Найдите k-ую в лексикографическом порядке строку из этого множества. - * Полезная статья про сравнение указателей: https://stackoverflow.com/questions/9086372/how-to-compare-pointers. -*/ -#include -#include - - -void sufix_array(std::string& s, int alphabet, std::vector& suffs) { - int n = s.size(); - int cnt_len = (n > alphabet ? n : alphabet); - std::vector cnt(cnt_len, 0); - std::vector classes(n, 0); - - for (int i = 0; i < n; ++i) { // карманная сортировка подсчетом - ++cnt[s[i] - '\0']; - } - for (int i = 1; i < alphabet; ++i) // считаем границы - cnt[i] += cnt[i-1]; - // suffs будет хранить индексы начал отсортированных подстрок текущей длины - for (int i = 0; i < n; ++i) { - suffs[--cnt[s[i] - '\0']] = i; - } - - int class_numb = 0; - char last_char = '$'; - // каждому суффиксу длины 1 сопоставляем класс - for (int i = 0; i < n; ++i) { - if (s[suffs[i]] != last_char){ - last_char = s[suffs[i]]; - ++class_numb; - } - classes[suffs[i]] = class_numb; - } - - - - - // нулевая итерация завершена - // сортируем подстроки длиной 2 * cur_len = 2^k - int cur_len = 1; - std::vector sorted_by2(n, 0); - std::vector new_classes(n, 0); - while (cur_len <= n){ - // сортируем по второй половине подстроки - for (int i = 0; i < n; ++i){ - sorted_by2[i] = (suffs[i] + n - cur_len) % n; - } - // сортируем по первой половине - // сортировка устойчивая, значит получим целиком отсортированные подстроки - for (int i = 0; i < cnt_len; ++i){ // обнуляем cnt - cnt[i] = 0; - } - - for (int i = 0; i < n; ++i){ - ++cnt[classes[sorted_by2[i]]]; - } - - for (int i = 1; i < cnt_len; ++i) // считаем границы - cnt[i] += cnt[i-1]; - - - for (int i = n - 1; i >= 0; --i){ - suffs[--cnt[classes[sorted_by2[i]]]] = sorted_by2[i]; - } - - class_numb = 0; - for (int i = 1; i < n; ++i){ - int mid1 = (suffs[i] + cur_len) % n; - int mid2 = (suffs[i - 1] + cur_len) % n; - if (classes[suffs[i]] != classes[suffs[i - 1]] or classes[mid1] != classes[mid2]) - ++class_numb; - new_classes[suffs[i]] = class_numb; - } - for (int i = 0; i < n; ++i){ - classes[i] = new_classes[i]; - } - cur_len *= 2; - } -} - -void lcp_array(std::string& s, std::vector& suffs, std::vector& lcp){ - int n = s.length(); - int k = 0; - std::vector pos(n); - for(int i = 0; i < n; ++i) pos[suffs[i]] = i; // pos = suffs^-1 - - for(int i = 0; i < n; ++i){ - if (k > 0) --k; - if (pos[i] == n - 1){ - k = 0; - lcp[n - 1] = -1; - }else{ - int j = suffs[pos[i] + 1]; - while ((i + k > j + k ? i + k : j + k) < n and s[i + k] == s[j + k]) - ++k; - lcp[pos[i]] = k; - } - } - - for(int i = n - 1; i > 0; --i){ - lcp[i] = lcp[i - 1]; - } - lcp[0] = -1; -} - -bool is_changed(std::vector& p, int i, int pivot){ - return (p[i] < pivot && p[i - 1] > pivot) || - (p[i] > pivot && p[i - 1] < pivot); -} - - -std::string find_k_substring(std::string& s, std::string& l, int64_t k){ - int old_s_size = s.size(); - s = s + "#" + l + "$"; - - std::vector p(s.size(), 0); - std::vector lcp(s.size(), 0); - sufix_array(s, 256, p); - lcp_array(s, p, lcp); - - for (int i = 0; i < s.size(); ++i) { - //std::cout << p[i] << "|" << lcp[i] << " \n"; - } - - int lcp_old = 0; - std::string ans; - - for (int i = 1; i < s.size(); ++i){ - if (is_changed(p, i, old_s_size)){ - //std::cout << p[i - 1] << " comp with " << p[i] << " " << "(" << lcp[i] << ") " << k << "\n"; - if (lcp_old + k > lcp[i]) { - if (lcp[i] >= lcp_old) { - k -= lcp[i] - lcp_old; - } - lcp_old = lcp[i]; - - }else{ - for (int j = p[i]; j < lcp_old + k + p[i]; ++j) { - std::cout << s[j]; - } - - k = 0; - break; - } - } - if (lcp[i] < lcp_old){ - lcp_old = lcp[i]; - } - } - - if (k > 0) - ans = "-1"; - - return ans; -} - -int main() { - std::string s, l; - int64_t k; - std::cin >> s; - std::cin >> l; - std::cin >> k; - - - std::cout << find_k_substring(s, l, k); - return 0; -} diff --git a/geometry.cpp b/geometry.cpp new file mode 100644 index 0000000..a2e3e4d --- /dev/null +++ b/geometry.cpp @@ -0,0 +1,147 @@ +#include "geometry.h" +#include +#include "vector_shift.h" + + +static const int int_max = 1001; + + +Point::Point() : x (0), y (0) {} + +Point::Point (double a, double b) : x (a), y (b) {} + +Point::Point (const Point& p) : x (p.x), y (p.y) {} + +// расстояние между точками +double Point::getDistance (const Point& p) const { + return sqrt(pow((p.x - this->x), 2) + pow((p.y - this->y), 2)); +} + +Point Point::operator+=(const Point& p) { + this->x += p.x; + this->y += p.y; + return *this; +} + +Point& Point::operator=(const Point& p) { + this->x = p.x; + this->y = p.y; + return *this; +} + +Point operator+(const Point& p1, const Point& p2) { + return Point (p1.x + p2.x, p1.y + p2.y); +} + +Point operator-(const Point& p1, const Point& p2) { + return Point (p1.x - p2.x, p1.y - p2.y); +} + +double findCos (const Point& c, const Point& b, const Point& a) { + double ab = a.getDistance(b); + double ac = a.getDistance(c); + double bc = b.getDistance(c); + + return (pow(bc, 2) + pow(ac, 2) - pow(ab, 2)) / (2 * bc * ac); +} + +bool isSinMoreThanZero (const Point& a, const Point& b, const Point& c) { + Point vector1 = c - b; + Point vector2 = a - b; + + return (vector1.x * vector2.y - vector1.y * vector2.x) >= 0; +} + + +// Convex methods +ConvexHull::ConvexHull () : points (0) {} + +void ConvexHull::addPoint (const Point& p) { + points.push_back(p); +} + +void ConvexHull::normalize () { + int min_x = int_max; + int min_y = int_max; + int iter = 0; + + // ищем самую левую самую нижнюю + for (int i = 0; i < points.size(); ++i) { + if (min_x > points[i].x) { + min_x = points[i].x; + min_y = points[i].y; + iter = i; + } + if (min_x == points[i].x && min_y > points[i].y) { + min_y = points[i].y; + iter = i; + } + } + + shiftLeft (points, ++iter); +} + +ConvexHull makeCommonHull(ConvexHull& first_hull, ConvexHull& second_hull) { + int this_ptr = first_hull.points.size() - 1; + int hull_ptr = second_hull.points.size() - 1; + + ConvexHull cmn_hull; + + Point c_k (first_hull.points[this_ptr]); + c_k += second_hull.points[hull_ptr]; // c_0 = a_0 + b_0 + cmn_hull.addPoint(Point(c_k)); + + Point c_k_prev (c_k); + c_k_prev.y += 1; + + // начинаем заворачивать подарок на основе двух готовых других + while (hull_ptr != 0 && this_ptr != 0) { + Point b_j = second_hull.points[hull_ptr]; // b_j + Point a_i = first_hull.points[this_ptr]; // a_i + Point b_j_next = second_hull.points[hull_ptr - 1]; // b_{j+1} + Point a_i_next = first_hull.points[this_ptr - 1]; // a_{i+1} + Point c_k_next1 = a_i + b_j_next; + Point c_k_next2 = b_j + a_i_next; + + double cos1 = findCos (c_k, c_k_prev, c_k_next1); + double cos2 = findCos (c_k, c_k_prev, c_k_next2); + + if (cos1 < cos2) { // => c_k_next1 подходит + cmn_hull.addPoint(c_k_next1); + --hull_ptr; + c_k_prev = c_k; + c_k = c_k_next1; + } else { + cmn_hull.addPoint(c_k_next2); + --this_ptr; + c_k_prev = c_k; + c_k = c_k_next2; + } + } + + // добраем оставшиеся вершины + if (hull_ptr == 0) { + Point last_p = second_hull.points[0]; + while (this_ptr != 0) { + cmn_hull.addPoint(last_p + first_hull.points[this_ptr - 1]); + --this_ptr; + } + } else { + Point last_p = first_hull.points[0]; + while (hull_ptr != 0) { + cmn_hull.addPoint(last_p + second_hull.points[hull_ptr - 1]); + --hull_ptr; + } + } + + return cmn_hull; +} + +bool isPointRelatedToHull (ConvexHull& hull, Point& pnt) { + for (int i = 0; i < hull.points.size() - 1; ++i) { + if (!isSinMoreThanZero(hull.points[i + 1], pnt, hull.points[i])) { + return false; + } + } + return isSinMoreThanZero(hull.points[0], pnt, hull.points[hull.points.size() - 1]); +} \ No newline at end of file diff --git a/geometry.h b/geometry.h new file mode 100644 index 0000000..abe7b18 --- /dev/null +++ b/geometry.h @@ -0,0 +1,50 @@ +#ifndef INC_3TERM_CONTESTS_GEOMETRY_H +#define INC_3TERM_CONTESTS_GEOMETRY_H + + +#include +#include + +struct Point { + double x, y; + + Point(); + + Point (double a, double b); + + Point (const Point& p); + + // расстояние между точками + double getDistance (const Point& p) const; + + Point operator+=(const Point& p); + + Point& operator=(const Point& p); +}; + + +struct ConvexHull { + std::vector points; + + ConvexHull (); + + void addPoint (const Point& p); + + void normalize (); +}; + + +Point operator+(const Point& p1, const Point& p2); + +Point operator-(const Point& p1, const Point& p2); + +double findCos (const Point& c, const Point& b, const Point& a); + +bool isSinMoreThanZero (const Point& a, const Point& b, const Point& c); + +ConvexHull makeCommonHull(ConvexHull& first_hull, ConvexHull& second_hull); + +bool isPointRelatedToHull (ConvexHull& hull, Point& pnt); + + +#endif //INC_3TERM_CONTESTS_GEOMETRY_H diff --git a/mod3_c.cpp b/mod3_c.cpp new file mode 100644 index 0000000..5c01b85 --- /dev/null +++ b/mod3_c.cpp @@ -0,0 +1,42 @@ +/* + * Даны два выпуклых многоугольника на плоскости. В первом n точек, во втором m. + * Определите, пересекаются ли они за O(n + m). Указание. Используйте сумму Минковского. + * + */ + + +#include +#include +#include +#include "geometry.h" + + +int main() { + double x, y; + int n; + ConvexHull set1, set2; + + std::cin >> n; + for (int i = 0; i < n; ++i) { + std::cin >> x >> y; + Point read_p (x, y); + set1.addPoint(read_p); + } + set1.normalize(); + + std::cin >> n; + for (int i = 0; i < n; ++i) { + std::cin >> x >> y; + Point read_p (-x, -y); + set2.addPoint(read_p); + } + set2.normalize(); + + + + ConvexHull set = makeCommonHull(set1, set2); + Point zero_p (0, 0); + std::cout << (isPointRelatedToHull(set, zero_p) ? "YES" : "NO"); + + return 0; +} diff --git a/vector_shift.h b/vector_shift.h new file mode 100644 index 0000000..aa042df --- /dev/null +++ b/vector_shift.h @@ -0,0 +1,20 @@ +#ifndef INC_3TERM_CONTESTS_VECTOR_SHIFT_H +#define INC_3TERM_CONTESTS_VECTOR_SHIFT_H + + +#include + +template +void shiftLeft (std::vector& arr, int k) { + k %= arr.size(); + std::vector buffer (arr.begin(), arr.begin() + k); + for (int i = k; i < arr.size(); ++i) { + arr[i - k] = arr[i]; + } + for (int i = arr.size() - k; i < arr.size(); ++i) { + arr[i] = buffer[i - arr.size() + k]; + } +} + + +#endif //INC_3TERM_CONTESTS_VECTOR_SHIFT_H