├── Exams ├── Solution12062018.cpp ├── Solution14022018_slow.cpp ├── Solution23012018.cpp ├── TestSet06072018.zip ├── TestSet12062018.zip ├── TestSet14012019.zip ├── TestSet14022018.zip ├── TestSet23012018.zip ├── Text06072018.pdf ├── Text12062018.pdf ├── Text14012019.pdf ├── Text14022018.pdf └── Text23012018.pdf ├── README.md ├── Solutions.md ├── code ├── Chocolate.cpp ├── FindPair.cpp ├── FindingTeamMember.cpp ├── FiringEmployees.cpp ├── IlyaQueries.cpp ├── InversionCount.cpp ├── IsBST.cpp ├── Kadane.cpp ├── LargestEvenNumber.cpp ├── Leaders.cpp ├── LittleGirl.cpp ├── MaximumPathSum.cpp ├── Megacity.cpp ├── MissingNumber.cpp ├── NestedSegments.cpp ├── NextLargerElements.cpp ├── NumberWays.cpp ├── PashmakParmida.cpp ├── PreorderTraversal.cpp ├── SlidingWindowMaxima.cpp ├── Towers.cpp ├── TrappingRainWater.cpp ├── TwoHeaps.cpp ├── UpdateArray.cpp ├── fenwick_tree.hpp └── segment_trees │ ├── gen_data.py │ ├── rmq_segment_tree.cpp │ ├── rmq_segment_tree.hpp │ ├── trees_with_arrays.cpp │ └── trees_with_pointers.cpp ├── handson ├── handson01 │ ├── README.md │ ├── imgs │ │ └── test_passed.png │ └── sliding_window_maximum │ │ ├── Cargo.toml │ │ ├── PlotResults.ipynb │ │ └── src │ │ ├── lib.rs │ │ └── main.rs ├── handson02 │ ├── README.md │ ├── problem_01 │ │ ├── Testset.zip │ │ └── text.pdf │ └── problem_02 │ │ ├── TestSet.zip │ │ └── text.pdf └── handson03 │ ├── README.md │ ├── problem_01 │ ├── TestSet.zip │ └── text.pdf │ └── problem_02 │ ├── TestSet.zip │ └── text.pdf ├── notes ├── DynamicProgramming.md ├── DynamicProgramming.pdf ├── Graph1.pdf ├── Graph2.pdf ├── Graph3.pdf ├── Greedy1.pdf ├── Greedy2.pdf ├── Martin_Gardner_Aha_Insight_DP.pdf ├── MosAlgorithm.pdf ├── PrefixSums.pdf ├── SearchingandSorting.pdf ├── SlidingWindowMaximum.pdf ├── StringMatching.pdf ├── Trees.pdf └── figures │ ├── DP_IndepSetTree.png │ ├── DP_IndepSetTree.tex │ └── DP_LCS_example.png └── slides ├── Coding1.key ├── Coding1.pdf ├── Introduction.key ├── Introduction.pdf ├── STL.key ├── STL.pdf ├── segment_trees.key └── segment_trees.pdf /Exams/Solution12062018.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | 10 | std::ios_base::sync_with_stdio(false); 11 | 12 | uint64_t n = 0; // number of elements in arrays 13 | std::cin >> n; 14 | 15 | std::vector A; 16 | A.reserve(n); 17 | 18 | for (uint64_t i = 0; i < n; ++i) { 19 | uint64_t x = 0; 20 | std::cin >> x; 21 | A.push_back(x); 22 | } 23 | 24 | if(n == 1) { 25 | std::cout << n << std::endl; 26 | return 0; 27 | } 28 | 29 | 30 | std::vector L(n, 1); 31 | std::vector R(n, 1); 32 | 33 | for(size_t i = 1; i < n; ++i) { 34 | if (A[i-1] < A[i]) 35 | L[i] = L[i-1] + 1; 36 | } 37 | 38 | for(int32_t i = n-2; i >= 0; --i) { 39 | if (A[i] < A[i+1]) 40 | R[i] = R[i+1] + 1; 41 | } 42 | 43 | uint64_t m = std::max(R[0], L[n-1]) + 1; 44 | 45 | for (uint64_t i = 1; i < n-1; ++i) { 46 | if (A[i-1] + 1 < A[i+1]) { 47 | uint64_t v = L[i-1] + R[i+1] + 1; 48 | m = std::max(v, m); 49 | } 50 | m = std::max(L[i] + 1, m); 51 | m = std::max(R[i] + 1, m); 52 | 53 | } 54 | std::cout << m << std::endl; 55 | 56 | std::cout << std::flush; 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /Exams/Solution14022018_slow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | 9 | std::ios_base::sync_with_stdio(false); 10 | 11 | uint64_t n = 0; // number of elements in arrays 12 | std::cin >> n; 13 | 14 | typedef uint64_t int_type; 15 | 16 | std::vector A; 17 | A.reserve(n); 18 | 19 | for (uint64_t i = 0; i < n; ++i) { 20 | int_type x = 0; 21 | std::cin >> x; 22 | A.push_back(x); 23 | } 24 | 25 | std::vector L(n); 26 | std::vector R(n); 27 | 28 | for (uint64_t i = 0; i < n-1; ++i) 29 | for (uint64_t j = i+1; j < n; ++j) 30 | if (A[i] < A[j]) { 31 | R[i]++; 32 | L[j]++; 33 | } 34 | 35 | int_type count = 0; 36 | 37 | for (uint64_t i = 0; i < n; ++i) 38 | count += L[i]*R[i]; 39 | 40 | std::cout << count << std::endl; 41 | 42 | std::cout << std::flush; 43 | // auto end = clock_type::now(); 44 | // std::chrono::duration elapsed = end - start; 45 | // std::cout << "queries executed in: " << elapsed.count() 46 | // << " [sec]" << std::endl; 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /Exams/Solution23012018.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define LEFT(i) 2 * i + 1 8 | #define RIGHT(i) 2 * i + 2 9 | #define PARENT(i) (i - 1) / 2 10 | 11 | struct query { 12 | query(size_t xx, 13 | size_t yy, 14 | size_t kk) 15 | : x(xx) 16 | , y(yy) 17 | , k(kk) 18 | {} 19 | 20 | size_t x, y, k; 21 | }; 22 | 23 | template 24 | struct segment_tree { 25 | 26 | segment_tree(size_t n) 27 | : m_n(n) 28 | , m_leaves(n) 29 | { 30 | // round up to the next power of 2 31 | size_t m = size_t(1) << static_cast(ceil(log2(n))); 32 | m_tree.resize(2 * m - 1, IntType(0)); 33 | build(0, n - 1, 0); 34 | } 35 | 36 | void build(size_t lo, size_t hi, size_t pos) { 37 | if (lo == hi) { 38 | m_leaves[lo] = pos; // save leaf position 39 | return; 40 | } 41 | size_t mid = (lo + hi) / 2; 42 | build(lo, mid, LEFT(pos)); 43 | build(mid + 1, hi, RIGHT(pos)); 44 | } 45 | 46 | // debug purposes 47 | void print_tree() const { 48 | for (auto x: m_tree) { 49 | std::cout << x << " "; 50 | } std::cout << std::endl; 51 | } 52 | 53 | struct range { 54 | range(size_t l, 55 | size_t h) 56 | : lo(l) 57 | , hi(h) 58 | {} 59 | 60 | size_t lo, hi; 61 | }; 62 | 63 | range root() const { 64 | return range(0, size()); 65 | } 66 | 67 | size_t size() const { 68 | return m_n; 69 | } 70 | 71 | void copy(query const& q, size_t query_id) { 72 | range r(q.y, q.y + q.k); 73 | copy(r, query_id, root(), 0); 74 | } 75 | 76 | size_t get_query_id(size_t i) 77 | { 78 | assert(i < size()); 79 | size_t max = 0; 80 | size_t pos = m_leaves[i]; // position of the i-th leaf 81 | 82 | while (true) { // return max from leaf to root 83 | if (m_tree[pos] > max) { 84 | max = m_tree[pos]; 85 | } 86 | if (pos == 0) { // root 87 | break; 88 | } 89 | pos = PARENT(pos); 90 | } 91 | 92 | return max; 93 | } 94 | 95 | private: 96 | size_t m_n; 97 | std::vector m_leaves; 98 | std::vector m_tree; 99 | 100 | void copy(range const& r, size_t query_id, range node_segment, size_t pos) { 101 | 102 | if (r.lo <= node_segment.lo 103 | and r.hi >= node_segment.hi) { // total overlap 104 | m_tree[pos] = query_id; 105 | if (node_segment.lo == node_segment.hi) { // leaf 106 | return; 107 | } 108 | } 109 | 110 | if (r.lo > node_segment.hi 111 | or r.hi < node_segment.lo) { // no overlap 112 | return; 113 | } 114 | 115 | // partial overlap 116 | size_t mid = (node_segment.lo + node_segment.hi) / 2; 117 | copy(r, query_id, {node_segment.lo, mid}, LEFT(pos)); 118 | copy(r, query_id, {mid + 1, node_segment.hi}, RIGHT(pos)); 119 | } 120 | }; 121 | 122 | int main() { 123 | 124 | std::ios_base::sync_with_stdio(false); 125 | 126 | uint64_t n = 0; // number of elements in arrays 127 | std::cin >> n; 128 | 129 | uint64_t m = 0; // number of queries 130 | std::cin >> m; 131 | 132 | typedef std::chrono::high_resolution_clock clock_type; 133 | typedef int int_type; 134 | 135 | std::vector A; 136 | std::vector B; 137 | A.reserve(n); 138 | B.reserve(n); 139 | 140 | for (uint64_t i = 0; i < n; ++i) { 141 | int_type x = 0; 142 | std::cin >> x; 143 | A.push_back(x); 144 | } 145 | 146 | for (uint64_t i = 0; i < n; ++i) { 147 | int_type x = 0; 148 | std::cin >> x; 149 | B.push_back(x); 150 | } 151 | 152 | segment_tree st(n); 153 | 154 | std::vector queries; 155 | queries.reserve(m); // upper bound 156 | 157 | // auto start = clock_type::now(); 158 | for (uint64_t i = 0; i < m; ++i) 159 | { 160 | size_t type; 161 | std::cin >> type; 162 | 163 | if (type == 1) { 164 | 165 | size_t x, y, k; 166 | std::cin >> x >> y >> k; 167 | queries.emplace_back(x, y, k); 168 | st.copy(queries.back(), 169 | queries.size()); // next query id 170 | 171 | } else if (type == 2) { 172 | 173 | size_t pos; 174 | std::cin >> pos; 175 | size_t query_id = st.get_query_id(pos); 176 | if (query_id == 0) { 177 | std::cout << B[pos] << "\n"; 178 | } else { 179 | auto q = queries[query_id - 1]; 180 | std::cout << A[pos - q.y + q.x] << "\n"; 181 | } 182 | 183 | } else { 184 | std::cerr << "unknown query type" << std::endl; 185 | return 1; 186 | } 187 | } 188 | 189 | std::cout << std::flush; 190 | // auto end = clock_type::now(); 191 | // std::chrono::duration elapsed = end - start; 192 | // std::cout << "queries executed in: " << elapsed.count() 193 | // << " [sec]" << std::endl; 194 | 195 | return 0; 196 | } 197 | -------------------------------------------------------------------------------- /Exams/TestSet06072018.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/TestSet06072018.zip -------------------------------------------------------------------------------- /Exams/TestSet12062018.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/TestSet12062018.zip -------------------------------------------------------------------------------- /Exams/TestSet14012019.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/TestSet14012019.zip -------------------------------------------------------------------------------- /Exams/TestSet14022018.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/TestSet14022018.zip -------------------------------------------------------------------------------- /Exams/TestSet23012018.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/TestSet23012018.zip -------------------------------------------------------------------------------- /Exams/Text06072018.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/Text06072018.pdf -------------------------------------------------------------------------------- /Exams/Text12062018.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/Text12062018.pdf -------------------------------------------------------------------------------- /Exams/Text14012019.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/Text14012019.pdf -------------------------------------------------------------------------------- /Exams/Text14022018.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/Text14022018.pdf -------------------------------------------------------------------------------- /Exams/Text23012018.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/Exams/Text23012018.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This page will no longer be updated. The new Web page is [here](https://pages.di.unipi.it/rossano/competitive/). 2 | 3 | 4 | # Competitive Programming and Contests 5 | 6 | * Teacher: [Rossano Venturini](http://pages.di.unipi.it/rossano) 7 | * CFU: 6 8 | * Period: First semester 9 | * Language: English 10 | * Classroom: [here](https://classroom.google.com/u/1/c/NTQ3NjY2MTA5NzI2). Code is **d77kira** 11 | * Lectures schedule: Monday 9-11 Room C1 and Thursday 9-11 Room C1 -- (Google Meet, link on our classroom) 12 | * Question time: After lectures or by appointment 13 | 14 | ## Goals and opportunities 15 | The goal of the course is to improve programming and problem-solving skills of the students by facing them with difficult problems and by presenting the techniques that help their reasoning in the implementation of correct and efficient solutions. 16 | The importance of these skills has been recognized by the most important software companies worldwide, which evaluate candidates in their job interviews mostly by the ability in addressing such difficult problems (e.g., see [here](http://www.geeksforgeeks.org/company-preparation/)). 17 | 18 | A natural goal is to involve the students in the intellectual pleasure of programming and problem solving, also preparing them for the most important international online contests, such as [Topcoder](https://www.topcoder.com/), [Codeforces](Codeforces), [HackerRank](https://www.hackerrank.com/), [CodeChef](https://www.codechef.com/), [Facebook Hacker Cup](https://www.facebook.com/hackercup/), [Google Code Jam](https://code.google.com/codejam/) and so on, for internships in most important companies and their interviews. 19 | A desirable side-effect of the course could be to organize and prepare teams of students for online contests. 20 | 21 | The course will provide the opportunity of 22 | * facing with challenging algorithmic problems; 23 | * improving problem solving and programming skills; 24 | * getting in touch with some big companies for internships, scholarships, or thesis proposals. 25 | 26 | ## Exam 27 | See these [slides](/slides/Introduction.pdf). Mandatory exercises for homeworks are in bold. 28 | 29 | Extra points for 30 | * active participation 31 | * serious participation to online contests, e.g., CodeForces, TopCoder, Hacker 32 | Rank, Google Code Jam, ... 33 | * successful interview with a big company 34 | 35 | Implementing solutions for the problems of each lecture is strongly recommended 36 | to improve your problem solving skill and to practice with Rust. 37 | 38 | I recommend you to create a [github](http://github.com) repository to collect all your 39 | solutions and their descriptions. 40 | The repository can be either private or public. In both cases I should be able 41 | to access it. 42 | Please send me a link to your repository and keep the repository updated. I 43 | should be able to monitor your progresses. 44 | 45 | ### Upcoming Exams 46 | 47 | | Type | Date | Room | 48 | | ------------- | ------------- | ------------- | 49 | | Written/Lab | 03/02/2022 9:00 | [Google Meet](https://meet.google.com/lookup/gitaxagnei) | 50 | 51 | ### Old Exams 52 | 53 | | Type | Date | Text | 54 | | ------------- | ------------- | ------------- | 55 | | Written/Lab | 23/01/2018 9:30 | [Text](Exams/Text23012018.pdf), [TestSet](Exams/TestSet23012018.zip), and [Solution](Exams/Solution23012018.cpp) | 56 | | Written/Lab | 14/02/2018 9:30 | [Text](Exams/Text14022018.pdf), [TestSet](Exams/TestSet14022018.zip), and [Quadratic solution](Exams/Solution14022018_slow.cpp)| 57 | | Written/Lab | 12/06/2018 14:00 | [Text](Exams/Text12062018.pdf), [TestSet](Exams/TestSet12062018.zip), and [Solution](Exams/Solution12062018.cpp) | 58 | | Written/Lab | 06/07/2018 9:30 | [Text](Exams/Text06072018.pdf) and [TestSet](Exams/TestSet06072018.zip) | 59 | | Written/Lab | 14/01/2019 14:00 | [Text](Exams/Text14012019.pdf) and [TestSet](Exams/TestSet14012019.zip)| 60 | 61 | ### How to solve a problem 62 | 63 | * Read carefully the description of the problem. 64 | * Make sure you understand the problem by checking the examples. 65 | * Design a first trivial solution. 66 | * Think about a more efficient solution. The use of some running examples 67 | usually helps a lot in finding a better solution. 68 | If your are not able to find such solution, try to find some hints by 69 | discussing with other students, by asking questions on the group, by looking at 70 | the solution in our Web page, or by searching on internet. This is perfectly 71 | fine for the first problems and for most difficult ones. In any case, make sure 72 | you really understand the solution and the properties it is exploiting! 73 | * Write a brief description of your solution in English. Provide an analysis of 74 | its time and space complexity. 75 | * Implement your own solution. 76 | * Submit your implementation to the problem's site. Fix it until it passes all 77 | the tests. 78 | * Always compare your solution and your implementation with existing ones. 79 | 80 | ## Background 81 | If you wish to refresh your mind on basic Algorithms and Data Structures, I suggest you to look at the well-known book [Introduction to Algorithms, 3rd Edition](http://mitpress.mit.edu/catalog/item/default.asp?ttype=2&tid=11866) by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein. 82 | 83 | I strongly suggest you to watch the following video lectures as soon as possible. 84 | * [Insertion Sort and Merge Sort](https://www.youtube.com/watch?v=Kg4bqzAqRBM&index=3&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb) 85 | * [Heaps and Heap Sort](https://www.youtube.com/watch?v=B7hVxCmfPtM&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=4) 86 | * [Counting Sort, Radix Sort, Lower Bounds for Sorting](https://www.youtube.com/watch?v=Nz1KZXbghj8&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=7) 87 | * [Binary Search Trees](https://www.youtube.com/watch?v=9Jry5-82I68&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb&index=5) 88 | * [AVL trees](https://www.youtube.com/watch?v=FNeL18KsWPc&index=6&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb) 89 | * [Hashing with Chaining](https://www.youtube.com/watch?v=0M_kIqhwbFo&index=8&list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb) 90 | 91 | ## References 92 | * Introduction to Algorithms,  3rd Edition, Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein, The MIT Press, 2009 ([Amazon](http://www.amazon.com/Introduction-Algorithms-3rd-Thomas-Cormen/dp/0262033844/ref=sr_1_1?s=books&ie=UTF8&qid=1443160441&sr=1-1&keywords=introduction+to+algorithms)) [CCLR] 93 | * Algorithms, 4th Edition, Robert Sedgewick, Kevin Wayne, Addison-Wesley Professional, 2011 ([Amazon](http://www.amazon.com/Algorithms-4th-Edition-Robert-Sedgewick/dp/032157351X/ref=pd_sim_14_2?ie=UTF8&refRID=1A2NFN935EST0ZQARB6H&dpID=51UDgHU9z9L&dpSrc=sims&preST=_AC_UL160_SR130%2C160_)) [RS] 94 | * Algorithms, Sanjoy Dasgupta, Christos Papadimitriou, Umesh Vazirani, McGraw-Hill, 2006\. ([Amazon](http://www.amazon.com/Algorithms-Sanjoy-Dasgupta/dp/0073523402)) [DPZ] 95 | * Programming Challenges: The Programming Contest Training Manual, Steven S. Skiena, Miguel A. Revilla, Springer, 2003 ([Amazon](http://www.amazon.com/Programming-Challenges-Contest-Training-Computer/dp/0387001638)) [SR] 96 | * Competitive Programming 4: The New Lower Bound of Programming Contests, Steven Halim, Felix Halim, ([here](https://cpbook.net/)) [HH] 97 | * Guide to Competitive Programming: Learning and Improving Algorithms Through Contests. Second Edition, Antti Laaksonen, Springer, 2020 ([here](https://www.springer.com/gp/book/9783030393564)) [L] 98 | ### Rust 99 | * [The Rust Programming Language](https://doc.rust-lang.org/stable/book/ch05-00-structs.html) 100 | - [Videos](https://www.youtube.com/watch?v=OX9HJsJUDxA&list=PLai5B987bZ9CoVR-QEIN9foz4QCJ0H2Y8) 101 | * [The Rust Reference](https://doc.rust-lang.org/reference/introduction.html) 102 | * [The Rust Standard Library](https://doc.rust-lang.org/std/index.html) 103 | * [Rust users forum](https://users.rust-lang.org/) 104 | * [Rustlings](https://github.com/rust-lang/rustlings) 105 | ### C++ 106 | * The C++ Programming Language, 4th Edition, Bjarne Stroustrup, Addison-Wesley Professional, 2013 ([Amazon](http://www.amazon.com/The-Programming-Language-4th-Edition/dp/0321563840/ref=dp_ob_image_bk)) 107 | * A Tour of C++, 2nd Edition, Bjarne Stroustrup, Addison-Wesley Professional, 2018 ([Amazon](https://www.amazon.com/Tour-2nd-Depth-Bjarne-Stroustrup/dp/0134997832/ref=sr_1_1?keywords=a+tour+of+c%2B%2B&qid=1570692421&sr=8-1)) 108 | * The C++ Standard Library: A Tutorial and Reference, 2nd Edition, Nicolai M. Josuttis, Addison-Wesley Professional, 2012 ([Amazon](http://www.amazon.com/The-Standard-Library-Tutorial-Reference/dp/0321623215/ref=pd_sim_14_11?ie=UTF8&refRID=1M156BZ8BPE95NBSP5PN)) 109 | 110 | ## Useful links 111 | * Erik D Demaine, Srini Devadas, Nancy Ann Lynch, ["MIT  Design and Analysis of Algorithms"](http://stellar.mit.edu/S/course/6/sp15/6.046J/), MIT Algorithm course which includes video lectures 112 | * Tim Roughgarden, "[Algorithm specialization](https://www.coursera.org/specializations/algorithms)", Coursera 113 | * [Visualgo](https://visualgo.net/en): visualising data structures and algorithms through animation 114 | * Geeks for Geeks: [Company interviews preparation](http://www.geeksforgeeks.org/company-preparation/) 115 | * [Interviews common coding questions](http://www.geeksforgeeks.org/must-do-coding-questions-for-companies-like-amazon-microsoft-adobe/) 116 | * How to: Work at Google — Example Coding/Engineering Interview [Video](https://www.youtube.com/watch?v=XKu_SEDAykw) 117 | * [Google's Code Jam](https://code.google.com/codejam/) 118 | * [Topcoder](https://www.topcoder.com/) 119 | * [Codeforces](http://codeforces.com/) 120 | * [LeetCode](https://leetcode.com/) 121 | * [HackerRank](https://www.hackerrank.com/) 122 | * [Geeks for Geeks](http://www.geeksforgeeks.org/) 123 | * [LeetCode](https://leetcode.com/) 124 | * [CodeChef - Data Structures and Algorithms links](https://discuss.codechef.com/questions/48877/data-structures-and-algorithms) 125 | * Geeks for Geeks: [Top 10 Algorithms and Data Structures for Competitive Programming](http://www.geeksforgeeks.org/top-algorithms-and-data-structures-for-competitive-programming/) 126 | * [List](http://codeforces.com/blog/entry/23054) of resources for competitive programming 127 | 128 | ## Lectures 129 | | Date | Lecture | References | Problems | 130 | | ------------- | ------------- | ------------- | ------------- | 131 | | 15/09/2022 | Introduction | [Slides](/slides/Introduction.pdf) | [Leaders in array](http://practice.geeksforgeeks.org/problems/leaders-in-an-array/0) ([solution](Solutions.md#Leaders)), **[Kadane's algorithm](https://leetcode.com/problems/maximum-subarray/) ([solution](Solutions.md#Kadane))**, and [Missing number in array](https://leetcode.com/problems/missing-number/) ([solution](Solutions.md#Number))| 132 | | 19/09/2022 | Solutions of Trapping rain water and Sliding window maximum | [Rossano's notes*](/notes/SlidingWindowMaximum.pdf) | [Trapping rain water](https://leetcode.com/problems/trapping-rain-water/) ([solution](Solutions.md#Water)), and **[Sliding window maximum](https://leetcode.com/problems/sliding-window-maximum/) ([solution](Solutions.md#Sliding))** | 133 | | 22/09/2022 | Analysis and correctness of Sliding window maximum. Brief introduction to Rust.| | [**Next greater element**](https://leetcode.com/problems/next-greater-element-ii/) and [Towers](http://codeforces.com/problemset/problem/37/A?locale=en) ([solution](Solutions.md#Towers))| 134 | | 29/09/2022 | Searching and Sorting: Binary Search, Merge Sort, QuickSort, Counting Sort, and Radix Sort | [Rossano's notes\*](notes/SearchingandSorting.pdf). [CCLR] Chapters 2.3, 7, and 8. [Binary search](http://www.geeksforgeeks.org/binary-search/). [Exponential search](http://www.geeksforgeeks.org/exponential-search/). [Interpolation search](http://www.geeksforgeeks.org/interpolation-search/) (optional) | [**The Monkey and the Oiled Bamboo**](https://onlinejudge.org/index.php?option=onlinejudge&Itemid=8&page=show_problem&problem=3183)| 135 | | 03/10/2022 | Searching and Sorting: Binary Search, Merge Sort, QuickSort, Counting Sort, and Radix Sort | | [**Inversion count**]([https://leetcode.com/problems/global-and-local-inversions/](https://leetcode.com/problems/count-of-smaller-numbers-after-self/)) and [Two Types of Spells](https://codeforces.com/contest/1398/problem/E?locale=en) | 136 | | 05/10/2022 | [**Hands-On 1**](handson/handson01/README.md). Deadline: 19/10/2022 | | | 137 | | 10/10/2022 | Trees: representation, traversals, and Binary Search Tree| [Rossano's notes\*](notes/Trees.pdf). [CCLR] Chapters 10.4 and 12. | [**Frogs and Mosquitoes**](https://codeforces.com/contest/609/problem/F?locale=en) | 138 | | 13/10/2022 | Lecture Cancelled! | | | 139 | | 17/10/2022 | Trees: representation, traversals, and Binary Search Tree| [Rossano's notes\*](notes/Trees.pdf). [Tree traversals](https://en.wikipedia.org/wiki/Tree_traversal). | [Maximum path sum](http://practice.geeksforgeeks.org/problems/maximum-path-sum/1) ([solution](Solutions.md#MaximumPathSum)) and [**Longest k-Good Segment**](https://codeforces.com/contest/616/problem/D?locale=en) | 140 | | 20/10/2022 | Trees: representation, traversals, and Binary Search Tree | [Euler Tour](https://en.wikipedia.org/wiki/Euler_tour_technique). [Two pointers technique](https://www.geeksforgeeks.org/two-pointers-technique/). | | 141 | | 24/10/2022 | (Static) Prefix sum | [Rossano's notes\*](notes/PrefixSums.pdf) | [Ilya and Queries](http://codeforces.com/problemset/problem/313/B?locale=en) ([solution](Solutions.md#IlyaandQueries)), [**Number of ways**](http://codeforces.com/problemset/problem/466/C?locale=en) ([solution](Solutions.md#NumberWays)), and  [Little girl and maximum sum](http://codeforces.com/problemset/problem/276/C?locale=en) ([solution](Solutions.md#LittleGirl))| 142 | | 27/10/2022 | Segment Trees | Segment Tree: [description](https://en.wikipedia.org/wiki/Segment_tree), [tutorial 1](http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range), [tutorial 2](https://codeforces.com/blog/entry/15890), [tutorial 3](https://cp-algorithms.com/data_structures/segment_tree.html), [video](https://www.youtube.com/watch?v=ZBHKZF5w4YU&list=PLrmLmBdmIlpv_jNDXtJGYTPNQ2L1gdHxu&index=22), [visualgo](https://visualgo.net/en/segmenttree?slide=1), [slides](slides/segment_trees.pdf) and [code](/code/segment_trees). | Solve [Nested segments](http://codeforces.com/problemset/problem/652/D?locale=en) with Segment trees.| 143 | | 31/10/2022 | Segment trees: Applications | | | 144 | | 03/11/2022 | Segment Trees: Lazy Propagation and Persistency | Segment Tree: [description](https://en.wikipedia.org/wiki/Segment_tree), [tutorial 1](http://www.geeksforgeeks.org/segment-tree-set-1-sum-of-given-range), [tutorial 2](https://codeforces.com/blog/entry/15890), [tutorial 3](https://cp-algorithms.com/data_structures/segment_tree.html), [video](https://www.youtube.com/watch?v=ZBHKZF5w4YU&list=PLrmLmBdmIlpv_jNDXtJGYTPNQ2L1gdHxu&index=22), [visualgo](https://visualgo.net/en/segmenttree?slide=1), [slides](slides/segment_trees.pdf) and [code](/code/segment_trees). Lazy propagation: [tutorial](http://www.geeksforgeeks.org/lazy-propagation-in-segment-tree/) and [video](https://www.youtube.com/watch?v=xuoQdt5pHj0&list=PLrmLmBdmIlpv_jNDXtJGYTPNQ2L1gdHxu&index=23).| [Circular RMQ](http://codeforces.com/problemset/problem/52/C)| 145 | | 07/11/2022 | Exercises | | Triplets ([Text](Exams/Text14022018.pdf) and [TestSet](Exams/TestSet14022018.zip)) and **Smaller Values** ([Text](Exams/Text14012019.pdf) and [TestSet](Exams/TestSet14012019.zip)) | 146 | | 10/11/2022 | [**Hands-On 2**](handson/handson02/README.md). Deadline: 23/11/2022 | | | 147 | | 14/11/2022 | Static RMQ with sparse table | RMQ and sparse table: [tutorial 1](http://www.geeksforgeeks.org/range-minimum-query-for-static-array/), [tutorial 2](https://cp-algorithms.com/sequences/rmq.html), [paper](http://www.ics.uci.edu/~eppstein/261/BenFar-LCA-00.pdf), and [code](https://github.com/spaghetti-source/algorithm/blob/master/data_structure/sparse_table.cc). [Static RMQ in 2n + o(n) bits and constant time](https://epubs.siam.org/doi/10.1137/090779759)(optional). | | 148 | | 17/11/2022 | Mo's algorithm on sequences and trees | [Rossano's notes\*](notes/MosAlgorithm.pdf). Mo's Algorithm: [Sequences](https://blog.anudeep2011.com/mos-algorithm/) and [Trees](http://codeforces.com/blog/entry/43230) | [**Powerful array**](http://codeforces.com/contest/86/problem/D) and [Tree and queries](http://codeforces.com/contest/375/problem/D) | 149 | | 21/11/2022 | Dynamic Programming: Fibonacci numbers, Rod cutting, and Shortest path on a DAG | [Rossano's notes\*](notes/DynamicProgramming.md) (or [pdf](notes/DynamicProgramming.pdf)). [CCLR] Chapter 15. | | 150 | | 24/11/2022 | Dynamic Programming: Minimum cost path and Longest common subsequence | [Rossano's notes\*](notes/DynamicProgramming.md) (or [pdf](notes/DynamicProgramming.pdf)). [Martin Gardner on Minimum cost path](notes/Martin_Gardner_Aha_Insight_DP.pdf).| [**Longest common subsequence**](https://practice.geeksforgeeks.org/problems/longest-common-subsequence/0) and [**Minimum number of jumps**](https://practice.geeksforgeeks.org/problems/minimum-number-of-jumps/0) | 151 | | 28/11/2022 | Dynamic Programming: 0/1 Knapsack, Fractional knapsack, and Subset sum. | [Rossano's notes\*](notes/DynamicProgramming.md) (or [pdf](notes/DynamicProgramming.pdf)). 0/1 Knapsack problem: [tutorial](https://www.youtube.com/watch?v=8LusJS5-AGo) | [**Subset sum**](https://practice.geeksforgeeks.org/problems/subset-sum-problem/0) and [0-1 knapsack](https://www.spoj.com/problems/KNAPSACK/)| 152 | | 01/12/2022 | Dynamic Programming: Longest increasing subsequence and Coin change| [Rossano's notes\*](notes/DynamicProgramming.md) (or [pdf](notes/DynamicProgramming.pdf)) | [**Longest increasing subsequence**](https://practice.geeksforgeeks.org/problems/longest-increasing-subsequence/0)| 153 | | 05/12/2022 | Dynamic Programming: Longest increasing subsequence, Longest bitonic subsequence, and Largest independent set on trees| [Rossano's notes\*](notes/DynamicProgramming.md) (or [pdf](notes/DynamicProgramming.pdf)) | [**Longest bitonic subsequence**](https://practice.geeksforgeeks.org/problems/longest-bitonic-subsequence/0) | 154 | | 09/12/2022 | [**Hands-On 3**](handson/handson03/README.md). Deadline: 23/12/2022 | | | 155 | 156 | ## Lectures from past years 157 | | Date | Lecture | References | Problems | 158 | | ------------- | ------------- | ------------- | ------------- | 159 | | 2021 | Prefix sum: Binary Indexed Tree (aka BIT or Fenwick tree) | [Rossano's notes\*](notes/PrefixSums.pdf). BIT: [description](https://en.wikipedia.org/wiki/Fenwick_tree), [tutorial](https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/#add), [video](https://www.youtube.com/watch?v=CWDQJGaN1gY), [visualgo](https://visualgo.net/fenwicktree), and [code](/code/fenwick_tree.hpp).| [Update the array](http://www.spoj.com/problems/UPDATEIT/) ([solution](Solutions.md#LittleGirl)) | 160 | | 2021 | Applications of BIT and Range update with BIT. | [Rossano's notes\*](notes/PrefixSums.pdf). [Range updates on BIT](http://petr-mitrichev.blogspot.com/2013/05/fenwick-tree-range-updates.html). [Tutorial](https://cp-algorithms.com/data_structures/fenwick.html). [RMQ with BIT](http://ioinformatics.org/oi/pdf/v9_2015_39_44.pdf) (optional) | [Nested segments](http://codeforces.com/problemset/problem/652/D?locale=en) ([solution](Solutions.md#NestedSegments)) and [Pashmak and Parmida's problem](http://codeforces.com/problemset/problem/459/D?locale=en) ([solution](Solutions.md#PashmakParmida)) | 161 | | 2017 | Simulation of the exam | | [Misha and forest](http://codeforces.com/problemset/problem/501/C?locale=en) | 162 | | 2017 | Centroid Decomposition of trees | Centroid Decomposition of trees: [here](https://medium.com/carpanese/an-illustrated-introduction-to-centroid-decomposition-8c1989d53308), [here](https://threads-iiith.quora.com/Centroid-Decomposition-of-a-Tree), [here](https://www.geeksforgeeks.org/centroid-decomposition-of-tree/), and [here](https://sai16vicky.wordpress.com/2014/11/01/divide-and-conquer-on-trees-centroid-decomposition/) | | 163 | | 2017 | String algorithms: Knuth-Morris-Pratt and Suffix array | Knuth-Morris-Pratt from [CLRS] Chapter 32.3. [Knuth-Morris-Pratt](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm). Optional: Rabin-Karp [here](notes/StringMatching.pdf) from *Algorithms on strings, trees, and sequences*, D. Gusfield, Cambridge university press, [here](https://www.topcoder.com/community/data-science/data-science-tutorials/introduction-to-string-searching-algorithms/), and [here](https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm). Suffix Array: Tutorial and implementation: [here](http://cs97si.stanford.edu/suffix-array.pdf) and [here](https://discuss.codechef.com/questions/21385/a-tutorial-on-suffix-arrays). Optional: Suffix Array in linear time [here](https://www.cs.helsinki.fi/u/tpkarkka/publications/jacm05-revised.pdf)| [Longest prefix suffix](https://practice.geeksforgeeks.org/problems/longest-prefix-suffix/0) and [Shift the string](https://www.codechef.com/problems/TASHIFT) | 164 | | 2017 | String algorithms: LCP array, trie and ternary search trie | Computing LCP array: [Kasai *et al.*'s algorithm](web.cs.iastate.edu/~cs548/references/linear_lcp.pdf) and [here](http://www.geeksforgeeks.org/%C2%AD%C2%ADkasais-algorithm-for-construction-of-lcp-array-from-suffix-array/). [Ternary search trie](http://www.drdobbs.com/database/ternary-search-trees/184410528) and a [video](https://www.youtube.com/watch?v=CIGyewO7868). | | 165 | | 2018 | Standard Template Library (STL) | [Slides](/slides/STL.pdf). [Tutorial](http://www.geeksforgeeks.org/the-c-standard-template-library-stl/) and [STL algorithms](http://www.geeksforgeeks.org/c-magicians-stl-algorithms/) | [Megacity](http://codeforces.com/problemset/problem/424/B?locale=en) ([solution](Solutions.md#Megacity)), [Find pair](http://codeforces.com/problemset/problem/160/C?locale=en) ([solution](Solutions.md#FindPair)), and [Two heaps](http://codeforces.com/problemset/problem/353/B?locale=en) ([solution](Solutions.md#TwoHeaps))| 166 | | 2018 | Standard Template Library (STL). Coding | [Slides](/slides/Coding1.pdf) | | 167 | | 2018 | Heavy-light Decomposition of trees. **This lecture is not mandatory.** | Heavy-light Decomposition of trees: [here](https://cp-algorithms.com/graph/hld.html), [here](http://wcipeg.com/wiki/Heavy-light_decomposition), and [here](https://blog.anudeep2011.com/heavy-light-decomposition/). | [QTREE](https://www.spoj.com/problems/QTREE/), [QTREE2](https://www.spoj.com/problems/QTREE2/), [QTREE3](https://www.spoj.com/problems/QTREE3/), [GOT](https://www.spoj.com/problems/GOT/), and [Chef and the tree](https://www.codechef.com/problems/CHEFTREE).| 168 | | 2021 | Greedy algorithms: Activity Selection, Job sequencing, and Fractional knapsack problem | [Rossano's notes\*](notes/Greedy1.pdf). [Notes by Jeff Erickson](http://jeffe.cs.illinois.edu/teaching/algorithms/notes/07-greedy.pdf). [Job sequencing](http://www.geeksforgeeks.org/job-sequencing-problem-set-1-greedy-algorithm/). [Fractional Knapsack Problem](http://www.geeksforgeeks.org/fractional-knapsack-problem/) | [N meetings in one room](http://practice.geeksforgeeks.org/problems/n-meetings-in-one-room/0), [Magic numbers](http://codeforces.com/problemset/problem/320/A?locale=en), [Wilbur and array](http://codeforces.com/problemset/problem/596/B?locale=en), and [Alternative thinking](http://codeforces.com/problemset/problem/603/A?locale=en)| 169 | | 2019 | Greedy Algorithms: Boxes and Hero | [Rossano's notes\*](notes/Greedy2.pdf). [Boxes and Hero](https://codeforces.com/blog/entry/63533). Huffman code: [Section 7.4 in Notes by Jeff Erickson](http://jeffe.cs.illinois.edu/teaching/algorithms/notes/07-greedy.pdf) (optional). | [Lexicographically maximum subsequence](http://codeforces.com/problemset/problem/196/A?locale=en), [Woodcutters](http://codeforces.com/contest/545/problem/C?locale=en), and [Queue](http://codeforces.com/problemset/problem/141/C?locale=en) | 170 | | 2021 | Dynamic Programming: Edit distance, Longest palindromic subsequence, and Weighted job scheduling | [Rossano's notes\*](notes/DynamicProgramming.md) (or [pdf](notes/DynamicProgramming.pdf)) | [**Edit distance**](https://practice.geeksforgeeks.org/problems/edit-distance/0), [Vertex cover](http://www.spoj.com/problems/PT07X/), and [Longest palindromic subsequence](https://practice.geeksforgeeks.org/problems/longest-palindromic-subsequence/0) | 171 | | 2021 | Graph algorithms: BFS, DFS, and Topological Sort | [Rossano's notes\*](notes/Graph1.pdf). [CCLR] Chapter 22 | [X total shapes](http://practice.geeksforgeeks.org/problems/x-total-shapes/0), [IsBipartite](http://practice.geeksforgeeks.org/problems/bipartite-graph/1), and [Fox and names](http://codeforces.com/problemset/problem/510/C?locale=en) | 172 | | 2021 | Graph algorithms: Strongly Connected Components and Single-Source Shortest Path| [Rossano's notes\*](notes/Graph2.pdf). [CCLR] Chapters 22 and 23 | [Learning languages](http://codeforces.com/problemset/problem/277/A?locale=en) and [Checkposts](http://codeforces.com/problemset/problem/427/C?locale=en) | 173 | | 2019 | Graph algorithms: Minimum Spanning Tree (and Disjoint Sets data structures) | [Rossano's notes\*](notes/Graph3.pdf). [CCLR] Chapters 21 and 23. Kruskal: [code](https://github.com/spaghetti-source/algorithm/blob/master/graph/kruskal.cc), Disjoint Set: [tutorial](https://www.topcoder.com/community/data-science/data-science-tutorials/disjoint-set-data-structures/) | [Minimum spanning tree](http://www.spoj.com/problems/MST/) | 174 | 175 | 176 | \* Notes marked with *"Rossano's notes"* are rough and non-exhaustive notes that I used while lecturing. Please use them just to have a list of the topics of each lecture and use other reported references to study these arguments. 177 | 178 | ## Further (optional) topics 179 | * [Aho-Corasick String Matching Algorithm](https://pdfs.semanticscholar.org/3547/ac839d02f6efe3f6f76a8289738a22528442.pdf) 180 | * [Convex Hull](jeffe.cs.illinois.edu/teaching/compgeom/notes/01-convexhull.pdf) 181 | * [Interval tree](http://www.geeksforgeeks.org/interval-tree/) 182 | * [Merge Sort Tree](https://www.commonlounge.com/discussion/d871499b49e443259cfbea9b16f9b958/main) 183 | * Manacher's Algorithm: [here](https://en.wikipedia.org/wiki/Longest_palindromic_substring) and [here](https://articles.leetcode.com/longest-palindromic-substring-part-ii/) 184 | * [Maximum flow](http://jeffe.cs.illinois.edu/teaching/algorithms/all-optimization.pdf) 185 | * [Splay trees](http://jeffe.cs.illinois.edu/teaching/algorithms/notes/16-scapegoat-splay.pdf) 186 | * [Sweep line algorithm](http://www.cs.tufts.edu/comp/163/notes05/seg_intersection_handout.pdf) 187 | -------------------------------------------------------------------------------- /Solutions.md: -------------------------------------------------------------------------------- 1 | 2 | ## Leaders in Array 3 | 4 | * [Code](/code/Leaders.cpp) 5 | 6 | 7 | ## Missing Number 8 | 9 | * [Code](/code/MissingNumber.cpp) 10 | 11 | 12 | ## Max-Sum Subarray 13 | 14 | * [Code](/code/Kadane.cpp) 15 | 16 | 17 | ## Trapping Rain Water 18 | 19 | * [Code](/code/TrappingRainWater.cpp) 20 | 21 | 22 | ## Sliding Window Maximum 23 | 24 | * [Description of the solution](/notes/lecture2.pdf) 25 | * [Code](/code/SlidingWindowMaxima.cpp) 26 | 27 | 28 | ## Next Larger Elements 29 | 30 | * [Code](/code/NextLargerElements.cpp) 31 | 32 | 33 | ## Towers 34 | 35 | * [Codeforces](http://codeforces.com/problemset/problem/37/A?locale=en) 36 | * [Code](/code/Towers.cpp) 37 | 38 | Easy: sort and compute the number of distinct lengths. 39 | 40 | 41 | ## Finding Team Member 42 | 43 | * [Codeforces](http://codeforces.com/problemset/problem/579/B?locale=en) 44 | * [Code](/code/FindingTeamMember.cpp) 45 | 46 | Create tuple $\langle S_{i,j}, i, j \rangle$, for each pair 47 | $i$ and $j$ where $S_{i,j}$ is the strength of the pair. Sort them by strength 48 | and start selecting the pairs greedly. 49 | 50 | 51 | ## Megacity 52 | 53 | * [Codeforces](http://codeforces.com/problemset/problem/424/B?locale=en) 54 | * [Code](/code/Megacity.cpp) 55 | 56 | Sort all the locations by their distance with Tomsk and, then, select greedly to sum to at least one million. 57 | 58 | 59 | ## Find Pair 60 | 61 | * [CodeForces](http://codeforces.com/problemset/problem/160/C?locale=en) 62 | * [Code](/code/FindPair.cpp) 63 | 64 | We can find the $k$-th pair without generating (and sorting) all the pairs. The 65 | idea is to sort the original keys. Then, if all the keys were distinct, the 66 | $k$th pair would be $\langle a_i, a_j \rangle$, where $i=(k-1)/n$ and 67 | $j=(k-1)\%n$. However, the presence of not distinct keys makes it slightly more 68 | difficult. Let $r$ be the number of keys equal to $a_i$ and $l$ be the number 69 | of keys smaller than $a_i$. Then, the pair is $\langle a_i, a_j \rangle$, where 70 | $i=k/n$ and $j=((k-1)-l*n)/r]$. 71 | 72 | 73 | ## Inversion Count 74 | 75 | * [Spoj](http://www.spoj.com/problems/INVCNT/) 76 | * [Code](/code/InversionCount.cpp) 77 | 78 | [Possible solutions](http://www.geeksforgeeks.org/counting-inversions/) 79 | 80 | 81 | ## Largest Even Number 82 | 83 | * [Code](/code/LargestEvenNumber.cpp) 84 | 85 | 86 | ## Firing Employees 87 | 88 | * [Code](/code/FiringEmployees.cpp) 89 | 90 | 91 | ## Is BST? 92 | 93 | * [Code](/code/IsBST.cpp) 94 | 95 | 96 | ## Preorder Traversal of BST 97 | 98 | * [Code](/code/PreorderTraversal.cpp) 99 | 100 | 101 | ## Two Heaps 102 | 103 | * [Codeforces](http://codeforces.com/problemset/problem/353/B?locale=en) 104 | * [Code](/code/TwoHeaps.cpp) 105 | 106 | Sort the values and for each value keep at most 2 occurrences. Let $c$ be 107 | the number of the remaining values. The number of possible fourdigit integers is 108 | $k=(c/2)(c-c/2)$. The assignment is done as follows: 109 | 110 | * Half of the excluded values are assigned to 1, the other to 2. 111 | * Remaining values are uniformly distributed among 1 or 2 taking care of 112 | assigning values with two occurrences to both sets. 113 | 114 | 115 | ## Maximum Path Sum 116 | 117 | * [Geeks for Geeks](http://practice.geeksforgeeks.org/problems/maximum-path-sum/1) 118 | * [Code](/code/MaximumPathSum.cpp) 119 | 120 | 121 | ## Ilya and Queries 122 | 123 | * [Codeforces](http://codeforces.com/problemset/problem/313/B?locale=en) 124 | * [Code](/code/IlyaQueries.cpp) 125 | 126 | Use prefix sums of the array $L[0,n]$ where $L[i] = 1$ iff $s_i = s_{i+1}$. 127 | 128 | 129 | ## Alice, Bob and Chocolate 130 | 131 | * [Codeforces](http://codeforces.com/problemset/problem/6/C?locale=en) 132 | * [Code](/code/Chocolate.cpp) 133 | 134 | 135 | ## Number of Ways 136 | 137 | * [Codeforces](http://codeforces.com/problemset/problem/466/C?locale=en) 138 | * [Code](/code/NumberWays.cpp) 139 | 140 | Let $S$ be the sum of the values in the array. If $3$ doesn't divide $S$, we 141 | conclude that the number of ways is zero. Otherwise, we compute the array 142 | $C$ which stores in position $i$ the number of suffixes of $a[i\ldots n]$ that 143 | sum to $\frac{S}{3}$. We then compute the sum of the prefixes of $a$. 144 | Every time a prefix $i$ sums to $\frac{S}{3}$, we add $c[i+2]$ to the result. 145 | 146 | 147 | ## Little Girl and Maximum 148 | 149 | * [Codeforces](http://codeforces.com/problemset/problem/276/C?locale=en) 150 | * [Code](/code/LittleGirl.cpp) 151 | 152 | We need to sort the entries of the array by their access frequencies and then 153 | assign the largest values to the most frequently accessed slots. We could use 154 | an array to keep track of the frequencies of the entries. However, let $S$ be 155 | the sum of the length of queries size, just updating the above array would cost 156 | $\Theta(q+S)$. However, $S$ may be $\Theta(qn)$ and, thus, this solution is 157 | quite inefficient. 158 | 159 | Thus, we need a cleaver way to compute those frequencies. The idea is to 160 | construct an array $F[1\ldots n]$, initially all the entries are set to $0$. If 161 | we read the query $\langle l_i, r_i \rangle$, we add $1$ to $F[l_i]$ and we 162 | subtract $-1$ to $F[r_i+1]$. The prefix sum of $F$ up to $i$ equals the 163 | frequency of entry $i$. This algorithm costs only $O(q+n)$ time. 164 | 165 | 166 | ## Update the Array 167 | 168 | * [Spoj](http://www.spoj.com/problems/UPDATEIT/) 169 | * [Code](/code/UpdateArray.cpp) 170 | 171 | We use a Fenwick tree F. For the update $l$, $r$, $val$ we add $val$ to $F[l]$ 172 | and we substract $val$ to $F[r+1]$. This way, the value at position $i$ is 173 | simply the sum from $F[0]$ to $F[i]$. 174 | 175 | 176 | ## Nested Segments 177 | 178 | * [CodeForces](http://codeforces.com/problemset/problem/652/D?locale=en) 179 | * [Code](/code/NestedSegments.cpp) 180 | 181 | See lecture notes. 182 | 183 | 184 | ## Pashmak and Parmida's problem 185 | 186 | * [CodeForces](http://codeforces.com/problemset/problem/459/D?locale=en) 187 | * [Code](/code/PashmakParmida.cpp) 188 | 189 | See lecture notes. 190 | -------------------------------------------------------------------------------- /code/Chocolate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | vector get_input_sequence(size_t n) { 9 | vector sequence(n); 10 | 11 | for(size_t i = 0; i < n; ++i) 12 | cin >> sequence[i]; 13 | return sequence; 14 | } 15 | 16 | int main() { 17 | std::ios_base::sync_with_stdio(false); 18 | 19 | size_t n; 20 | cin >> n; 21 | 22 | auto v = get_input_sequence(n); 23 | 24 | uint32_t sum = accumulate(v.begin(), v.end(), 0); 25 | uint32_t prefix_sum = 0; 26 | size_t i = 0; 27 | while(i < n and prefix_sum < sum) { 28 | sum -= v[i]; 29 | prefix_sum += v[i]; 30 | i++; 31 | } 32 | 33 | if(i != 0 and sum < prefix_sum - v[i-1]) i--; // who is going to eat i-th bar? 34 | 35 | cout << i << " " << n-i << endl; 36 | return 0; 37 | } -------------------------------------------------------------------------------- /code/FindPair.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | vector get_input_sequence(size_t n) { 9 | vector sequence(n); 10 | 11 | for(size_t i = 0; i < n; ++i) 12 | cin >> sequence[i]; 13 | return sequence; 14 | } 15 | 16 | int main() { 17 | std::ios_base::sync_with_stdio(false); 18 | 19 | uint64_t n, k; 20 | cin >> n; 21 | cin >> k; 22 | 23 | auto numbers = get_input_sequence(n); 24 | sort(numbers.begin(), numbers.end()); 25 | 26 | uint64_t i = (k-1)/n; 27 | int first = numbers[i]; 28 | uint64_t l; // number of values smaller than first 29 | for(l = 0; l < n; l++) 30 | if(numbers[l] == first) break; 31 | 32 | uint64_t r = count(numbers.begin(), numbers.end(), first); 33 | int second = numbers[((k-1)-l*n)/r]; 34 | 35 | cout << first << " " << second << endl; 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /code/FindingTeamMember.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | struct team { 8 | size_t m1; 9 | size_t m2; 10 | int32_t strength; 11 | 12 | team(size_t a, size_t b, int64_t s) 13 | : m1(a) 14 | , m2(b) 15 | , strength(s) {} 16 | }; 17 | 18 | int main() { 19 | std::ios_base::sync_with_stdio(false); 20 | 21 | size_t n; 22 | cin >> n; 23 | 24 | vector teams; 25 | teams.reserve(n*(n-1)/2); 26 | 27 | for(size_t i = 1; i < 2*n; ++i) { 28 | for(size_t j = 0; j < i; ++j) { 29 | int32_t strength; 30 | cin >> strength; 31 | teams.emplace_back(i, j, strength); 32 | } 33 | } 34 | 35 | sort(teams.begin(), 36 | teams.end(), 37 | [](const team &a, const team &b) { 38 | return a.strength > b.strength; 39 | } 40 | ); 41 | 42 | vector assign(2*n); 43 | for(auto &team: teams) { 44 | if(assign[team.m1] == 0 and assign[team.m2] == 0) { 45 | assign[team.m1] = team.m2 + 1; // +1, 0 is reserved to "no assigment yet" 46 | assign[team.m2] = team.m1 + 1; 47 | } 48 | } 49 | 50 | for(auto assigment: assign) 51 | cout << assigment << " "; 52 | cout << endl; 53 | 54 | return 0; 55 | } -------------------------------------------------------------------------------- /code/FiringEmployees.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // problem: http://practice.geeksforgeeks.org/problems/firing-employees/0 7 | 8 | /* Marks the prime numbers up to n with Sieve of Eratosthenes http://www.geeksforgeeks.org/sieve-of-eratosthenes/ */ 9 | std::vector generate_primes(size_t n) { 10 | std::vector primes(n, true); 11 | for(uint64_t i = 2; i <= (uint64_t) sqrt(n); ++i) { 12 | if (primes[i]) { 13 | uint64_t isquare = i*i; 14 | for(uint64_t j = isquare; j < n; j+=i) 15 | primes[j] = false; 16 | } 17 | } 18 | 19 | return primes; 20 | } 21 | 22 | int num_fired_employees(std::vector const& vec) { 23 | 24 | size_t n = vec.size(); 25 | 26 | // save the position of employees' ranks in original array 27 | std::vector> positions(n + 1, std::vector()); 28 | for (int i = 0; i < n; ++i) { 29 | positions[vec[i]].push_back(i + 1); 30 | } 31 | 32 | std::vector seniors(n + 1, 0); 33 | 34 | std::stack s; 35 | 36 | // for each employee calculate the number of his/her seniors 37 | s.push(positions[0].front()); // position of Mr. Alfred 38 | for (int i = 0; i < n; ++i) { 39 | auto list = positions[s.top()]; 40 | s.pop(); 41 | for (auto pos: list) { 42 | seniors[pos] = 1 + seniors[vec[pos - 1]]; 43 | s.push(pos); 44 | } 45 | } 46 | 47 | auto primes = generate_primes(2*(n+1)); 48 | int fired_employees = 0; 49 | for (int i = 1; i <= n; ++i) { 50 | if (seniors[i] and primes[seniors[i] + i]) { 51 | ++fired_employees; 52 | } 53 | } 54 | 55 | return fired_employees; 56 | } 57 | 58 | int main() { 59 | std::ios_base::sync_with_stdio(false); 60 | 61 | int num_test_cases = 0; 62 | std::cin >> num_test_cases; 63 | 64 | std::vector vec; 65 | for (int i = 0; i < num_test_cases; ++i) { 66 | int n = 0; 67 | std::cin >> n; 68 | vec.reserve(n); 69 | for (int j = 0; j < n; ++j) { 70 | int x = 0; 71 | std::cin >> x; 72 | vec.push_back(x); 73 | } 74 | 75 | std::cout << num_fired_employees(vec) << std::endl; 76 | vec.clear(); 77 | } 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /code/IlyaQueries.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | std::ios_base::sync_with_stdio(false); 9 | 10 | string s; 11 | cin >> s; 12 | 13 | size_t n = s.length(); 14 | vector sums(n+1); 15 | sums[0] = 0; 16 | for(size_t i = 1; i < n; ++i) { 17 | sums[i] = s[i-1] == s[i] ? sums[i-1] + 1 : sums[i-1]; 18 | } 19 | sums[n] = sums[n-1]; 20 | 21 | size_t q; 22 | cin >> q; 23 | for(size_t i = 0; i < q; ++i) { 24 | int l, r; 25 | cin >> l >> r; 26 | cout << sums[r-1]-sums[l-1] << endl; 27 | } 28 | 29 | return 0; 30 | } -------------------------------------------------------------------------------- /code/InversionCount.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | template 9 | vector get_input_sequence(size_t n) { 10 | vector sequence(n); 11 | 12 | for(size_t i = 0; i < n; ++i) 13 | cin >> sequence[i]; 14 | return sequence; 15 | } 16 | 17 | uint64_t merge_and_count(vector& A, size_t l, size_t middle, size_t r ) { 18 | size_t i = l; 19 | size_t j = middle + 1; 20 | vector B((r-l)+1); 21 | size_t k = 0; 22 | uint64_t n_invs = 0; 23 | 24 | while((i <= middle) and (j <= r)) { 25 | if(A[i] < A[j]) { 26 | B[k++] = A[i++]; 27 | } else { 28 | B[k++] = A[j++]; 29 | n_invs += middle-i+1; 30 | } 31 | } 32 | 33 | while(i <= middle) { 34 | B[k++] = A[i++]; 35 | } 36 | 37 | while(j <= r) { 38 | B[k++] = A[j++]; 39 | } 40 | 41 | copy(B.begin(), B.end(), A.begin()+l); 42 | 43 | return n_invs; 44 | } 45 | 46 | /* Sort and count the number of invertions in A[l..r] */ 47 | uint64_t sort_and_count(vector& A, size_t l, size_t r ) { 48 | if(l >= r) return 0; 49 | size_t middle = (l+r)/2; 50 | uint64_t l_count = sort_and_count(A, l, middle); 51 | uint64_t r_count = sort_and_count(A, middle + 1, r); 52 | return l_count + r_count + merge_and_count(A, l, middle, r); 53 | } 54 | 55 | 56 | int main() { 57 | string blank; 58 | size_t n_tests; 59 | cin >> n_tests; 60 | getline(cin, blank); 61 | 62 | for(size_t i = 0; i < n_tests; ++i) { 63 | size_t n; 64 | cin >> n; 65 | auto A = get_input_sequence(n); 66 | getline(cin, blank); 67 | uint64_t n_invs = sort_and_count(A, 0, n-1); 68 | 69 | cout << n_invs << endl; 70 | } 71 | 72 | return 0; 73 | } -------------------------------------------------------------------------------- /code/IsBST.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Please note that it's Function problem i.e. 3 | you need to write your solution in the form of Function(s) only. 4 | Driver Code to call/invoke your function would be added by GfG's Online Judge.*/ 5 | 6 | 7 | /* A binary tree node has data, pointer to left child 8 | and a pointer to right child 9 | struct Node { 10 | int data; 11 | Node* left, * right; 12 | }; */ 13 | /* Should return true if tree represented by root is BST. 14 | For example, return value should be 1 for following tree. 15 | 20 16 | / \ 17 | 10 30 18 | and return value should be 0 for following tree. 19 | 10 20 | / \ 21 | 20 30 */ 22 | 23 | 24 | // problem: http://practice.geeksforgeeks.org/problems/check-for-bst/1 25 | 26 | 27 | // smaller version 28 | // #include // for INT_MIN and INT_MAX 29 | 30 | // bool check(Node* root, int min, int max) { 31 | // if (!root) return true; // root is a leaf 32 | // if (root->data < min or root->data > max) return false; 33 | // return check(root->left, min, root->data - 1) and 34 | // check(root->right, root->data + 1, max); 35 | // } 36 | 37 | // bool isBST(Node* root) { 38 | // return check(root, INT_MIN, INT_MAX); 39 | // } 40 | 41 | std::pair min_max_subtree(Node* root, bool* res) { 42 | bool l = true; 43 | bool r = true; 44 | int curr_min = root->data; 45 | int curr_max = root->data; 46 | 47 | if (root->left) { 48 | auto left = min_max_subtree(root->left, &l); 49 | if (left.second > root->data) l = false; 50 | curr_min = std::min(curr_min, left.first); 51 | curr_max = std::max(curr_max, left.second); 52 | } 53 | if (root->right) { 54 | auto right = min_max_subtree(root->right, &r); 55 | if (right.first < root->data) r = false; 56 | curr_min = std::min(curr_min, right.first); 57 | curr_max = std::max(curr_max, right.second); 58 | } 59 | 60 | *res = l&&r; 61 | return std::make_pair(curr_min, curr_max); 62 | } 63 | 64 | bool isBST(Node* root) { 65 | if(!root) return true; 66 | bool res = true; 67 | auto p = min_max_subtree(root, &res); 68 | return res; 69 | } 70 | -------------------------------------------------------------------------------- /code/Kadane.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // problem: http://practice.geeksforgeeks.org/problems/kadanes-algorithm/0 5 | 6 | /* 7 | Property 1: the max-sum subarray cannot start with a negative number 8 | (the first element to the left of its beginning is negative), 9 | otherwise we could just remove its beninning and obtain a new 10 | subarray whose elements' sum is greater. 11 | 12 | Property 2: the sums of each prefix in the max-sum subarray must be positives, 13 | otherwise we could just remove the prefix of negative sum to obtain 14 | a new subarray whose elements' sum is greater. 15 | */ 16 | void print_max_sum_subarry(std::vector const& vec) { 17 | int sum = vec.front(); // thus skip first element 18 | int max_sum = sum; 19 | 20 | for (auto it = vec.begin() + 1; it != vec.end(); ++it) { 21 | if (sum > 0) { 22 | sum += *it; 23 | } else { 24 | sum = *it; 25 | } 26 | 27 | if (sum > max_sum) { 28 | max_sum = sum; 29 | } 30 | } 31 | 32 | std::cout << max_sum << std::endl; 33 | } 34 | 35 | int main() { 36 | 37 | int num_test_cases = 0; 38 | std::cin >> num_test_cases; 39 | 40 | std::vector vec; 41 | for (int i = 0; i < num_test_cases; ++i) { 42 | int n = 0; 43 | std::cin >> n; 44 | vec.reserve(n); 45 | for (int j = 0; j < n; ++j) { 46 | int x = 0; 47 | std::cin >> x; 48 | vec.push_back(x); 49 | } 50 | print_max_sum_subarry(vec); 51 | vec.clear(); 52 | } 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /code/LargestEvenNumber.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // for memmove 5 | 6 | // problem: http://practice.geeksforgeeks.org/problems/largest-even-number/0 7 | 8 | // assume digits span a consecutive range, i.e., [min_digit..min_digit + num_digits] 9 | template 10 | void counting_sort(Digital& a, size_t n, int num_digits, Digit min_digit, bool reverse = false) { 11 | 12 | std::vector counts(num_digits + 1, 0); 13 | for (size_t i = 0; i < n; ++i) { 14 | ++counts[a[i] - min_digit]; 15 | } 16 | 17 | for (uint32_t i = 1; i <= num_digits; ++i) { 18 | counts[i] += counts[i - 1]; 19 | } 20 | 21 | Digital temp; 22 | temp.resize(n); 23 | 24 | // could do this with bool tricks 25 | size_t offset = 0; 26 | int sign = 1; 27 | int b = -1; 28 | 29 | if (reverse) { 30 | offset = n; 31 | sign = -1; 32 | b = 0; 33 | } 34 | 35 | for (size_t i = 0; i < n; ++i) { 36 | temp[offset + sign * counts[a[i] - min_digit] + b] = std::move(a[i]); 37 | --counts[a[i] - min_digit]; 38 | } 39 | 40 | std::move(temp.begin(), temp.end(), a.begin()); 41 | } 42 | 43 | void largest_even_number(std::string& str) { 44 | // ASCII codes for '0' to '9' span a consecutive range ([48..57]) 45 | bool reverse = true; 46 | counting_sort(str, str.size(), 10, '0', reverse); 47 | 48 | // determine the position of the smallest even number (if present) 49 | uint64_t i = str.size() - 1; 50 | while (str[i] % 2) { 51 | if (!i) break; 52 | --i; 53 | } 54 | 55 | if (str[i] % 2 == 0) { // could not contain any even number 56 | char x = str[i]; 57 | // shift left by 1 58 | memmove(&str[i], &str[i + 1], str.size() - i - 1); 59 | str.back() = x; 60 | } 61 | } 62 | 63 | int main() { 64 | 65 | int num_test_cases = 0; 66 | std::cin >> num_test_cases; 67 | 68 | std::string str; 69 | for (int i = 0; i < num_test_cases; ++i) { 70 | std::cin >> str; 71 | largest_even_number(str); 72 | std::cout << str << std::endl; 73 | str.clear(); 74 | } 75 | 76 | return 0; 77 | } 78 | 79 | int main() { 80 | 81 | int num_test_cases = 0; 82 | std::cin >> num_test_cases; 83 | 84 | std::string str; 85 | for (int i = 0; i < num_test_cases; ++i) { 86 | std::vector occs(10,0); 87 | std::cin >> str; 88 | 89 | for(auto &c : str) { 90 | int c_id = c - '0'; 91 | occs[c_id]++; 92 | } 93 | 94 | int min_even = 10; 95 | int min_odd = 11; 96 | for(int i = 8; i >= 0; i-=2) 97 | if(occs[i]>0) min_even = i; 98 | for(int i = 9; i >= 0; i-=2) 99 | if(occs[i]>0) min_odd = i; 100 | 101 | if(min_even > min_odd) occs[min_even]--; 102 | for(int i = 9; i >= 0; --i) 103 | for(int j = 0; j < occs[i]; ++j) 104 | std::cout << i; 105 | if(min_even > min_odd && min_even != 10) std::cout << min_even; 106 | 107 | std::cout << std::endl; 108 | str.clear(); 109 | } 110 | 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /code/Leaders.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // problem: http://practice.geeksforgeeks.org/problems/leaders-in-an-array/0 5 | 6 | void print_leaders(std::vector const& vec) { 7 | 8 | std::vector leaders; // accumulate leaders to print them in original order 9 | leaders.reserve(vec.size()); 10 | int max = vec.back(); 11 | leaders.push_back(max); // last element is always a leader 12 | for (auto it = vec.rbegin() + 1; it != vec.rend(); ++it) { 13 | if (*it > max) { 14 | max = *it; 15 | leaders.push_back(max); 16 | } 17 | } 18 | 19 | for (auto it = leaders.rbegin(); it != leaders.rend(); ++it) { 20 | std::cout << *it << " "; 21 | } 22 | std::cout << std::endl; 23 | } 24 | 25 | int main() { 26 | 27 | int num_test_cases = 0; 28 | std::cin >> num_test_cases; 29 | 30 | std::vector vec; 31 | for (int i = 0; i < num_test_cases; ++i) { 32 | int n = 0; 33 | std::cin >> n; 34 | vec.reserve(n); 35 | for (int j = 0; j < n; ++j) { 36 | int x = 0; 37 | std::cin >> x; 38 | vec.push_back(x); 39 | } 40 | print_leaders(vec); 41 | vec.clear(); 42 | } 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /code/LittleGirl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | vector get_input_sequence(size_t n) { 9 | vector sequence(n); 10 | 11 | for(size_t i = 0; i < n; ++i) 12 | cin >> sequence[i]; 13 | return sequence; 14 | } 15 | 16 | int main() { 17 | std::ios_base::sync_with_stdio(false); 18 | 19 | size_t n, q; 20 | cin >> n; 21 | cin >> q; 22 | auto array = get_input_sequence(n); 23 | 24 | vector F(n+1); 25 | 26 | int l, r; 27 | for(size_t i = 0; i < q; ++i) { 28 | cin >> l >> r; 29 | F[l-1] += 1; 30 | F[r] -= 1; 31 | } 32 | 33 | /* Prefix sums */ 34 | for(size_t i = 1; i < n; ++i) 35 | F[i] += F[i-1]; 36 | 37 | sort(array.begin(), array.end()); 38 | sort(F.begin(), F.end()-1); 39 | 40 | int64_t result = 0; 41 | for(size_t i = 0; i < n; ++i) 42 | result += static_cast(F[i])*static_cast(array[i]); 43 | 44 | cout << result << endl; 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /code/MaximumPathSum.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Please note that it's Function problem i.e. 3 | you need to write your solution in the form of Function(s) only. 4 | Driver Code to call/invoke your function would be added by GfG's Online Judge.*/ 5 | 6 | 7 | /*Complete the function below 8 | Node is as follows 9 | struct Node{ 10 | int data; 11 | Node *left, *right; 12 | }; 13 | */ 14 | 15 | int maxLeaf(struct Node *root, int *max) { 16 | if (root == NULL) return INT_MIN; 17 | int pathleft = maxLeaf(root->left, max); 18 | int pathright = maxLeaf(root->right, max); 19 | 20 | if ((pathleft == INT_MIN) && (pathright == INT_MIN)) return root->data; 21 | 22 | int pathcurr = root->data; 23 | pathcurr += pathleft > pathright ? pathleft : pathright; 24 | 25 | if ((pathleft != INT_MIN) && (pathright != INT_MIN)) { 26 | int maxcurr = root->data + pathleft + pathright; 27 | *max = maxcurr > *max ? maxcurr : *max; 28 | } 29 | 30 | return pathcurr; 31 | } 32 | 33 | 34 | int maxPathSum(struct Node *root) { 35 | int max = INT_MIN; 36 | maxLeaf(root, &max); 37 | return max; 38 | } 39 | -------------------------------------------------------------------------------- /code/Megacity.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include /* sqrt */ 5 | 6 | using namespace std; 7 | 8 | int main(){ 9 | std::ios_base::sync_with_stdio(false); 10 | 11 | size_t n; 12 | cin >> n; 13 | int pop; 14 | cin >> pop; 15 | 16 | vector> cities; 17 | cities.reserve(n); 18 | 19 | for(size_t i = 0; i < n; i++) { 20 | int x, y, population; 21 | cin >> x >> y >> population; 22 | double distance = sqrt(x*x + y*y); 23 | cities.emplace_back(distance, population); 24 | } 25 | 26 | sort(cities.begin(), 27 | cities.end(), 28 | [](const pair & a, const pair & b) { 29 | return a.first= 1000000) { 36 | cout.precision(8); 37 | cout << a.first << endl; 38 | return 0; 39 | } 40 | } 41 | 42 | cout << -1 << endl; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /code/MissingNumber.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // problem: http://practice.geeksforgeeks.org/problems/missing-number-in-array/0 4 | 5 | int main() { 6 | int num_test_cases = 0; 7 | std::cin >> num_test_cases; 8 | 9 | for (int i = 0; i < num_test_cases; ++i) { 10 | int n = 0; 11 | std::cin >> n; 12 | int sum = 0; 13 | int total_sum = n * (n + 1) / 2; 14 | for (int j = 0; j < n - 1; ++j) { 15 | int x = 0; 16 | std::cin >> x; 17 | sum += x; 18 | } 19 | std::cout << total_sum - sum << "\n"; 20 | } 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /code/NestedSegments.cpp: -------------------------------------------------------------------------------- 1 | // Solution by Italo Guarrieri 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "fenwick_tree.h" 7 | 8 | int main() { 9 | std::ios_base::sync_with_stdio(false); 10 | 11 | int64_t n; 12 | std::cin >> n; 13 | 14 | std::vector> vet(n); 15 | std::vector all_elem; 16 | for (int64_t i = 0; i < n; ++i) { 17 | int64_t a, b; 18 | std::cin >> a; 19 | std::cin >> b; 20 | all_elem.push_back(a); 21 | all_elem.push_back(b); 22 | vet[i]=std::tuple(a,b,i); 23 | } 24 | 25 | std::sort(all_elem.begin(), all_elem.end()); 26 | for (int64_t i = 0; i < n; ++i) { 27 | std::get<0>(vet[i]) = (int64_t) (std::lower_bound(all_elem.begin(), all_elem.end(), std::get<0>(vet[i])) - all_elem.begin()); 28 | std::get<1>(vet[i]) = (int64_t) (std::lower_bound(all_elem.begin(), all_elem.end(), std::get<1>(vet[i])) - all_elem.begin()); 29 | 30 | } 31 | 32 | std::sort(vet.begin(), vet.end(), [](const std::tuple & a, const std::tuple & b) { 33 | return std::get<0>(a)(b); 34 | }); 35 | 36 | int64_t size_ft = all_elem.size(); 37 | 38 | fenwick_tree s(size_ft); 39 | for (int64_t i = 0; i < n; ++i) { 40 | s.add(std::get<1>(vet.at(i)), 1); 41 | } 42 | 43 | std::vector res(n); 44 | for (int64_t i = 0; i < n; ++i) { 45 | res[std::get<2>(vet.at(i))]=s.sum(std::get<1>(vet.at(i)))-1; 46 | s.add(std::get<1>(vet.at(i)), -1); 47 | } 48 | 49 | for (int64_t i = 0; i < n; ++i) { 50 | std::cout << res[i] << std::endl; 51 | } 52 | 53 | return 0; 54 | } -------------------------------------------------------------------------------- /code/NextLargerElements.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // problem: http://practice.geeksforgeeks.org/problems/next-larger-element/0 6 | 7 | struct int_type { 8 | 9 | int_type(int v) 10 | : val(v) 11 | {} 12 | 13 | void operator>>(int_type x) { 14 | std::cin >> x.val; 15 | } 16 | 17 | friend void operator>>(std::istream& in, int_type& x) { 18 | in >> x.val; 19 | } 20 | 21 | friend std::ostream& operator<<(std::ostream& out, int_type x) { 22 | out << x.val; 23 | return out; 24 | } 25 | 26 | static int_type invalid() { 27 | return int_type(-1); 28 | } 29 | 30 | int64_t val; 31 | }; 32 | 33 | template 34 | std::vector next_larger_elements(std::vector const& vec, GreaterFunc g) { 35 | 36 | std::vector results; // accumulate results here 37 | results.reserve(vec.size()); 38 | 39 | std::stack s; 40 | 41 | for (auto it = vec.rbegin(); it != vec.rend(); ++it) { 42 | auto next_greater = T::invalid(); 43 | while (!s.empty()) { 44 | auto tos = s.top(); 45 | if (g(tos, *it)) { 46 | next_greater = tos; 47 | break; 48 | } 49 | s.pop(); 50 | } 51 | results.push_back(next_greater); 52 | s.push(*it); 53 | } 54 | 55 | return results; 56 | } 57 | 58 | int main() { 59 | 60 | int num_test_cases = 0; 61 | std::cin >> num_test_cases; 62 | 63 | std::vector vec; 64 | for (int i = 0; i < num_test_cases; ++i) { 65 | int n = 0; 66 | std::cin >> n; 67 | vec.reserve(n); 68 | for (int j = 0; j < n; ++j) { 69 | int_type x = 0; 70 | std::cin >> x; 71 | vec.push_back(x); 72 | } 73 | auto res = next_larger_elements(vec, 74 | [](int_type x, int_type y) { 75 | return x.val > y.val; 76 | } 77 | ); 78 | 79 | for (auto it = res.rbegin(); 80 | it != res.rend(); ++it) { 81 | std::cout << *it << " "; 82 | } 83 | std::cout << std::endl; 84 | 85 | vec.clear(); 86 | } 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /code/NumberWays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | template 9 | vector get_input_sequence(size_t n) { 10 | vector sequence(n); 11 | 12 | for(size_t i = 0; i < n; ++i) 13 | cin >> sequence[i]; 14 | return sequence; 15 | } 16 | 17 | int main() { 18 | std::ios_base::sync_with_stdio(false); 19 | 20 | int n; 21 | cin >> n; 22 | auto a = get_input_sequence(n); 23 | auto c = vector(n, 0); 24 | 25 | int64_t S = 0; 26 | 27 | for(auto x : a) 28 | S +=x; 29 | 30 | if(S % 3 != 0) { 31 | cout << "0\n"; 32 | return 0; 33 | } 34 | 35 | S /= 3; 36 | int64_t L = 0, counter = 0; 37 | for(int i = n-1; i >= 0; --i) { 38 | L += a[i]; 39 | if(L == S) 40 | c[i] = 1; 41 | } 42 | 43 | for(int i = n-2; i >= 0; --i) 44 | c[i] += c[i+1]; 45 | 46 | L = 0; 47 | int64_t results = 0; 48 | for(int i = 0; i < n-2; ++i) { 49 | L += a[i]; 50 | if(L == S) results+=c[i+2]; 51 | } 52 | 53 | cout << results << endl; 54 | 55 | return 0; 56 | } -------------------------------------------------------------------------------- /code/PashmakParmida.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "fenwick_tree.hpp" 5 | 6 | using namespace std; 7 | 8 | template 9 | vector get_input_sequence(size_t n) { 10 | vector sequence(n); 11 | 12 | for(size_t i = 0; i < n; ++i) 13 | cin >> sequence[i]; 14 | return sequence; 15 | } 16 | 17 | template 18 | void remap(vector& a) { 19 | vector tmp(a.size()); 20 | copy(a.begin(), a.end(), tmp.begin()); 21 | sort(tmp.begin(), tmp.end()); 22 | size_t sz = distance(tmp.begin(), unique(tmp.begin(), tmp.end())); 23 | tmp.resize(sz); 24 | 25 | for(auto &x : a) 26 | x = distance(tmp.begin(), lower_bound(tmp.begin(), tmp.end(), x)); 27 | } 28 | 29 | int main() { 30 | size_t n; 31 | cin >> n; 32 | 33 | auto a = get_input_sequence(n); 34 | remap(a); 35 | 36 | fenwick_tree f(n); 37 | vector suffix_counter(n); 38 | vector counter(n); 39 | 40 | for(int i = n-1; i >= 0; --i) { 41 | counter[a[i]]++; 42 | suffix_counter[i] = counter[a[i]]; // number occs a[i] in a[i..n-1] 43 | f.add(counter[a[i]], 1); 44 | } 45 | 46 | fill(counter.begin(), counter.end(), 0); 47 | 48 | uint64_t res = 0; 49 | for(int i = 0; i < n; ++i) { 50 | f.add(suffix_counter[i], -1); 51 | counter[a[i]]++; // number occs a[i] in a[0..i] 52 | res += f.sum(counter[a[i]]-1); 53 | } 54 | 55 | cout << res << endl; 56 | return 0; 57 | } -------------------------------------------------------------------------------- /code/PreorderTraversal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // problem: http://practice.geeksforgeeks.org/problems/preorder-traversal-and-bst/0 7 | 8 | int check_preorder(std::vector const& visit) { 9 | 10 | int root = INT_MIN; 11 | std::stack s; 12 | 13 | for (auto current: visit) { 14 | 15 | // we maintain the invariant 16 | // of being in a right subtree 17 | if (current < root) return 0; 18 | 19 | while (!s.empty()) { // find next greater 20 | if (current < s.top()) { 21 | s.pop(); 22 | } else { 23 | root = s.top(); 24 | break; 25 | } 26 | } 27 | 28 | // now current is next greater of root, 29 | // therefore we are in a right subtree 30 | s.push(current); 31 | } 32 | 33 | return 1; 34 | } 35 | 36 | int main() { 37 | std::ios_base::sync_with_stdio(false); 38 | 39 | int num_test_cases = 0; 40 | std::cin >> num_test_cases; 41 | 42 | std::vector vec; 43 | for (int i = 0; i < num_test_cases; ++i) { 44 | int n = 0; 45 | std::cin >> n; 46 | vec.reserve(n); 47 | for (int j = 0; j < n; ++j) { 48 | int x = 0; 49 | std::cin >> x; 50 | vec.push_back(x); 51 | } 52 | 53 | std::cout << check_preorder(vec) << std::endl; 54 | vec.clear(); 55 | } 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /code/SlidingWindowMaxima.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // problem: http://practice.geeksforgeeks.org/problems/maximum-of-all-subarrays-of-size-k/0 6 | 7 | template 8 | std::vector sliding_window_maximum(std::vector const& A, int k) { 9 | std::deque Q; // Q will store positions not values 10 | std::vector maxs; 11 | maxs.reserve(A.size() - k + 1); 12 | 13 | for (int i = 0 ; i < A.size(); ++i) { 14 | // Removes from front elements which are no longer in the window 15 | while (!Q.empty() and Q.front() <= i - k) { 16 | Q.pop_front(); 17 | } 18 | 19 | // Removes from back elements which are no longer useful, i.e., no greater than the current element 20 | while (!Q.empty() and A[i] >= A[Q.back()]) { 21 | Q.pop_back(); 22 | } 23 | 24 | Q.push_back(i); 25 | 26 | if (i >= k - 1) { 27 | maxs.push_back(A[Q.front()]); 28 | } 29 | } 30 | 31 | return maxs; 32 | } 33 | 34 | int main() { 35 | std::ios_base::sync_with_stdio(false); 36 | 37 | int num_test_cases = 0; 38 | std::cin >> num_test_cases; 39 | 40 | std::vector vec; 41 | for (int i = 0; i < num_test_cases; ++i) { 42 | int n = 0; 43 | int k = 0; 44 | std::cin >> n; 45 | std::cin >> k; 46 | vec.reserve(n); 47 | for (int j = 0; j < n; ++j) { 48 | int x = 0; 49 | std::cin >> x; 50 | vec.push_back(x); 51 | } 52 | 53 | auto res = sliding_window_maximum(vec, k); 54 | for (auto const& x: res) { 55 | std::cout << x << " "; 56 | } 57 | std::cout << std::endl; 58 | 59 | vec.clear(); 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /code/Towers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | template 8 | vector get_input_sequence(size_t n) { 9 | vector sequence(n); 10 | 11 | for(size_t i = 0; i < n; ++i) 12 | cin >> sequence[i]; 13 | return sequence; 14 | } 15 | 16 | int main() { 17 | std::ios_base::sync_with_stdio(false); 18 | 19 | size_t n; 20 | cin >> n; 21 | auto length = get_input_sequence(n); 22 | sort(length.begin(), length.end()); 23 | 24 | size_t numTowers = 0, currentLength = 0, currentHeight = 0, maxHeight = 1; 25 | for(size_t k = 0; k < n; k++) { 26 | if(length[k] == currentLength) { 27 | currentHeight += 1; 28 | if(currentHeight > maxHeight) 29 | maxHeight = currentHeight; 30 | } else { 31 | currentLength = length[k]; 32 | currentHeight = 1; 33 | numTowers++; 34 | } 35 | } 36 | cout << maxHeight << " " << numTowers << endl; 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /code/TrappingRainWater.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // problem: http://practice.geeksforgeeks.org/problems/trapping-rain-water/0 6 | 7 | template 8 | int trapped_rain_water(Iterator it, int& level) { 9 | if (*it > level) { 10 | level = *it; 11 | } 12 | int trapped_rain = level - *it; 13 | assert(trapped_rain >= 0); 14 | return trapped_rain; 15 | } 16 | 17 | void print_trapped_rain_water(std::vector const& vec) { 18 | auto begin = vec.begin(); 19 | auto end = vec.end() - 1; 20 | 21 | int tot_trapped_rain = 0; 22 | int level = 0; 23 | 24 | while (begin != end) { 25 | if (*begin <= *end) { 26 | tot_trapped_rain += trapped_rain_water(begin, level); 27 | ++begin; 28 | } else { 29 | tot_trapped_rain += trapped_rain_water(end, level); 30 | --end; 31 | } 32 | } 33 | 34 | std::cout << tot_trapped_rain << "\n"; 35 | }; 36 | 37 | int main() { 38 | 39 | int num_test_cases = 0; 40 | std::cin >> num_test_cases; 41 | 42 | std::vector vec; 43 | for (int i = 0; i < num_test_cases; ++i) { 44 | int n = 0; 45 | std::cin >> n; 46 | vec.reserve(n); 47 | for (int j = 0; j < n; ++j) { 48 | int x = 0; 49 | std::cin >> x; 50 | vec.push_back(x); 51 | } 52 | 53 | print_trapped_rain_water(vec); 54 | vec.clear(); 55 | } 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /code/TwoHeaps.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | std::ios_base::sync_with_stdio(false); 9 | size_t n; 10 | cin >> n; 11 | n = 2*n; 12 | 13 | vector> sequence(n); 14 | for(size_t i = 0; i < n; ++i) { 15 | cin >> sequence[i].first; 16 | sequence[i].second = i; 17 | } 18 | 19 | vector heaps(n); 20 | 21 | sort(sequence.begin(), sequence.end()); 22 | 23 | bool first_occ = true; 24 | int d_heap[3]; 25 | d_heap[1] = 0; d_heap[2] = 0; 26 | 27 | for(size_t i = 1; i < n; ++i) { 28 | if(sequence[i].first == sequence[i-1].first) { 29 | if(first_occ) { 30 | heaps[sequence[i-1].second] = 1; 31 | heaps[sequence[i].second] = 2; 32 | d_heap[1]++; d_heap[2]++; 33 | first_occ = false; 34 | } 35 | continue; 36 | } 37 | if(first_occ) { 38 | heaps[sequence[i-1].second] = (d_heap[1] > d_heap[2])+1; 39 | d_heap[heaps[sequence[i-1].second]]++; 40 | } 41 | first_occ = true; 42 | } 43 | 44 | if(first_occ and sequence[n-1] != sequence[n-2]) { 45 | heaps[sequence[n-1].second] = (d_heap[1] > d_heap[2])+1; 46 | d_heap[heaps[sequence[n-1].second]]++; 47 | } 48 | 49 | cout << d_heap[1] * d_heap[2] << endl; 50 | 51 | for(auto x: heaps) { 52 | if(x == 0) { 53 | x = (d_heap[1] > d_heap[2])+1; 54 | d_heap[x]++; 55 | } 56 | cout << x << " "; 57 | } 58 | cout << endl; 59 | return 0; 60 | } -------------------------------------------------------------------------------- /code/UpdateArray.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fenwick_tree.hpp" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | size_t n_tests; 8 | cin >> n_tests; 9 | 10 | for(size_t i = 0; i < n_tests; ++i) { 11 | size_t n, u; 12 | cin >> n; 13 | cin >> u; 14 | fenwick_tree F(n+1); 15 | 16 | int l, r, val; 17 | for(size_t j = 0; j < u; ++j) { 18 | scanf("%u%d%d", &l, &r, &val); 19 | F.add(l, val); 20 | F.add(r+1, -1*val); 21 | } 22 | 23 | size_t q; 24 | cin >> q; 25 | for(size_t j = 0; j < q; ++j) { 26 | scanf("%d", &l); 27 | cout << F.sum(l) << endl; 28 | } 29 | } 30 | 31 | return 0; 32 | } -------------------------------------------------------------------------------- /code/fenwick_tree.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | Code from https://github.com/spaghetti-source/algorithm/blob/master/data_structure/fenwick_tree.cc 5 | */ 6 | 7 | #include 8 | 9 | template 10 | struct fenwick_tree { 11 | std::vector x; 12 | fenwick_tree(size_t n) : x(n+1) { } 13 | 14 | // initialize by a constant 15 | fenwick_tree(size_t n, T a) : x(n+1, a) { 16 | x[0] = 0; 17 | for (int k = 1; k+(k&-k) <= n; ++k) x[k+(k&-k)] += x[k]; 18 | } 19 | 20 | // initialize by a std::vector 21 | fenwick_tree(std::vector y) : x(y.size()+1) { 22 | for (int k = 0; k < y.size(); ++k) x[k+1] = y[k]; 23 | for (int k = 1; k+(k&-k) < x.size(); ++k) x[k+(k&-k)] += x[k]; 24 | } 25 | 26 | // b[k] += a 27 | void add(int k, T a) { 28 | for (++k; k < x.size(); k += k&-k) x[k] += a; 29 | } 30 | 31 | // sum b[0,k) 32 | T sum(int k) { 33 | T s = 0; 34 | for (++k; k > 0; k &= k-1) s += x[k]; 35 | return s; 36 | } 37 | 38 | // min { k : sum(k) >= a }; it requires b[k] >= 0 39 | int lower_bound(T a) { 40 | if (a <= 0) return 0; 41 | int k = x.size()-1; 42 | for (int s: {1,2,4,8,16}) k |= (k >> s); 43 | for (int p = ++k; p > 0; p >>= 1, k |= p) 44 | if (k < x.size() && x[k] < a) a -= x[k]; else k ^= p; 45 | return k+1; 46 | } 47 | 48 | // max { k : sum(k) <= a }; it requires b[k] >= 0 49 | int upper_bound(T a) { 50 | int k = x.size()-1; 51 | for (int s: {1,2,4,8,16}) k |= (k >> s); 52 | for (int p = ++k; p > 0; p >>= 1, k |= p) 53 | if (k < x.size() && x[k] <= a) a -= x[k]; else k ^= p; 54 | return k; 55 | } 56 | }; -------------------------------------------------------------------------------- /code/segment_trees/gen_data.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import random 3 | 4 | n = int(sys.argv[1]) # num. leaves 5 | m = int(sys.argv[2]) # num. queries 6 | k = int(sys.argv[3]) # num. updates 7 | 8 | print n 9 | for i in xrange(0, n): 10 | print random.randint(0, 1000) 11 | print m 12 | for i in xrange(0, m): 13 | lo = random.randint(0, n) 14 | hi = random.randint(0, n) 15 | min = lo 16 | max = hi 17 | if min > max: 18 | print max, 19 | print min 20 | else: 21 | print min, 22 | print max 23 | print k 24 | for i in xrange(0, k): 25 | lo = random.randint(0, 200) 26 | hi = random.randint(0, 200) 27 | delta = random.randint(0, 100) 28 | min = lo 29 | max = hi 30 | if min > max: 31 | print max, 32 | print min, 33 | print delta 34 | else: 35 | print min, 36 | print max, 37 | print delta 38 | -------------------------------------------------------------------------------- /code/segment_trees/rmq_segment_tree.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rmq_segment_tree.hpp" 7 | 8 | template 9 | inline void do_not_optimize_away(T&& datum) { 10 | asm volatile("" : "+r" (datum)); 11 | } 12 | 13 | template 14 | struct range_min_query_operator { 15 | IntType operator()(IntType x, IntType y) { 16 | return std::min(x, y); 17 | } 18 | }; 19 | 20 | template 21 | struct range_max_query_operator { 22 | IntType operator()(IntType x, IntType y) { 23 | return std::max(x, y); 24 | } 25 | }; 26 | 27 | int main() { 28 | 29 | std::ios_base::sync_with_stdio(false); 30 | 31 | uint64_t n = 0; // number of leaves in the tree 32 | std::cin >> n; 33 | 34 | typedef std::chrono::high_resolution_clock clock_type; 35 | 36 | auto start = clock_type::now(); 37 | std::vector leaves; 38 | leaves.reserve(n); 39 | for (uint64_t i = 0; i < n; ++i) { 40 | int x = 0; 41 | std::cin >> x; 42 | leaves.push_back(x); 43 | } 44 | auto end = clock_type::now(); 45 | std::chrono::duration elapsed = end - start; 46 | std::cout << "parsing the input took: " << elapsed.count() << " [sec]" << std::endl; 47 | 48 | typedef rmq_segment_tree> segment_tree_type; 49 | // typedef rmq_segment_tree> segment_tree_type; 50 | 51 | segment_tree_type::type_traits traits; 52 | traits.invalid = std::numeric_limits::max(); 53 | // traits.invalid = std::numeric_limits::min(); 54 | 55 | std::cout << "building tree with " << n << " leaves" << std::endl; 56 | start = clock_type::now(); 57 | segment_tree_type::builder builder(leaves, traits); 58 | segment_tree_type min_seg_tree; 59 | builder.build(min_seg_tree); 60 | end = clock_type::now(); 61 | elapsed = end - start; 62 | std::cout << "building took: " << elapsed.count() << " [sec]" << std::endl; 63 | 64 | uint64_t m = 0; // number of queries 65 | std::cin >> m; 66 | 67 | std::vector queries; 68 | queries.reserve(m); 69 | 70 | for (uint64_t i = 0; i < m; ++i) { 71 | size_t lo, hi; 72 | std::cin >> lo >> hi; 73 | queries.emplace_back(lo, hi); 74 | } 75 | 76 | std::cout << "executing " << m << " range queries" << std::endl; 77 | auto root = min_seg_tree.root(); 78 | start = clock_type::now(); 79 | for (int run = 0; run < 5; ++run) { 80 | for (uint64_t i = 0; i < m; ++i) { 81 | auto x = min_seg_tree.rmq(queries[i], root, 0); 82 | // std::cout << "rmq in [" << queries[i].lo << ", " 83 | // << queries[i].hi << "]: " << x << "\n"; 84 | do_not_optimize_away(x); 85 | } 86 | } 87 | end = clock_type::now(); 88 | elapsed = end - start; 89 | 90 | std::cout << "average query time: " 91 | << static_cast(elapsed.count()) / (5 * m) * 1000000 92 | << " [musec]" << std::endl; 93 | 94 | uint64_t k = 0; // number of updates 95 | std::cin >> k; 96 | 97 | typedef std::pair update_query; 98 | std::vector updates; 99 | updates.reserve(k); 100 | 101 | for (uint64_t i = 0; i < k; ++i) { 102 | size_t lo, hi; 103 | int delta; 104 | std::cin >> lo >> hi >> delta; 105 | segment_tree_type::range r(lo, hi); 106 | updates.emplace_back(r, delta); 107 | } 108 | 109 | std::cout << "executing " << k << " updates" << std::endl; 110 | start = clock_type::now(); 111 | for (uint64_t i = 0; i < k; ++i) { 112 | auto const& range = updates[i].first; 113 | int delta = updates[i].second; 114 | min_seg_tree.update(range.lo, delta, root, 0); 115 | } 116 | end = clock_type::now(); 117 | elapsed = end - start; 118 | 119 | std::cout << "average update time: " 120 | << static_cast(elapsed.count()) / k * 1000000 121 | << " [musec]" << std::endl; 122 | 123 | std::cout << "executing " << k << " range updates" << std::endl; 124 | start = clock_type::now(); 125 | for (uint64_t i = 0; i < k; ++i) { 126 | auto const& range = updates[i].first; 127 | int delta = updates[i].second; 128 | min_seg_tree.update_range(range, delta, root, 0); 129 | } 130 | end = clock_type::now(); 131 | elapsed = end - start; 132 | 133 | std::cout << "average range update time: " 134 | << static_cast(elapsed.count()) / k * 1000000 135 | << " [musec]" << std::endl; 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /code/segment_trees/rmq_segment_tree.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define LEFT(i) 2 * i + 1 7 | #define RIGHT(i) 2 * i + 2 8 | #define PARENT(i) (i - 1) / 2 9 | 10 | template 11 | struct rmq_segment_tree { 12 | 13 | struct type_traits { 14 | IntType invalid; 15 | BinaryFunct funct; 16 | }; 17 | 18 | struct builder { 19 | 20 | builder() 21 | {} 22 | 23 | builder(std::vector const& leaves, type_traits traits) 24 | : m_traits(traits) 25 | { 26 | size_t n = leaves.size(); 27 | // round up to the next power of 2 28 | size_t m = size_t(1) << static_cast(ceil(log2(n))); 29 | m_tree.resize(2 * m - 1, m_traits.invalid); 30 | build(leaves, 0, n - 1, 0); 31 | 32 | // for (auto x: m_tree) { 33 | // std::cout << x << " "; 34 | // } std::cout << std::endl; 35 | } 36 | 37 | void swap(builder& other) { 38 | std::swap(other.m_traits, m_traits); 39 | other.m_tree.swap(m_tree); 40 | } 41 | 42 | void build(rmq_segment_tree& rst) { 43 | std::swap(rst.m_traits, m_traits); 44 | rst.m_tree.swap(m_tree); 45 | builder().swap(*this); 46 | } 47 | 48 | private: 49 | type_traits m_traits; 50 | std::vector m_tree; 51 | 52 | void build(std::vector const& leaves, size_t lo, size_t hi, size_t pos) { 53 | if (lo == hi) { 54 | m_tree[pos] = leaves[lo]; 55 | return; 56 | } 57 | size_t mid = (lo + hi) / 2; 58 | build(leaves, lo, mid, LEFT(pos)); 59 | build(leaves, mid + 1, hi, RIGHT(pos)); 60 | m_tree[pos] = m_traits.funct(m_tree[LEFT(pos)], m_tree[RIGHT(pos)]); 61 | } 62 | }; 63 | 64 | rmq_segment_tree() 65 | {} 66 | 67 | // debug purposes 68 | void print_tree() const { 69 | for (auto x: m_tree) { 70 | std::cout << x << " "; 71 | } std::cout << std::endl; 72 | } 73 | 74 | struct range { 75 | range(size_t l, size_t h) 76 | : lo(l), hi(h) 77 | {} 78 | 79 | size_t lo, hi; 80 | }; 81 | 82 | range root() const { 83 | return range(0, size() - 1); 84 | } 85 | 86 | size_t size() const { 87 | return m_tree.size() / 2 + 1; 88 | } 89 | 90 | IntType rmq(range const& query, range node_segment, size_t pos) { 91 | 92 | if (query.lo <= node_segment.lo 93 | and query.hi >= node_segment.hi) { // total overlap 94 | return m_tree[pos]; 95 | } 96 | if (query.lo > node_segment.hi 97 | or query.hi < node_segment.lo) { // no overlap 98 | return m_traits.invalid; 99 | } 100 | 101 | // partial overlap 102 | size_t mid = (node_segment.lo + node_segment.hi) / 2; 103 | return m_traits.funct( 104 | rmq(query, {node_segment.lo, mid}, LEFT(pos)), 105 | rmq(query, {mid + 1, node_segment.hi}, RIGHT(pos)) 106 | ); 107 | } 108 | 109 | // increment the i-th leaf by delta 110 | void update(size_t i, IntType delta, range node_segment, size_t pos) { 111 | 112 | if (i > node_segment.hi 113 | or i < node_segment.lo) { 114 | return; 115 | } 116 | 117 | if (node_segment.lo == node_segment.hi) { // leaf 118 | m_tree[pos] += delta; 119 | return; 120 | } 121 | 122 | size_t mid = (node_segment.lo + node_segment.hi) / 2; 123 | update(i, delta, {node_segment.lo, mid}, LEFT(pos)); 124 | update(i, delta, {mid + 1, node_segment.hi}, RIGHT(pos)); 125 | m_tree[pos] = m_traits.funct(m_tree[LEFT(pos)], m_tree[RIGHT(pos)]); 126 | } 127 | 128 | // increment all leaves in the range [query.lo, query.hi] by delta 129 | void update_range(range const& query, IntType delta, range node_segment, size_t pos) { 130 | 131 | if (query.lo > node_segment.hi 132 | or query.hi < node_segment.lo) { 133 | return; 134 | } 135 | 136 | if (node_segment.lo == node_segment.hi) { // leaf 137 | m_tree[pos] += delta; 138 | return; 139 | } 140 | 141 | size_t mid = (node_segment.lo + node_segment.hi) / 2; 142 | update_range(query, delta, {node_segment.lo, mid}, LEFT(pos)); 143 | update_range(query, delta, {mid + 1, node_segment.hi}, RIGHT(pos)); 144 | m_tree[pos] = m_traits.funct(m_tree[LEFT(pos)], m_tree[RIGHT(pos)]); 145 | } 146 | 147 | private: 148 | type_traits m_traits; 149 | std::vector m_tree; 150 | }; 151 | -------------------------------------------------------------------------------- /code/segment_trees/trees_with_arrays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define LEFT(i) 2 * i + 1 8 | #define RIGHT(i) 2 * i + 2 9 | #define PARENT(i) (i - 1) / 2 10 | 11 | int main() { 12 | 13 | std::ios_base::sync_with_stdio(false); 14 | 15 | std::vector tree; 16 | 17 | typedef std::chrono::high_resolution_clock clock_type; 18 | auto start = clock_type::now(); 19 | 20 | { 21 | int n = 0; 22 | std::cin >> n; 23 | int tree_size = 2 * n - 1; 24 | tree.resize(tree_size); 25 | 26 | int h = ceil(log2(n)); 27 | // left-most internal node id 28 | int left_most_node = (int(1) << (h - 1)) - 1; 29 | int offset = LEFT(left_most_node); 30 | 31 | // set leaves circularly 32 | 33 | // 1. go forward 34 | int i = 0; 35 | for (int j = offset; j != tree_size; ++i, ++j) { 36 | int x = 0; 37 | std::cin >> x; 38 | tree[j] = x; 39 | } 40 | 41 | // 2. fall back 42 | for (int j = 0; i != n; ++i, ++j) { 43 | int x = 0; 44 | std::cin >> x; 45 | tree[n - 1 + j] = x; 46 | } 47 | 48 | // set internal nodes 49 | for (int i = tree_size - 1; i != 0; i -= 2) { 50 | int min = std::min(tree[i], tree[i - 1]); 51 | tree[PARENT(i)] = min; 52 | } 53 | } 54 | 55 | auto end = clock_type::now(); 56 | std::chrono::duration elapsed = end - start; 57 | std::cout << "building took: " << elapsed.count() << " [sec]" << std::endl; 58 | 59 | start = clock_type::now(); 60 | uint64_t s = std::accumulate(tree.begin(), tree.end(), uint64_t(0)); 61 | end = clock_type::now(); 62 | elapsed = end - start; 63 | 64 | std::cout << "sum is: " << s << std::endl; 65 | std::cout << "sum took: " << elapsed.count() << " [sec]" << std::endl; 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /code/segment_trees/trees_with_pointers.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct node { 7 | node(int k, 8 | node* l = nullptr, 9 | node* r = nullptr) 10 | : key(k), left(l), right(r) 11 | {} 12 | 13 | int key; 14 | node* left; 15 | node* right; 16 | }; 17 | 18 | uint64_t sum(node* n) { 19 | 20 | if (n == nullptr) { 21 | return 0; 22 | } 23 | 24 | uint64_t left_subtree_sum = 0; 25 | if (n->left != nullptr) { 26 | left_subtree_sum = sum(n->left); 27 | } 28 | uint64_t right_subtree_sum = 0; 29 | if (n->right != nullptr) { 30 | right_subtree_sum = sum(n->right); 31 | } 32 | 33 | return n->key + left_subtree_sum + right_subtree_sum; 34 | } 35 | 36 | int main() { 37 | 38 | std::ios_base::sync_with_stdio(false); 39 | 40 | node* root = nullptr; 41 | typedef std::chrono::high_resolution_clock clock_type; 42 | 43 | auto start = clock_type::now(); 44 | { 45 | std::deque q; 46 | int n = 0; 47 | std::cin >> n; 48 | 49 | for (int i = 0; i < n; ++i) { 50 | int x = 0; 51 | std::cin >> x; 52 | node* n = new node(x); 53 | q.push_back(n); 54 | } 55 | 56 | node* last = nullptr; 57 | if (n % 2) { 58 | last = q.back(); 59 | q.pop_back(); 60 | } 61 | 62 | // helper function 63 | auto min_parent = [&](node* left, node* right) { 64 | int min = std::min(left->key, right->key); 65 | node* parent = new node(min, left, right); 66 | q.push_back(parent); 67 | }; 68 | 69 | // build tree topology 70 | while (q.size() != 1) { 71 | min_parent(q[0], q[1]); 72 | q.pop_front(); 73 | q.pop_front(); 74 | } 75 | 76 | if (last != nullptr) { // create a new root node with 77 | // the old root as left child 78 | // and the last node as right child 79 | min_parent(q.front(), last); 80 | q.pop_front(); 81 | } 82 | 83 | root = q.front(); 84 | } 85 | auto end = clock_type::now(); 86 | std::chrono::duration elapsed = end - start; 87 | std::cout << "building took: " << elapsed.count() << " [sec]" << std::endl; 88 | 89 | start = clock_type::now(); 90 | uint64_t s = sum(root); 91 | end = clock_type::now(); 92 | elapsed = end - start; 93 | 94 | std::cout << "sum is: " << s << std::endl; 95 | std::cout << "sum took: " << elapsed.count() << " [sec]" << std::endl; 96 | 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /handson/handson01/README.md: -------------------------------------------------------------------------------- 1 | # Hands-on #01: Sliding Window Maximum problem 2 | In this hands-on, we are going to experiment with different solutions for the *Sliding Window Maximum* problem. 3 | Folder *sliding_window_maximum* contains two brute force implementations for this problem, tests to check their correctness and 4 | a file ```main.rs``` to compare their performance on vectors with different sizes. 5 | 6 | You are asked to implement the following three asymptotically faster solutions: 7 | 8 | - PriorityQueue-based solution with time complexity $\Theta(n \log n)$. **Implement** this solution in function ```pub fn heap(nums: &Vec, k: i32) -> Vec```. 9 | - BBST-based solution with time complexity $\Theta(n \log k)$. **Implement** this solution in function ```pub fn bst(nums: &Vec, k: i32) -> Vec```. 10 | - Deque-based solution with time complexity $\Theta(n)$. **Implement** this solution in function ```pub fn linear(nums: &Vec, k: i32) -> Vec```. 11 | 12 | Your goal is to implement these functions in the ```src/lib.rs``` file. Their signatures match the requirements at [LeetCode](https://leetcode.com/problems/sliding-window-maximum/) to allow you to submit any implementation to this site. 13 | Each implementation starts with an ugly ```let k = k as usize;``` which is necessary to avoid many annoying casts. 14 | 15 | File ```src/lib.rs``` contains some tests to check the correctness of you implementation. Feel free to add more tests if needed. 16 | You can check the correctness of your implementation by removing the line ```#[ignore]``` before a test you are ready to activate. 17 | For example, 18 | ``` 19 | #[ignore] 20 | #[test] 21 | fn check_bst_version() { 22 | ... 23 | ``` 24 | will skip correctness tests on the ```bst``` implementation while 25 | ``` 26 | #[test] 27 | fn check_bst_version() { 28 | ... 29 | ``` 30 | will perform it. 31 | 32 | To run tests, execute 33 | ``` 34 | cargo test 35 | ``` 36 | and check the output. 37 | As an example, the following output 38 | 39 | ![Sample Output](imgs/test_passed.png) 40 | 41 | indicates that the linear version test has successfully been executed while the bst and the pqueue tests have been ignored. 42 | 43 | 44 | ## Performance 45 | Once your code successfully passes the complete test suite, you can visualize the performance of your algorithms on random data. 46 | Run 47 | 48 | ``` cargo run``` 49 | 50 | to execute the code inside ```main.rs```. 51 | This measures the execution time of the different implementations by varying the value of k and the size of the vector. 52 | Results are reported on a *results.csv* file. 53 | You can look at this file with any other text editor (e.g., ```nano```). 54 | We provide a *PlotResults.ipynb* Jupyter notebook to visualize the results. [Install](https://jupyter.org/install) Jupyter lab and run 55 | 56 | ```jupyter-lab``` 57 | 58 | to launch the notebook. Make sure that you have all the required libraries installed by running the cell 59 | 60 | ``` 61 | !{sys.executable} -m pip install seaborn 62 | !{sys.executable} -m pip install pandas 63 | ``` 64 | 65 | [Seaborn](https://seaborn.pydata.org/) is an awesome data visualization library built on the library ```Matplolib```. 66 | 67 | Read the *.csv* file using [Pandas](https://pandas.pydata.org) - a popular Python Data Analysis Library - 68 | 69 | ```python 70 | results_df = pd.read_csv(result_path) 71 | ``` 72 | 73 | and then plot using 74 | 75 | ```python 76 | sns.scatterplot(x="k", y="elapsed", hue="Method", data=results_df). 77 | ``` 78 | 79 | ### Code optimization 80 | 81 | Rust provides various options for compiling code. The command ```cargo build``` compiles code in debug mode with the minimum 82 | level of optimizations. 83 | The command ```cargo build --release``` instead optimizes the code at the cost of an increased compile time. 84 | Finally, the command ```RUSTFLAGS='-C target-cpu=native' cargo build --release``` optimizes the code using all the features 85 | (e.g., latest available SIMD instructions set) of your CPU. 86 | 87 | We encourage you to **experiments with these three different optimization levels**. 88 | 89 | ### Best/Worst cases 90 | 91 | Performance are measured on randomly initialized vectors (```gen_random_vector``` function in ```main.rs```). Think about the __best__ and the __worst__ input configurations for each of the proposed algorithms and measure their performance by adding customized inputs. What is the difference, in terms of execution time, between the best, the worst, and the average scenario? Write your considerations in your report. 92 | 93 | ## Submission 94 | Submit the file ```lib.rs``` and a file ```SWM_solution_YOUR_NAME.pdf``` to [rossano.venturini@gmail.com](mailto:rossano.venturini@gmail.com) by 19/10/2022. 95 | 96 | - Source code ```lib.rs``` contains your implementations. 97 | - A report ```SWM_solution_YOUR_NAME.pdf``` that briefly describes your implementations and provides a detailed analysis of the experimental results. In the report, you should try to answer questions like *What's the fastest solution with small values of $k$ and $n$? Why? What's the difference when you increase $k$ or $n$? Do ```--release``` and ```target-cpu=native``` improve the running time? Is the 1-line idiomatic implementation of the brute force solution slower than the other longer one? Is BST-based solution faster than Heap-based one? Are you able to explain this result? Is linear time solution always the fastest?*, and so on. Feel free to modify the Jupyter notebook to better answer those (and other different) questions. The .pdf should be roughly 2 pages (feel free to include plots, if needed). 98 | 99 | Before submitting your solutions, 100 | - make sure your implementation successfully passes all the tests. 101 | - use ```cargo fmt``` to format your code. 102 | - use ```cargo clippy``` to check your code. 103 | - use [Grammarly](https://grammarly.com/) to improve your English and avoid [tpyos](https://en.wiktionary.org/wiki/tpyo#English) :-). There is an [extension for vscode](https://marketplace.visualstudio.com/items?itemName=znck.grammarly). 104 | 105 | ## Cheating 106 | **Very important!** You are allowed to discuss verbally solutions with other 107 | students, **BUT** you have to implement all the solutions by yourself. 108 | Thus, sharing implementations with others is strictly **forbidden**. 109 | -------------------------------------------------------------------------------- /handson/handson01/imgs/test_passed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson01/imgs/test_passed.png -------------------------------------------------------------------------------- /handson/handson01/sliding_window_maximum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sliding_window_maximum" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rand = "0.8.3" 10 | csv = "1.1" 11 | binary_search_tree = "0.2.2" 12 | dict = "0.1.5" 13 | #counter = "0.5.6" -------------------------------------------------------------------------------- /handson/handson01/sliding_window_maximum/PlotResults.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "88f13377-09c2-453b-939c-34514442a349", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import sys\n", 11 | "import matplotlib.pyplot as plt" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "id": "01b306a1-57e4-46ad-a485-a87c52f8ff54", 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | "!{sys.executable} -m pip install seaborn\n", 22 | "!{sys.executable} -m pip install pandas" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "id": "26715c52-fbcc-4a91-825d-e6f7fd627001", 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "import seaborn as sns\n", 33 | "import pandas as pd" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": null, 39 | "id": "48219cb3-e06a-44ee-8a43-ff5b7e474add", 40 | "metadata": {}, 41 | "outputs": [], 42 | "source": [ 43 | "result_path = \"results.csv\"\n", 44 | "results_df = pd.read_csv(result_path)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "id": "bc479568-8cd0-410c-93ca-b4673b29431f", 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "results_df[(results_df.Method == \"Linear\") & (results_df.n == 32768)]" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "id": "ac6bf8de-c6f7-4f64-8612-d99cf7c20551", 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "results_df[(results_df.Method == \"Heap\") & (results_df.n == 32768)]" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "id": "4a7d1a79-ab75-4df0-a520-ef0a4ef1b125", 71 | "metadata": { 72 | "tags": [] 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "sns.set_style('darkgrid')\n", 77 | "sns.set_context('notebook')\n", 78 | "for curr_n in pd.unique(results_df['n']):\n", 79 | " plt.title(f\"n = {curr_n}\")\n", 80 | " curr_df = results_df[results_df.n == curr_n]\n", 81 | " ax = sns.scatterplot(x=\"k\", y=\"elapsed\", hue=\"Method\", data=curr_df)\n", 82 | " ax.legend(bbox_to_anchor=(1.5, 1.05))\n", 83 | " plt.show()" 84 | ] 85 | } 86 | ], 87 | "metadata": { 88 | "kernelspec": { 89 | "display_name": "Python 3 (ipykernel)", 90 | "language": "python", 91 | "name": "python3" 92 | }, 93 | "language_info": { 94 | "codemirror_mode": { 95 | "name": "ipython", 96 | "version": 3 97 | }, 98 | "file_extension": ".py", 99 | "mimetype": "text/x-python", 100 | "name": "python", 101 | "nbconvert_exporter": "python", 102 | "pygments_lexer": "ipython3", 103 | "version": "3.10.6" 104 | }, 105 | "vscode": { 106 | "interpreter": { 107 | "hash": "aee8b7b246df8f9039afb4144a1f6fd8d2ca17a180786b69acc140d282b71a49" 108 | } 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 5 113 | } 114 | -------------------------------------------------------------------------------- /handson/handson01/sliding_window_maximum/src/lib.rs: -------------------------------------------------------------------------------- 1 | use binary_search_tree::BinarySearchTree; 2 | use rand::Rng; 3 | use std::collections::BinaryHeap; 4 | use std::collections::VecDeque; 5 | 6 | pub fn brute_force(v: &Vec, k: i32) -> Vec { 7 | let k = k as usize; 8 | let n = v.len(); 9 | let mut maximums = Vec::with_capacity(n - k + 1); 10 | for i in 0..(n - k + 1) { 11 | let current_slice = &v[i..i + k]; 12 | let max_value = *current_slice.iter().max().unwrap(); 13 | maximums.push(max_value); 14 | } 15 | maximums 16 | } 17 | 18 | pub fn brute_force_idiomatic(v: &Vec, k: i32) -> Vec { 19 | let k = k as usize; 20 | v.windows(k).map(|w| *w.iter().max().unwrap()).collect() 21 | } 22 | 23 | pub fn heap(nums: &Vec, k: i32) -> Vec { 24 | todo!(); 25 | } 26 | 27 | pub fn bst(nums: &Vec, k: i32) -> Vec { 28 | todo!(); 29 | } 30 | 31 | pub fn linear(nums: &Vec, k: i32) -> Vec { 32 | todo!(); 33 | } 34 | 35 | pub fn gen_random_vector(n: usize) -> Vec { 36 | let mut nums: Vec = Vec::with_capacity(n); 37 | let mut rng = rand::thread_rng(); 38 | for _ in 0..n { 39 | nums.push(rng.gen_range(0..i32::MAX)); 40 | } 41 | 42 | nums 43 | } 44 | 45 | #[cfg(test)] 46 | mod tests { 47 | use super::*; 48 | 49 | #[test] 50 | fn test_idiomatic_version() { 51 | let k = 3; 52 | let v = gen_random_vector(100); 53 | 54 | let results = brute_force_idiomatic(&v, k); 55 | let truth = brute_force(&v, k); 56 | 57 | assert_eq!(results, truth); 58 | } 59 | 60 | #[ignore] 61 | #[test] 62 | fn test_heap_version() { 63 | let k = 3; 64 | let v = gen_random_vector(100); 65 | 66 | let results = heap(&v, k); 67 | let truth = brute_force(&v, k); 68 | 69 | assert_eq!(results, truth); 70 | } 71 | 72 | #[ignore] 73 | #[test] 74 | fn test_bst_version() { 75 | let k = 3; 76 | let v = gen_random_vector(100); 77 | 78 | let results = bst(&v, k); 79 | let truth = brute_force(&v, k); 80 | 81 | assert_eq!(results, truth); 82 | } 83 | 84 | #[ignore] 85 | #[test] 86 | fn test_linear_version() { 87 | let k = 3; 88 | let v = gen_random_vector(100); 89 | 90 | let results = linear(&v, k); 91 | let truth = brute_force(&v, k); 92 | 93 | assert_eq!(results, truth); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /handson/handson01/sliding_window_maximum/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use std::time::Instant; 3 | 4 | use sliding_window_maximum::{ 5 | brute_force, brute_force_idiomatic, bst, gen_random_vector, heap, linear, 6 | }; 7 | 8 | fn main() { 9 | let ns = [ 10 | 1024, 11 | 2 * 1024, 12 | 4 * 1024, 13 | 8 * 1024, 14 | 16 * 1024, 15 | 32 * 1024, 16 | 64 * 1024, 17 | 128 * 1024, 18 | ]; 19 | let ks = [8, 16, 32, 64, 128, 256, 512, 1024]; 20 | 21 | // Write csv header 22 | let mut output_text: String = "Method,n,k,elapsed\n".to_string(); 23 | 24 | for &n in ns.iter() { 25 | for &k in ks.iter() { 26 | if k as usize > n { 27 | continue; 28 | } 29 | let nums = gen_random_vector(n); 30 | 31 | // Brute force 32 | let (elapsed_times, _) = measure_elapsed_time(brute_force, &nums, k); 33 | let min_elapsed = *elapsed_times.iter().min().unwrap(); 34 | let row = format!("{},{},{},{}\n", "BruteForce", n, k, min_elapsed); 35 | output_text.push_str(&row); 36 | 37 | // Brute force idiomatic 38 | let (elapsed_times, _) = measure_elapsed_time(brute_force_idiomatic, &nums, k); 39 | let min_elapsed = *elapsed_times.iter().min().unwrap(); 40 | let row = format!( 41 | "{},{},{},{}\n", 42 | "BruteForceIdiomatic", n, k, min_elapsed 43 | ); 44 | output_text.push_str(&row); 45 | 46 | // Heap 47 | let (elapsed_times, _) = measure_elapsed_time(heap, &nums, k); 48 | let min_elapsed = *elapsed_times.iter().min().unwrap(); 49 | let row = format!("{},{},{},{}\n", "Heap", n, k, min_elapsed); 50 | output_text.push_str(&row); 51 | 52 | // Bst 53 | let (elapsed_times, _) = measure_elapsed_time(bst, &nums, k); 54 | let min_elapsed = *elapsed_times.iter().min().unwrap(); 55 | let row = format!("{},{},{},{}\n", "BST", n, k, min_elapsed); 56 | output_text.push_str(&row); 57 | 58 | // Linear 59 | let (elapsed_times, _) = measure_elapsed_time(linear, &nums, k); 60 | let min_elapsed = *elapsed_times.iter().min().unwrap(); 61 | let row = format!("{},{},{},{}\n", "Linear", n, k, min_elapsed); 62 | output_text.push_str(&row); 63 | } 64 | } 65 | 66 | let output_path = "results.csv"; 67 | fs::write(output_path, output_text).expect("Unable to write file"); 68 | } 69 | 70 | const N_RUNS: usize = 5; 71 | 72 | fn measure_elapsed_time( 73 | f: fn(vec: &Vec, k: i32) -> Vec, 74 | nums: &Vec, 75 | k: i32, 76 | ) -> (Vec, Vec) { 77 | let mut elapsed_times: Vec = Vec::with_capacity(N_RUNS); 78 | let mut results = Vec::new(); 79 | for _ in 0..N_RUNS { 80 | let start = Instant::now(); 81 | results = f(nums, k); 82 | let duration = start.elapsed().as_nanos(); 83 | elapsed_times.push(duration); 84 | } 85 | 86 | (elapsed_times, results) 87 | } 88 | -------------------------------------------------------------------------------- /handson/handson02/README.md: -------------------------------------------------------------------------------- 1 | # Hands-on #02: Segment tree 2 | In this hands-on, we are going to solve two problems with segment trees. 3 | For each problem, we have a pdf with the description of the problem and a set of tests to check the correctness of your implementations. 4 | 5 | - Problem *Min and Max*: [Text](./problem_01/text.pdf) and [TestSet.zip](./problem_01/Testset.zip) 6 | - Problem *Queries and Opearations*: [Text](./problem_02/text.pdf) and [TestSet.zip](./problem_02/Testset.zip) 7 | 8 | ## Submission 9 | Submit 10 | - a file ```lib.rs``` and a ```main.rs``` for each problem 11 | - a file ```Handson_02_solution_YOUR_NAME.pdf``` to [rossano.venturini@gmail.com](mailto:rossano.venturini@gmail.com) 12 | by 23/11/2022. 13 | 14 | - The ```main.rs``` file takes its input from stdin and produces its output to the stdout. This way we can use ```./solution < input1.txt | diff - output1.txt``` to compare its output with the expected one on the first test case. 15 | - A report ```Handson_02_solution_YOUR_NAME.pdf``` that briefly describes your solutions, your implementations, and an analysis of their time and space complexities. Add references to 16 | any relevant source you consulted to find your solutions or to develop their implementations. 17 | 18 | Before submitting your solutions, 19 | - make sure your implementation successfully passes all the tests. 20 | - use ```cargo fmt``` to format your code. 21 | - use ```cargo clippy``` to check your code. 22 | - use [Grammarly](https://grammarly.com/) to improve your English and avoid [tpyos](https://en.wiktionary.org/wiki/tpyo#English) :-). There is an [extension for vscode](https://marketplace.visualstudio.com/items?itemName=znck.grammarly). 23 | 24 | ## Cheating 25 | **Very important!** You are allowed to discuss possible solutions with other 26 | students, **BUT** you have to implement all the solutions by yourself. 27 | Thus, sharing implementations with others is strictly **forbidden**. 28 | -------------------------------------------------------------------------------- /handson/handson02/problem_01/Testset.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson02/problem_01/Testset.zip -------------------------------------------------------------------------------- /handson/handson02/problem_01/text.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson02/problem_01/text.pdf -------------------------------------------------------------------------------- /handson/handson02/problem_02/TestSet.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson02/problem_02/TestSet.zip -------------------------------------------------------------------------------- /handson/handson02/problem_02/text.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson02/problem_02/text.pdf -------------------------------------------------------------------------------- /handson/handson03/README.md: -------------------------------------------------------------------------------- 1 | # Hands-on #03 2 | ## Dynamic Programming 3 | In this hands-on, we are going to solve two problems with Dynamic Programming. 4 | For each problem, we have a pdf with the description of the problem and a set of tests to check the correctness of your implementations. 5 | 6 | - Problem *Holyday planning*: [Text](./problem_01/text.pdf) and [TestSet.zip](./problem_01/Testset.zip) 7 | - Problem *Xmas Lights*: [Text](./problem_02/text.pdf) and [TestSet.zip](./problem_02/Testset.zip). If your are not able to solve this problem, do your best and write on the report all your progresses. 8 | 9 | # Submission 10 | Submit 11 | - a file ```lib.rs``` and a ```main.rs``` for each problem 12 | - a file ```Handson_03_solution_YOUR_NAME.pdf``` to [rossano.venturini@gmail.com](mailto:rossano.venturini@gmail.com) 13 | by 23/12/2022. 14 | 15 | - Source code ```lib.rs``` contains your solutions. 16 | - The ```main.rs``` file takes its input from stdin and produces its output to the stdout. This way we can use ```./solution < input1.txt | diff - output1.txt``` to compare its output with the expected one on the first test case. 17 | - A report ```Handson_03_solution_YOUR_NAME.pdf``` that briefly describes your solutions, your implementations, and an analysis of their time and space complexities. Add references to 18 | any relevant source you consulted to find your solutions or to develop their implementations. 19 | 20 | Before submitting your solutions, 21 | - make sure your implementation successfully passes all the tests. 22 | - use ```cargo fmt``` to format your code. 23 | - use ```cargo clippy``` to check your code. 24 | - use [Grammarly](https://grammarly.com/) to improve your English and avoid [tpyos](https://en.wiktionary.org/wiki/tpyo#English) :-). There is an [extension for vscode](https://marketplace.visualstudio.com/items?itemName=znck.grammarly). 25 | 26 | ## Cheating 27 | **Very important!** You are allowed to discuss possible solutions with other 28 | students, **BUT** you have to implement all the solutions by yourself. 29 | Thus, sharing implementations with others is strictly **forbidden**. 30 | -------------------------------------------------------------------------------- /handson/handson03/problem_01/TestSet.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson03/problem_01/TestSet.zip -------------------------------------------------------------------------------- /handson/handson03/problem_01/text.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson03/problem_01/text.pdf -------------------------------------------------------------------------------- /handson/handson03/problem_02/TestSet.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson03/problem_02/TestSet.zip -------------------------------------------------------------------------------- /handson/handson03/problem_02/text.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/handson/handson03/problem_02/text.pdf -------------------------------------------------------------------------------- /notes/DynamicProgramming.md: -------------------------------------------------------------------------------- 1 | # Dynamic programming 2 | These notes sketch dynamic programming lectures. Dynamic programming is treated in any introductory book on Algorithms. You may refer to Chapter 15 of *Introduction to Algorithms, 3rd Edition* by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, Clifford Stein, The MIT Press, 2009 for a more detailed explanation and Chapter 6 of *Algorithms* by 3 | S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani 4 | [see here](https://people.eecs.berkeley.edu/~vazirani/algorithms/chap6.pdf). 5 | 6 | These are rough and non-exhaustive notes that I used while lecturing. Please use them just to have a list of the topics of each lecture and use other reported references to study these arguments. 7 | 8 | Feel free to send a pull request to fix any typo or to clarify any obscure description. 9 | 10 | 11 | ## Dynamic Programming: introduction 12 | Dynamic programming, like the divide-and-conquer method, solves problems by combining the solutions to subproblems. 13 | 14 | Divide-and-conquer algorithms partition the problem into disjoint subproblems, solve the subproblems recursively, and then combine their solutions to solve the original problem. 15 | 16 | In contrast, dynamic programming applies when subproblems overlap, that is, when subproblems share subsubproblems. 17 | 18 | In this context, a divide-and-conquer algorithm does more work than necessary, repeatedly solving the common subsubproblems. 19 | 20 | A dynamic-programming algorithm solves each subsubproblem just once and then saves its answer in a table. Thus, avoiding the work of recomputing the answer every time it solves each subsubproblem. 21 | 22 | 23 | ## A first easy problem: Fibonacci numbers 24 | 25 | Fibonacci numbers are defined as follows. 26 | 27 | $F_0 = 0$ 28 | 29 | $F_1 = 1$ 30 | 31 | $F_n = F_{n-1}+ F_{n-2}$ 32 | 33 | Our goal is to compute the $n$th Fibonacci number $F_n$. 34 | 35 | Consider the following trivial recursive algorithm. 36 | 37 | ```c++ 38 | uint64_t Fibonacci(uint64_t n) { 39 | if (n == 0) return 0; 40 | if (n == 1) return 1; 41 | else return Fibonacci(n-1) + Fibonacci(n-2); 42 | } 43 | ``` 44 | 45 | The time complexity of this algorithm is given by the recurrence $T(n)=T(n-1)+T(n-2)+\Theta(1)$. It easy to see that $T(n)\geq F_n$. 46 | 47 | $$T(n) > 2T(n-2) > 2(2T(n-4)) = 2^2T(n-4)$$ 48 | $$> 2^2(2T(n-6)) = 2^3T(n-6)> \ldots$$ 49 | $$> 2^k T(n-2k) > \ldots$$ 50 | 51 | Thus, for $n$ even, we get $T(n) > 2^\frac{n}{2}T(0)= 2^\frac{n}{2}c_0$ while 52 | for $n$ odd, we get $T(n) > 2^\frac{n-1}{2}T(1)= 2^\frac{n-1}{2}c_1$. 53 | 54 | Memoization is the trick that allows to reduce the time complexity. Whenver we 55 | compute a Fibonacci number, we store it in a array $M$. Everytime we need a 56 | Fibonacci number, we compute it only if the answer is not in the array. 57 | 58 | ```c++ 59 | uint64_t FibonacciMemo(n) { 60 | if (n == 0) return 0; 61 | if (n == 1) return 1; 62 | if (M[n] == NULL) M[n] = FibonacciMemo(n-1) + FibonacciMemo(n-2); 63 | return M[n]; 64 | } 65 | ``` 66 | 67 | This algorithm requires linear time and space. 68 | 69 | Actually, there is a more direct bottom-up approach which uses linear time and constant space. How? 70 | 71 | This approach typically depends on some natural notion of the "size" of a subproblem, such that solving any particular subproblem depends only on solving "smaller" subproblems. 72 | 73 | We sort the subproblems by size and solve them in size order, smallest first. When solving a particular subproblem, we have already solved all of the smaller subproblems its solution depends upon, and we have saved their solutions. 74 | 75 | We solve each sub-problem only once, and when we first see it, we have already solved all of its prerequisite subproblems. 76 | 77 | In our Fibonacci problem this approach correspond to compute an array $F$ 78 | which entry $F[i]$ is the $i$th Fibonacci number. 79 | 80 | We can fill this array from left (smaller subproblems) to right (larger 81 | subproblems). Entry $F[i]$ requires only entries $F[i-1]$ and $F[i-2]$ only. 82 | 83 | This way the solution is much more direct. 84 | 85 | ```c++ 86 | uint64_t FibonacciIterative(n) { 87 | vector M(n); 88 | if (n == 0) return 0; 89 | if (n == 1) return 1; 90 | M[0] = 0; 91 | M[1] = 1; 92 | for(size_t i = 2; i < n; ++i) 93 | M[i] = M[i-1] + M[i-2]; 94 | return M[n]; 95 | } 96 | ``` 97 | 98 | We note that there exist a faster algorithm to compute the $n$th Fibonacci number. 99 | Indeed, the $n$th Fibonacci number is the top-left element of the 4x4 matrix 100 | 101 | $$ 102 | M= \left( 103 | \begin{bmatrix} 104 | 1 & 1 \\ 105 | 1 & 0 106 | \end{bmatrix} 107 | \right)^n. 108 | $$ 109 | 110 | The matrix can be computed in $\Theta(\log n)$ time by using [fast exponentiation](https://www.johndcook.com/blog/2008/12/10/fast-exponentiation/). 111 | 112 | ## Rod cutting 113 | 114 | ### Problem 115 | *Serling Enterprises buys long steel rods and cuts them into shorter rods, which it then sells. 116 | Each cut is free. The management of Serling Enterprises wants to know the best way to cut up the rods. 117 | Given a rod of length $n$ and for any $i\in[1,n]$, the price $p_i$ of a rod 118 | of length $i$, the goal is that of determining the maximum revenue $r_n$ 119 | obtainable by cutting up the rod and selling the pieces.* 120 | 121 | The bottom-up DP solution of the problem is as follows. 122 | Our goal is to fill an array $r[0, n]$, where entry $r[i]$ stores 123 | the maximum revenue obtainable with a rod of size $i$. 124 | 125 | Assuming we have already solved all the subproblems of size $j &p) { 137 | vector r(n+1, 0); 138 | for(size_t j = 1; j < n; ++j) { 139 | uint64_t q = 0; 140 | for(size_t i = 1; i < j; ++i) 141 | q = max(q, p[i] + r[j-i]); 142 | r[j] = q; 143 | } 144 | return r[n]; 145 | } 146 | ``` 147 | 148 | The algorithm runs in $\Theta(n^2)$ time. 149 | 150 | The algorithm computes only optimal revenue but not a cut that gives such a revenue. 151 | The algorithm can be easily modified to obtain a optimal cut. How? 152 | 153 | Consider the following running example. 154 | 155 | | length | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 156 | |:---------|---:|---:|---:|---:|----:|----:|----:|---:|---:|---:|---:| 157 | | price | 0 | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 | 158 | | revenue | 0 | 1 | 5 | 8 | 10 | 13 | 17 | 18 | 22 | 25 | 30 | 159 | | cut | 0 | 1 | 2 | 3 | 2 | 2 | 6 | 1 | 2 | 3 | 10 | 160 | 161 | ## Minimum Cost Path 162 | ### Problem 163 | *We are given a matrix $M$ of $n\times m$ integers. The goal is to find the minimum cost path to move from the top-left corner to the bottom-right corner by moving only down or to right.* 164 | 165 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/path-in-matrix/0). 166 | 167 | Consider the matrix below. 168 | 169 | ||||| 170 | |---|---|---|---| 171 | | 1 | 2 | 6 | 9 | 172 | | 0 | 0 | 3 | 1 | 173 | | 1 | 7 | 7 | 2 | 174 | 175 | It is easy to see that the following recurrence solves the problem. 176 | 177 | \[W(i,j) = M[i,j] + \left\{ 178 | \begin{array}{ll} 179 | 0 & \text{if } i = j = 1\\ 180 | W(i,j-1) & \text{if } i = 1 \text{ and } j > 1\\ 181 | W(i-1,j) & \text{if } i > 1 \text{ and } j = 1\\ 182 | \min(W(i-1,j), W(i, j-1))& \text{otherwise}\\ 183 | \end{array} 184 | \right. \] 185 | 186 | Thus, the problem is solved in linear time by filling a matrix $W$. 187 | Matrix $W$ for the example above is as follows. 188 | 189 | ||||| 190 | |---|---|---|---| 191 | | 1 | 3 | 9 | 18 | 192 | | 1 | 1 | 4 | 5 | 193 | | 2 | 8 | 11 | 7 | 194 | 195 | ## Longest Common Subsequence (LCS) 196 | ### Problem 197 | *Given two sequences $S_1[1,n]$ and $S_2[1,m]$, find the length of longest subsequence present in both of them.* 198 | 199 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/longest-common-subsequence/0). 200 | 201 | As an example, consider $S_1 = ABCBDAB$ and $S_2 = BDCABA$. 202 | A longest common subsequence is $BCBA$. There may be several other optimal solutions, e.g., $BCAB$. 203 | 204 | The subproblems here ask to compute the LCS of prefixes of the two sequences: given two prefixes $S_1[1,i]$ and $S_2[1,j]$, our goal is to compute 205 | ${\sf LCS}(S_1[1,i], S_2[1,j])$. 206 | 207 | Assume we already know ${\sf LCS}(S_1[1,i-1], S_2[1,j-1])$, 208 | ${\sf LCS}((S_1[1,i], S_2[1,j-1]))$, and ${\sf LCS}(S_1[1,i-1], S_2[1,j])$, 209 | i.e., three smaller subproblems. 210 | 211 | If $S_1[i] = S_2[j]$, we can extend a LCS of $S_1[1,i-1]$ and $S_2[1,j-1]$ 212 | by adding the character $c=S_1[i]$. For example, $ABCB$ and $BDCAB$. 213 | The LCS of $S_1[1,i-1] = $ABC$$ and $S_2[1,j-1] = $BDCA$$ has length $2$ 214 | and can be extended with character $c = B$. 215 | 216 | Observe that we could also use ${\sf LCS}(S_1[1,i], S_2[1,j-1])$, and 217 | ${\sf LCS}(S_1[1,i-1], S_2[1,j])$ ignoring the match on the last character, 218 | but these two cannot be longer. 219 | 220 | Instead, if $S_1[i] \neq S_2[j] $, we can only consider 221 | ${\sf LCS}(S_1[1,i], S_2[1,j-1])$, and 222 | ${\sf LCS}(S_1[1,i-1], S_2[1,j])$. 223 | We take the longest one. 224 | 225 | Summarising, 226 | 227 | \[{\sf LCS}(S_1[1,i], S_2[1,j]) = \left\{ 228 | \begin{array}{ll} 229 | 0 & i = 0 \text{ or } j = 0 \\ 230 | {\sf LCS}(S_1[1,i-1], S_2[1,j-1]) + 1 & S_1[i]=S_2[j] \\ 231 | \max({\sf LCS}(S_1[1,i], S_2[1,j-1]), 232 | {\sf LCS}(S_1[1,i-1], S_2[1,j])) & \text{otherwise}\\ 233 | \end{array} 234 | \right. \] 235 | 236 | Below the pseudocode of this algorithm where we use a matrix $C$ to store the solution of all the subproblems. 237 | 238 | ``` 239 | function LCSLength(X[1..m], Y[1..n]) 240 | C = array(0..m, 0..n) 241 | for i := 0..m 242 | C[i,0] = 0 243 | for j := 0..n 244 | C[0,j] = 0 245 | for i := 1..m 246 | for j := 1..n 247 | if X[i] = Y[j] 248 | C[i,j] := C[i-1,j-1] + 1 249 | else 250 | C[i,j] := max(C[i,j-1], C[i-1,j]) 251 | return C[m,n] 252 | ``` 253 | 254 | This algorithm runs in $\Theta(nm)$ time. 255 | 256 | Figure below show the execution of the algorithm on $S_1 = ABCBDAB$ and 257 | $S_2 = BDCABA$. 258 | 259 | ![LCS running example](figures/DP_LCS_example.png) 260 | 261 | Take a look to [this](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem) Wikipedia entry for more details. 262 | 263 | ## IWGBS - 0110SS 264 | ### Problem 265 | *Dor is IWGolymp student so he has to count in how many ways he can make binary strings of length $N$ where zeroes cannot be next to each other. Help to him in how many different numbers can he make.* 266 | 267 | You can submit your solution [here](https://www.spoj.com/problems/IWGBS/). 268 | 269 | As an example, if $N = 3$, we have the following $5$ binary strings $101$, $010$, $111$, $110$, and $011$. 270 | 271 | Let $F(N)$ be number we are looking for. We know that $F(1)=2$ and $F(0)=1$. 272 | Any number with the desired property can be obtained either: 1) by taking any $n-1$ digits number and by appending a $1$, or by taking any $n-2$ number and by 273 | appending $10$. Thus, $F(n)= F(n-1) + F(n-2)$ (Looks familiar?). 274 | 275 | This problem is similar to the problem of completely covering a 2xn rectangle with 2x1 dominoes. See chapter 7.1 of *Concrete Mathematics, 2Ed.* by D. Knuth, O. Patashnik, and R. Graham. 276 | 277 | 278 | ## 0/1 Knapsack 279 | ### Problem 280 | *We are given $n$ items. Each item $i$ has a value $v_i$ and a weight $w_i$. 281 | We need put a subset of these items in a knapsack of capacity $C$ to get the maximum total value in the knapsack.* 282 | 283 | You can submit your solution [here](https://www.spoj.com/problems/KNAPSACK/). 284 | 285 | The problem is called 0/1 because each item is either selected or not selected. 286 | Two possible variants of the problem allows to select fraction of the items (fractional knapsack problem) or select the same item multiple times (0/$\infty$ knapsack problem). 287 | 288 | The problem is a well-know NP-Hard problem, which admits a pseudo-polynomial time algorithm. 289 | 290 | We can use the following solutions. 291 | - If $C$ is small, we can use *Weight Dynamic Programming*. The time 292 | complexity is $\Theta(Cn))$. 293 | - Ff $V=\sum_i v_i$ is small, we can use *Price Dynamic Programming*. The time complexity is $\Theta(Vn))$. 294 | - If both are large, we can use *branch and bound*. This approach is not covered by our lecture note. 295 | 296 | The idea of the *Weight DP* algorithm is to fill a $(n+1)\times (C+1)$ matrix $K$. 297 | Let $K[i, A]$ be the max profit for weight at most $A$ using items from $1$ up 298 | to $i$. Thus, we have that $K[i, A] = \max(K[i-1, A], K[i-1, A-w[i]] + 299 | v[i])$. The last entry $K[C,n]$ contains the solution. 300 | We can fill the matrix $K$ in $\Theta(Cn))$ time. 301 | 302 | Here an example. Consider a knapsack of capacity $C = 7$ and the following items. 303 | 304 | | weight | value | 305 | |--------:|-------:| 306 | | 1 | 1 | 307 | | 3 | 4 | 308 | | 4 | 5 | 309 | | 5 | 7 | 310 | 311 | The matrix $K$ is as follows. 312 | 313 | | value | weight | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 314 | |-------:|--------:|---:|---:|---:|---:|---:|---:|---:|---:| 315 | | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 316 | | 4 | 3 | 0 | 1 | 1 | 4 | 5 | 5 | 5 | 5 | 317 | | 5 | 4 | 0 | 1 | 1 | 4 | 5 | 6 | 6 | 9 | 318 | | 7 | 5 | 0 | 1 | 1 | 4 | 5 | 7 | 8 | 9 | 319 | 320 | The idea of the *Profit DP* algorithm is similar. We use a $(n+1)\times (V+1)$ 321 | matrix $K$. Let $K[V,i]$ be the min weight for profit at least $V$ using items 322 | $1, \leq , i$. Thus, we have $K[A, i] = \min(K[A, i-1], K[A-p[i], i-1] + 323 | w[i])$. The solution is $\max \{ a : K[A,n] \leq C \}$. 324 | 325 | [Here](https://en.wikipedia.org/wiki/Knapsack_problem) you can find more details about this problem. 326 | 327 | ## Subset sum 328 | ### Problem 329 | *Given a set $S$ of $n$ non-negative integers, and a value $v$, determine if there is a subset of the given set with sum equal to given $v$.* 330 | 331 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/subset-sum-problem/0). 332 | 333 | The problem is a well-know NP-Hard problem, which admits a pseudo-polynomial time algorithm. 334 | 335 | The problem has a solution which is almost the same as 0/1 knapsack problem. 336 | 337 | As in the 0/1 knapsack problem, we construct a matrix $W$ with $n+1$ rows and 338 | $v+1$ columns. Here the matrix contains booleans. 339 | 340 | Entry $W[i][j]$ is *True* if and only if there exists a subset of the first $i$ items with sum $j$, *False* otherwise. 341 | 342 | The entries of the first row $W[0][]$ are set to false while entries of the first column $W[][0]$ are set to true. 343 | 344 | Entry $W[i][j]$ is true either if $W[i-1][j]$ is true or $W[i-1][j-S[i]]$ is 345 | true. 346 | 347 | As an example, consider the set $S= \{3,2,5,1\}$ and value $v=6$. Below the matrix $W$ for this example. 348 | 349 | | Elements \ v | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 350 | |--------------|---|---|---|---|---|---|---| 351 | | $\\emptyset$ | T | F | F | F | F | F | F | 352 | | 3 | T | F | F | T | F | F | F | 353 | | 2 | T | F | T | T | F | T | F | 354 | | 5 | T | F | T | T | F | T | F | 355 | | 1 | T | T | T | T | T | T | T | 356 | 357 | The algorithm runs in $\Theta(vn)$ time. 358 | 359 | [Here](https://en.wikipedia.org/wiki/Subset_sum_problem) you can find more details about this problem. 360 | 361 | ## Coin change 362 | ### Problem 363 | *We have $n$ types of coins available in infinite quantities where the value of 364 | each coin is given in the array $C=[c_1, c_2, \ldots, c_n]$. 365 | The goal is find out how many ways we can make the change of the amount $K$ using the coins given.* 366 | 367 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/coin-change/0). 368 | 369 | For example, if $C=[1, 2, 3, 8]$, there are $3$ ways to make $K=3$, i.e., $1,1,1$, 370 | $1,2$ and $3$. 371 | 372 | The solution is similar to the one for 0/1 knapsack and subset sum problems. 373 | 374 | The goal is to build a $(n+1)\times(K+1)$ matrix $W$, i.e., we compute the number of ways to change any amount smaller than or equal to $K$ by using coins in any prefix of $C$. 375 | 376 | The easy cases are when $K=0$. We have just one way to change this amount. 377 | Thus, the first column of $W$ contains $1$ but $W[0,0]=0$ which is the number of ways to change $0$ with no coin. 378 | 379 | Now, for every coin we have an option to include it in the solution or exclude it. 380 | 381 | If we decide to include the $i$th coin, we reduce the amount by coin value and 382 | use the subproblem solution ($K-c[i]$). 383 | 384 | If we decide to exclude the $i$th coin, the solution for the same amount 385 | with­out considering that coin is on the entry above. 386 | 387 | ## Longest increasing subsequence (LIS) 388 | 389 | ### Problem 390 | *Given a sequence $S$ of $n$ numbers, find the length of its longest increasing subsequence.* 391 | 392 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/longest-increasing-subsequence/0). 393 | 394 | 395 | As an example consider the sequence $S = 10, 22, 9, 21, 33, 50, 41, 60, 80$. 396 | The length of LIS is $6$ and $10, 22, 33, 50, 60, 80$ is a LIS. In general, LIS is not unique, e.g., $9, 21, 33, 50, 60, 80$ is another LIS. 397 | 398 | 399 | Consider the sequence $S[1,n]$ and let ${\sf LIS}(i)$ be the LIS of the prefix 400 | $S[1,i]$ whose last element is $S[i]$. 401 | 402 | 403 | \[{\sf LIS}(i) = \left\{ 404 | \begin{array}{ll} 405 | 1 + \max({\sf LIS}(j) \mid 1 \leq j < i \; \sf {and}\; S[j] < S[i])& \\ 406 | 1 & \text{if such } j \text{ does not exist}\\ 407 | \end{array} 408 | \right. \] 409 | 410 | 411 | It should be clear that the above recurrence can be solved in $\Theta(n^2)$ time. 412 | 413 | [Here](https://en.wikipedia.org/wiki/Longest_increasing_subsequence) you can find more details about this problem. 414 | 415 | ### Dynamic programming as shortest/longest path on a DAG 416 | Often it is convenient to reduce a problem to a (single source) longest path 417 | computation on a suitable DAG. 418 | 419 | Let's consider again the LIS problem. Our DAG $G$ has a vertex for each element of the sequence, plus a dummy vertex that marks the end of the sequence. Let us 420 | use $v_i$ to denote the vertex corresponding to element $S[i]$, $v_{n+1}$ 421 | denotes the dummy vertex. 422 | 423 | Edges are as follows. Every vertex has an edge to $v_{n+1}$. Moreover, 424 | a vertex $v_j$ is connected to $v_i$ iff $j A[j], then $LDS[i] \geq LDS[j] + 1$. 468 | 469 | As all the pairs are distinct, by Pigeonhole principle, there must be a pair with either a LIS value larger than $r-1$ or a LDS value larger than $s-1$. 470 | 471 | ## Longest Bitonic Subsequence 472 | ### Problem 473 | *Given a sequence $S[1,n]$, find the length of its longest bitonic 474 | subsequence. A bitonic sequence is a sequence that first increases and then decreases.* 475 | 476 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/longest-bitonic-subsequence/0). 477 | 478 | Consider for example the sequence $S= 2, -1, 4, 3, 5, -1, 3, 2$. 479 | The subsequence $-1, 4, 3, -1$ is bitonic. A longest bitonic subsequence is $ 2,3,5,3,2$. 480 | 481 | The idea is to compute the longest increasing subsequence from left to right and the longest increasing subsequence from right to left by using the $\Theta(n\log n)$ time solution of the previous lecture. 482 | 483 | Then, we combine these two solutions to find the longest bitonic subsequence. 484 | This is done by taking the values in a column, adding them and subtracting one. 485 | This is correct because ${\sf LIS}[i]$ computes the longest increasing subsequence of $S[1,i]$ and ends with $S[i]$. 486 | 487 | | S | 2 | -1 | 4 | 3 | 5 | -1 | 3 | 2 | 488 | |--------------|---|-----|---|---|---|-----|---|---| 489 | | LIS | 1 | 1 | 2 | 2 | 3 | 1 | 2 | 2 | 490 | | LDS | 2 | 1 | 3 | 2 | 3 | 1 | 2 | 1 | 491 | | LBS | 2 | 1 | 4 | 3 | 5 | 1 | 3 | 2 | 492 | 493 | ## Minimum number of jumps 494 | ### Problem 495 | *Given an array of integers where each element represents the max number of steps that can be made forward from that element. Write a function to return the minimum number of jumps to reach the end of the array (starting from the first element). If an element is $0$, then cannot move through that element.* 496 | 497 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/minimum-number-of-jumps/0). 498 | 499 | As an example, consider the array $1, 3, 5, 8, 9, 2, 6, 7, 6, 8, 9$. 500 | The minimum number of jumps is $3$, i.e., $1, 3, 9$. 501 | 502 | Think about the reduction to a SSSP on a DAG. This gives a $\Theta(n^2)$ time 503 | solution. 504 | 505 | A linear time solution is [here](http://www.geeksforgeeks.org/minimum-number-jumps-reach-endset-2on-solution/). 506 | 507 | ## Largest independent set on trees 508 | ### Problem 509 | *Given a tree $T$ with $n$ nodes, find one of its largest independent sets.* 510 | 511 | An independent set is a set of nodes $I$ such that there is no edge connecting any pair of nodes in $I$. 512 | 513 | Example below shows a tree whose largest independent set consists of the red nodes a, d, e, and f. 514 | 515 | ![Largest independent set](figures/DP_IndepSetTree.png) 516 | 517 | In general the largest independent set is not unique. For example, we can obtain a different largest independent set by replacing nodes a and d with nodes b and g. 518 | 519 | Consider a bottom up traversal of the tree $T$. For any node $u$, we have two possibilities: either add or not add the node $u$ to the independent set. 520 | 521 | In the former case, $u$'s children cannot be part of the independent set but its grandchildren could. 522 | In the latter case, $u$'s children could be part of the independent set. 523 | 524 | Let ${\sf LIST}(u)$ be the size of the independent set of the subtree rooted at $u$ and let $C_u$ and $G_u$ be the set of children and the set of grandchildren of $u$, respectively. 525 | 526 | Thus, we have the following recurrence. 527 | \[{\sf LIST}(u) = \left\{ 528 | \begin{array}{ll} 529 | 1 & \text{if } u \text{ is a leaf}\\ 530 | \max(1 + \sum_{v \in G_u}{\sf LIST}(v), \sum_{v \in C_u}{\sf LIST}(v))& \text{otherwise}\\ 531 | \end{array} 532 | \right. \] 533 | 534 | The problem is, thus, solved with a post-order visit of $T$ in linear time. 535 | 536 | Observe that the same problem on general graphs is NP-Hard. 537 | 538 | ## Edit distance 539 | ### Problem 540 | *Given two strings $S_1[1,n]$ and $S_2[1,m]$, find the minimum number of edit operations required to transform $S_1$ into $S_2$.* 541 | *There are three edit operations:* 542 | - *Insert a symbol at a given position* 543 | - *Replace a symbol at a given position* 544 | - *Delete a symbol at a given position.* 545 | 546 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/edit-distance/0). 547 | 548 | For example, if the two strings are $S_1 = hello$ and $S_2 = hallo$, 549 | the edit distance is $1$ as we can replace symbol $e$ with $a$ in second positions of $S_1$. 550 | 551 | Let ${\sf ED}(i,j)$ be the edit distance of prefixes $S_1[1,i]$ and $S_2[1,j]$. 552 | The idea is to compute ${\sf ED}(i,j)$ by using shorter prefixes as subproblems. 553 | Indeed, we can compute ${\sf ED}(i,j)$ with the following recurrence. 554 | 555 | \[{\sf ED}(i,j) = \left\{ 556 | \begin{array}{ll} 557 | i & \text{if } $j = 0$\\ 558 | j & \text{if } $i = 0$\\ 559 | {\sf ED}(i-1,j-1) & \text{if } $S[i] = S[j]$ \\ 560 | 1 + \min({\sf ED}(i,j-1), {\sf ED}(i-1,j), {\sf ED}(i-1,j-1)) & \text{otherwise}\\ 561 | \end{array} 562 | \right. \] 563 | 564 | Here we report the matrix obtained for the strings $S_1 = agced$ and $S_2 = abcdef$. 565 | 566 | | | ∅ | a | b | c | d | e | f | 567 | |---|---|---|---|---|---|---|---| 568 | | ∅ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 569 | | a | 1 | 0 | 1 | 2 | 3 | 4 | 5 | 570 | | g | 2 | 1 | 1 | 2 | 3 | 4 | 5 | 571 | | c | 3 | 2 | 2 | 1 | 2 | 3 | 4 | 572 | | e | 4 | 3 | 3 | 2 | 2 | 2 | 3 | 573 | | d | 5 | 4 | 4 | 3 | 2 | 3 | 3 | 574 | 575 | [Here](https://en.wikipedia.org/wiki/Edit_distance) you can find more details about this problem. 576 | 577 | ## Longest palindromic subsequence 578 | ### Problem 579 | *Given a sequence $S[1,n]$, find the length of its longest palindromic subsequence.* 580 | 581 | You can submit your solution [here](https://practice.geeksforgeeks.org/problems/longest-palindromic-subsequence/0). 582 | 583 | Given sequence is $S=bbabcbcab$, then the output should be $7$ as $babcbab$ is the longest palindromic subsequence in it. Notice that $bbbbb$ and $bbcbb$ are palindromic subsequences of $S$, but not the longest ones. 584 | 585 | Let ${\sf LPS}(i,j)$ be the length of the longest palindromic subsequence of 586 | $S[i,j]$. 587 | 588 | There is a very easy solution which reduces to the Longest Common Subsequence Problem. 589 | Indeed, it is easy to see that the longest common subsequence of $S$ and $S^R$, i.e., 590 | $S$ reversed, is the longest palindromic subsequence in $S$. 591 | 592 | A direct computation of the longest palindromic subsequence is based on the idea 593 | of computing ${\sf LPS}(i,j)$ by using three subproblems. 594 | If $S[i]$ and $S[j]$ equal, then we can extend the longest palindromic subsequence of $S[i+1, j-1]$ by prepending and appending character $S[i]$. 595 | If this is not the case, then the longest palindromic subsequence is 596 | the longest palindromic subsequence of either $S[i+1, j]$ or $S[i, j-1]$. 597 | 598 | Thus, the recurrence is as follows. 599 | 600 | \[{\sf LPS}(i,j) = \left\{ 601 | \begin{array}{ll} 602 | 0 & \text{if } $i > j$\\ 603 | 1 & \text{if } $i = j$\\ 604 | 2 + {\sf LPS}(i+1,j-1) & \text{if } $S[i] = S[j]$\\ 605 | \max({\sf LPS}(i+1,j), {\sf LPS}(i,j-1))& \text{otherwise}\\ 606 | \end{array} 607 | \right. \] 608 | 609 | Here we report the matrix obtained for the example above. Observe that we have to fill the matrix starting from its diagonal 610 | 611 | | | b | b | a | b | c | b | c | a | b | 612 | |---|---|---|---|---|---|---|---|---|---| 613 | | b | 1 | 2 | 2 | 3 | 3 | 5 | 5 | 5 | 7 | 614 | | b | 0 | 1 | 1 | 3 | 3 | 3 | 3 | 5 | 7 | 615 | | a | 0 | 0 | 1 | 1 | 1 | 3 | 3 | 5 | 5 | 616 | | b | 0 | 0 | 0 | 1 | 1 | 3 | 3 | 3 | 5 | 617 | | c | 0 | 0 | 0 | 0 | 1 | 1 | 3 | 3 | 3 | 618 | | b | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 3 | 619 | | c | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 620 | | a | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 621 | | b | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 622 | 623 | 624 | ## Weighted job scheduling 625 | ### Problem 626 | *There are $n$ jobs and three arrays $S[1\ldots n]$ and $F[1\ldots n]$ listing 627 | the start and finish times of each job, and $P[1\ldots n]$ reporting the 628 | profit of completing each job. 629 | The task is to choose a subset $X \subseteq \{1, 2, \ldots, n\}$ 630 | so that for any pair $i,j \in X$, either $S[i] > F[j]$ or 631 | $S[j] > F[i]$, which maximizes the total profit.* 632 | 633 | Consider the following example. Arrays are $S=[1,2,4,6,5,7]$, $F=[3,5,6,7,8,9]$, 634 | and $P=[5,6,5,4,11,2]$. 635 | 636 | The solution is as follows. We first sort the jobs by finish time. 637 | 638 | Let ${\sf WJS}(i)$ be the maximum profit by selecting among the first $i$ jobs 639 | (ordered by finish time). 640 | 641 | The value of ${\sf WJS}(i)$ is computed by either excluding or including $i$th 642 | job. If we exclude $i$th job, then ${\sf WJS}(i)={\sf WJS}(i-1)$. 643 | Instead, if it is included, then we have to find the largest index of $j$ such 644 | that $F[j] \leq S[i]$ so that ${\sf WJS}(i)={\sf WJS}(j) + P[i]$. 645 | Obviously, among these two possibilities, we take the one that give the largest profit. 646 | 647 | We assume we have a fake job with index $0$ whose finish time is $-\infty$. 648 | We also let ${\sf WJS}(0)$ to be $0$. This serves as sentinel to avoid special 649 | cases. 650 | 651 | Observe that sorting by finish time guarantees that if we current job $i$ does 652 | not overlap with $j$th job, then it does not overlap with any other job with a 653 | smaller index. This means that we can safely use the value ${\sf WJS}(j)$. 654 | 655 | Notice that the index $j$ can be found in $\Theta(\log n)$ time with binary 656 | search. Thus, the algorithm runs in $\Theta(n\log n)$ time. 657 | 658 | | S | - | 1 | 2 | 4 | 6 | 5 | 7 | 659 | |---|-------------|---|---|----|----|----|----| 660 | | F | $\infty$ | 3 | 5 | 6 | 7 | 8 | 9 | 661 | | P | 0 | 5 | 6 | 5 | 4 | 11 | 2 | 662 | | R | 0 | 5 | 6 | 10 | 14 | 17 | 17 | 663 | 664 | 665 | We notice that this problem under the hypothesis that all the jobs have the same profit is called *activity selection*. For that easier problem, a greedy algorithm finds the optimal schedule in $\Theta(n\log n)$ time. 666 | 667 | ## A coin problem 668 | *A coin is tossed $n$ times. Find the number of combinations such that there is no $3$ consecutive tails.* 669 | 670 | You can submit your solution [here](https://www.hackerearth.com/challenges/college/lets-code-20/algorithm/coin-problem-2/). 671 | 672 | We use a $n\times 3$ matrix $dp$. 673 | For each position $i$, we would like to compute 674 | 675 | - $dp[i][0]$ is the number of combinations for $i$ tosses that ends with head 676 | - $dp[i][1]$ is the number of combinations for $i$ tosses that ends with a tail preceded by head 677 | - $dp[i][2]$ is the number of combinations for $i$ tosses that ends with two tails preceded by head. 678 | 679 | The result is $dp[n][0]+dp[n][1]+dp[n][2]$. 680 | 681 | How do we compute $dp[i][0]$? 682 | 683 | We have 684 | - $dp[1][0] = 1$ 685 | - $dp[1][1] = 1$ 686 | - $dp[1][0] = 0$ 687 | 688 | For a generic position $i$, we compute the three corresponding columns as follows. 689 | 690 | - We put a head in position $i$. In this case we have $dp[i][0] = dp[i-1][0]+dp[i-1][1]+dp[i-1][2]$. 691 | - We put a tail in position $i$. In this case we have $dp[i][1] = dp[i-1][0]$ 692 | and $dp[i][2] = dp[i-1][1]$. 693 | 694 | ## Two other coin problems 695 | *There are two players: Alice and Bob. We have an even number $n$ of coins of different values in a row. First Alice picks up a coin from one of the ends. 696 | Then, Bob takes a coins from one of the (new) ends, and so on. 697 | The game ends when Bob takes the last coin. Is there any stategy for Alice 698 | which always guarantes Alice to get at least as much money as Bob?* 699 | 700 | This puzzle is described in *Mathematical Puzzles* by Peter Winkler. 701 | 702 | Consider coins at even positions and coins at odd positions. 703 | As there is a even number of coins and Alice starts first, 704 | she can always choose to get all coins at even positions or all coins at 705 | odd positions. Thus, she simply chooses even or odd depending on which 706 | gives the best result. 707 | 708 | Notice that this strategy always works, no matter the values of the coins. 709 | Moreover, there no possible strategy when the number of coins is odd. 710 | For example, if we have three coins $1,3,1$ Bob always wins no matter Alice's strategy. 711 | 712 | *We are playing the same game before. Given the $n$ coins $A[1,n]$, we want 713 | to maximize the difference between coins taken by Alice and the ones of Bob. 714 | We assume that both players play optimally.* 715 | 716 | Let be $dp(i,j)$ be the best difference we can have on the subarray $A[i,j]$ 717 | when Alice is the first one to choose. 718 | 719 | \[{\sf dp}(i,j) = \left\{ 720 | \begin{array}{ll} 721 | 0 & \text{if } $i > j$\\ 722 | A[i] & \text{if } $i = j$\\ 723 | \max(A[i] - {\sf dp}(i+1,j), A[j] -{\sf dp}(i,j-1))& \text{otherwise}\\ 724 | \end{array} 725 | \right. \] 726 | 727 | Here is an example. 728 | 729 | | | 10 | 1 | 3 | 5 | 1 | 7 | 730 | |---|----|---|----|----|----|----| 731 | | i/j | 1 | 2 | 3 | 4 | 5 | 6 | 732 | | 1 | 10 | 10-1 = 9 | 10-2 = 8 | 10-3 = 7 | 10-2=10 | **10-5=5** | 733 | | 2 | 0 | 1 | 3-1 = 2 | 5-2 = 3 | 1+1 = 2 | 7-2=5 | 734 | | 3 | 0 | 0 | 3 | 5-3 = 2 | 3-4=-1 | 7+1 = 8 | 735 | | 4 | 0 | 0 | 0 | 5 | 5-1 = 4 | 7-4 = 3 | 736 | | 5 | 0 | 0 | 0 | 0 | 1 | 7-1 = 6 | 737 | | 6 | 0 | 0 | 0 | 0 | 0 | 7 | 738 | 739 | 740 | ## Multiplicity 741 | *You are given an integer array $a_1, a_2, \ldots, a_n$. 742 | The array $b$ is called to be a subsequence of $a$ if it is possible to remove some elements from $a$ to get $b$.* 743 | 744 | *Array $b_1, b_2, \ldots, b_k$. is called to be good if it is not empty and for 745 | every $j$ ($1\leq j \leq k$) $b_j$ is divisible by $j$.* 746 | 747 | *Find the number of good subsequences in $a$ modulo $10^9+7$.* 748 | 749 | The value of $n$ is up to $10^5$, elements of $a$ are up to $10^6$. 750 | 751 | You can submit your solution [here](https://codeforces.com/problemset/problem/1061/C) 752 | 753 | We use $M[i][j]$ to count the number of good subsequences of $a[1,i]$ of 754 | length $j$. 755 | 756 | $M[i][j]$ is equal to $M[i-1][j] + [j|a_i]M[i-1][j-1]$, i.e., we add $M[i-1][j-1]$ 757 | only if $j$ divides $a_i$. 758 | 759 | This solution would require $\Theta(n^2)$ time and space. 760 | 761 | To reduce the space use, we notice that we do not need to use a 2D matrix but we can simply use a vector to store only the last column of $M$. 762 | 763 | To reduce the time, we observe that we only need to update rows corresponding to indexes $j$ that divides the current element $a_i$. Observe that 764 | $a_i$ as at most $\sqrt{a_i}$ divisors (only numbers from $1$ to $\sqrt{a_i}$). 765 | Time complexity is thus $O(n\sqrt{n})$. 766 | 767 | ## Geometric progression 768 | *We are given an array $A[1,n]$ and an integer $K$. 769 | The goal is to count the number of subsequence of $A$ of length $3$ form a geometric progression with ratio $K$. 770 | A geometric progression with ratio $K$ is $b, bK^0, bK^1, bK^2, \ldots$* 771 | 772 | You can submit your solution [here](https://codeforces.com/problemset/problem/567/C) 773 | 774 | For every entry $A[i]$ we want to know the numbers $N[i,1]$, $N[i,2]$ and $N[i,3]$ of subsequences of length, respectively, $1$, $2$, and $3$ in the prefix $A[1,i]$ which end with a number equal to $A[i]$. We keep a counter $c$. 775 | 776 | These numbers can be computed as follows: 777 | - $N[i,1] = N[j,1]+1$, where $j] 19 | node [punkt, fill=red, text=black] {a} 20 | child { 21 | node [punkt, text=black] {b} 22 | child [fill=none] {edge from parent[draw=none]} 23 | child { 24 | node [punkt, fill=red, text=black] {d} 25 | child { 26 | node [punkt, text=black] {g} 27 | [fill=none] {edge from parent[draw=none]} 28 | [fill=none] {edge from parent[draw=none]} 29 | } 30 | child [fill=none] {edge from parent[draw=none]} 31 | } 32 | } 33 | child { 34 | node [punkt, text=black] {c} 35 | child { 36 | node[punkt, fill=red, text=black] {e} 37 | } 38 | child { 39 | node[punkt, fill=red, text=black] {f} 40 | } 41 | }; 42 | \end{tikzpicture} 43 | \end{center} 44 | 45 | \end{document} 46 | -------------------------------------------------------------------------------- /notes/figures/DP_LCS_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/notes/figures/DP_LCS_example.png -------------------------------------------------------------------------------- /slides/Coding1.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/Coding1.key -------------------------------------------------------------------------------- /slides/Coding1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/Coding1.pdf -------------------------------------------------------------------------------- /slides/Introduction.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/Introduction.key -------------------------------------------------------------------------------- /slides/Introduction.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/Introduction.pdf -------------------------------------------------------------------------------- /slides/STL.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/STL.key -------------------------------------------------------------------------------- /slides/STL.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/STL.pdf -------------------------------------------------------------------------------- /slides/segment_trees.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/segment_trees.key -------------------------------------------------------------------------------- /slides/segment_trees.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rossanoventurini/CompetitiveProgramming/68bf15d4182c87d42b5c655f6aa6c12bf077ebd8/slides/segment_trees.pdf --------------------------------------------------------------------------------