├── Task0 ├── A_Light_Wallet.cpp ├── Pawan_and_chocolates.cpp ├── Sam_keeps_searching.cpp └── Order_matters.cpp ├── Task1 ├── Dhruvik's-Obsession.cpp ├── Am-I-Odd-or-Even.cpp ├── Lonely-Nimesh.cpp └── Start_to_Finish.cpp └── README.md /Task0/A_Light_Wallet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | int arr[] = {100,50,10,5,2,1}; 7 | int t; 8 | cin>>t; 9 | for(int i =0 ;i < t ; i++) 10 | { 11 | long long int n; 12 | cin>>n; 13 | long long int cnt=0,j=0; 14 | while(n!=0) 15 | { 16 | cnt += n/arr[j]; 17 | n = n%arr[j]; 18 | j++; 19 | } 20 | cout< 2 | using namespace std; 3 | 4 | 5 | int main() { 6 | int t; 7 | cin>>t; 8 | while(t--) 9 | { 10 | int n; 11 | cin>>n; 12 | vector arr(n); 13 | 14 | for(int i = 0; i >arr[i]; 16 | 17 | sort(arr.begin(),arr.end(),greater()); 18 | 19 | for(int i = 0;i < n ;i++) 20 | { 21 | cout< 2 | using namespace std; 3 | 4 | 5 | int main() 6 | { 7 | int t; 8 | cin>>t; 9 | while(t--) 10 | { 11 | 12 | string s; 13 | cin>>s; 14 | int count[26] = {0}; 15 | for(int i = 0 ;i < s.size() ;i++) 16 | count[s[i] - 'A']++; 17 | int flag = 0; 18 | for(int i = 0;i < s.size() ; i++) 19 | { 20 | if(count[s[i]-'A'] == 1) 21 | { 22 | cout< 2 | using namespace std; 3 | 4 | int LS(int a[] ,int key,int size) 5 | { 6 | int i; 7 | for(i =0 ; i < size ;i++) 8 | { 9 | if(a[i] == key) 10 | return i; 11 | } 12 | return -1; 13 | } 14 | 15 | int main() 16 | { 17 | int t; 18 | cin>>t; 19 | while(t--) 20 | { 21 | int na,nb,a,b; 22 | cin>>na>>nb>>a>>b; 23 | int aa[na],ab[nb]; 24 | 25 | for(int i = 0; i < na ;i++) 26 | cin>>aa[i]; 27 | 28 | for(int i = 0; i < nb ;i++) 29 | cin>>ab[i]; 30 | 31 | if(LS(aa,a,na)!=-1 && LS(ab,b,nb)!=-1) 32 | cout< 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | int n,q; 7 | cin>>n>>q; 8 | vector arr(n); 9 | for(int i = 0; i < n ; i++) 10 | cin>>arr[i]; 11 | 12 | for(int i = 0; i < q ; i++) 13 | { 14 | int k; 15 | cin>>k; 16 | if(k == 1) 17 | { 18 | int t; 19 | cin>>t; 20 | if(arr[t-1] == 0) 21 | arr[t-1] = 1; 22 | else 23 | arr[t-1] = 0; 24 | } 25 | else 26 | { 27 | int a,b; 28 | cin>>a>>b; 29 | if(arr[b-1] == 1) 30 | cout<<"ODD"< 2 | #include 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | 9 | int main() 10 | { 11 | int t; 12 | cin>>t; 13 | while(t--) 14 | { 15 | int n; 16 | cin>>n; 17 | int a[n]; 18 | for(int i = 0; i < n; i++) 19 | cin>>a[i]; 20 | 21 | int max = -1, second_max = -1; 22 | 23 | for(int i = 0; i < n; i++) 24 | { 25 | if(a[i] > max) 26 | { 27 | second_max = max; 28 | max = a[i]; 29 | } 30 | 31 | else if(a[i] < max && a[i] > second_max) 32 | second_max = a[i]; 33 | } 34 | cout< 2 | using namespace std; 3 | 4 | int main() 5 | { 6 | //We use fast I/O method to improve speed. Refer wiki. 7 | ios_base::sync_with_stdio(false); 8 | cin.tie(NULL); 9 | int t; 10 | cin>>t; 11 | while(t--) 12 | { 13 | int n; 14 | cin>>n; 15 | for(int i=0;i>k>>a>>b; 19 | if(a%2==0) 20 | { 21 | cout< 2 | using namespace std; 3 | int isPattern(string text, string pat) 4 | { 5 | int n_t = text.length(); 6 | int n_p = pat.length(); 7 | if(n_p > n_t) 8 | return -1; 9 | int min_ans=INT_MAX; 10 | for(int k=0; k>n; 41 | while(n--) 42 | { 43 | string text,pat; 44 | cin>>text>>pat; 45 | int del=isPattern(text, pat); 46 | if(del==-1) 47 | { 48 | cout<<"NO"< 2 | 3 | ## Table of Contents 4 | 5 | * 1. [Introduction to Competitive Coding](#IntroductiontoCompetitiveCoding) 6 | * 2. [STL in C++ and Collections in Java](#STLinCandCollectionsinJava) 7 | * 2.1. [Imports](#Imports) 8 | * 2.2. [Strings](#Strings) 9 | * 2.3. [Inputting, Concatenating, Comparing Strings](#InputtingConcatenatingComparingStrings) 10 | * 2.4. [Vectors](#Vectors) 11 | * 3. [Some Useful Functions](#SomeUsefulFunctions) 12 | * 3.1. [Sorting](#Sorting) 13 | * 3.2. [Min, Max](#MinMax) 14 | * 3.3. [Further Reading](#FurtherReading) 15 | * 4. [Recursion](#Recursion) 16 | * 5. [Time Complexities](#Time) 17 | * 5.1 [Introduction](#Timeintro) 18 | * 5.2 [Big O notation](#Timebig) 19 | * 5.3 [Further Reading](#Timefurther) 20 | * 6. [Fast IO for Competitive Programming](#Fastio) 21 | * 7. [Basic Mathematics](#Basemaths) 22 | * 7.1 [GCD and LCM](#Gcdlcm) 23 | * 7.2 [Combinatorics](#Combinatorics) 24 | * 7.3 [Bit Manipulation](#Bitmanipulation) 25 | * 7.4 [Primality and Sieve of Eratosthenes](#Primality) 26 | * 8. [Modular Arithmetic](#Modarith) 27 | * 9. [Ad Hoc](#Adhoc) 28 | * 10. [Kadane's Algorithm and Prefix Sum](#Kadane) 29 | 30 | ## 1. Introduction to Competitive Coding 31 | 32 | Let us first talk about how one should approach a problem in Competitive Coding. There are broadly 4 steps - 33 | 34 | **1. Understanding the problem:** Try and figure out the basic logic behind the problem. If you don't understand how it's working, then the best way around it is to write up some random test cases and figure out the logic. This process helps you later to test your code more thoroughly. 35 | 36 | **2. The Algorithm:** Come up with an algorithm. Don't start coding yet. Find cases where your code might be failing. Take care of these cases. This is an iterative process. **Always look for cases you might be missing.** More formally, prove the correctness of the algorithm. Run the algorithm over the test cases that you found in Step 1. This process is called a **dry run**. 37 | 38 | **3. Validate Constraints:** Once you have an airtight logic, find the runtime of your algorithm. See if it's enough to pass the time limit considering the **worst case, not the best case**. If it isn't, find ways to optimize the code. Most of the times, it's a data structure that helps you out. Most people overlook this step and this almost always results in a Time Limit Exceeded Error. 39 | 40 | **4. Code:** Write the code. Submit. If it doesn't pass, that means you went wrong in one of the previous steps. Start again at step 1 to check the problem statement and see if you've missed some tiny detail in the question. Then start thinking of possible edge cases where your code might be failing. If there is a timeout error, that shows that you didn't check if the runtime fits in the given constraints. The best way to fix it then is to check the values being computed and see if there are any anomalies. 41 | 42 | A few tips for everyone - 43 | 44 | Master your language. If you're doing it in C++, learn the **STL** well, same goes for Java and **Collections**. Have the tools you need at your disposal. Learn the different space and time complexities for each data structure. Not knowing the underlying complexities often lead to wasting time on attempting the problem with unnecessary and costly implementations. 45 | 46 | The key to improving yourself is practice. People chose different ways to do this. You can choose a standard platform and sort the problems by the number of people who have solved the problem. Keep solving. The most popular choices are Hackerrank and Codechef. If you can't solve a problem even after trying it out a lot, look at the editorials. Understand the solution, and then implement it on your own. Look at other people's submissions. Sometimes the red coders have very intriguing solutions to the simplest of problems. 47 | 48 | For your practice we are providing you with a few problems based on all the topics listed below. You can find them [here](https://www.hackerrank.com/contests/iecse-winterproject-2019/challenges/filters/page:1). 49 | 50 | Start attempting contests. Codechef long contests are really good for beginners. Since this contest runs for ten days, you'll have enough time to research and find the right algorithms for the problems. Once you're confident, you can start attempting short contests on platforms like codeforces, codechef, etc. The most important time of a contest is after the contest. This is when you try solving the problems that you couldn't solve during the contest. This is called up solving. This is a very efficient way of learning new tricks, optimizations, and concepts. 51 | 52 | Also check [this](https://www.codechef.com/certification/data-structures-and-algorithms/prepare) out! 53 | 54 | ## 2. STL in C++ and Collections in Java 55 | When you are taking part in a competition, creating functions/methods for certain tasks, like extracting substrings, sorting, adding and removing elements to/from an array, requires time to code and hence you lose out on valuable time. A good understanding of the library functions is important for writing quick and bug-free code. Most programming languages provide with predefined libraries which help you do the same. Here are a few you'll need to know to get started with competitive coding. 56 | 57 | >It is always suggested you understand how these are implemented without using STL, because if you ever face a problem where time is a constraint or requires a specific form of updation which STL do not have, you will have to code a program for it. 58 | 59 | 60 | #### 2.1. Imports 61 | 62 | Imports for C++ STL 63 | ```cpp 64 | #include 65 | ``` 66 | Imports for Java Utility Package 67 | ```Java 68 | import java.util.*; 69 | import java.io.*; // Classes for Fast I/O implementation in Java 70 | ``` 71 | 72 | #### 2.2. Strings 73 | 74 | If you have ever tried coding in C, you are probably used to declaring a string using an array of chars. C++ offers a string class that makes string handling easier. 75 | 76 | The following code snippet shows how to declaring and use a string : 77 | 78 | ```cpp 79 | #include 80 | using namespace std; 81 | int main() 82 | { 83 | string str = "Coding is fun"; // Declaring and initialising string 84 | 85 | int len = str.length(); // the length() function returns the length of the string 86 | 87 | cout<<"The length of string "<Inputting, Concatenating, Comparing Strings 108 | A major advantage of using string class instead of character array is that you don't need to know the size of the string while declaring it. 109 | 110 | Concatenating strings is also easier with the string class. You can concatenate two strings using the '+' operator. 111 | 112 | For comparing if two strings are equal , you can either use the relational operators('<' , '>' , '==' , "!="). Another way is using the compare function. 113 | ```cpp 114 | #include 115 | using namespace std; 116 | int main() 117 | { 118 | // Input 119 | 120 | string str1; // Declaring a string 121 | cin>>str1; // Taking user input for the string 122 | 123 | int len = str1.length(); // the length() function returns the length of the string 124 | cout<<"The length of string "<0) 187 | System.out.println("s5 greater than s4"); 188 | else if(s5.compareTo(s4)<0) 189 | System.out.println("s5 less than s4"); 190 | else 191 | System.out.println("s5 equal to s4"); 192 | 193 | String s6 = ""; 194 | 195 | for(int i=0;i<26;i++){ 196 | s6 += (char)(i+'a'); // shorthand operator += 197 | } 198 | 199 | System.out.println(s6); 200 | } 201 | } 202 | ``` 203 | #### 2.4. Vectors 204 | 205 | A vector is a container i.e. something you can use to store many elements together. It is similar to an array but with added functionalities. 206 | 207 | You don't need to know the size of a vector when declaring it. You can also get a vector's length and resize a vector at runtime. 208 | 209 | 210 | ```cpp 211 | #include 212 | using namespace std; 213 | int main() 214 | { 215 | vector v1(10); // this is a declaration for a vector of integers that has size 10. Note that unlike an array declaration, we use () 216 | // instead of [] 217 | for(int i=0 ; i < 10 ; i++) 218 | { 219 | v1[i] = i; 220 | } 221 | 222 | for(int i=0 ; i < 10 ; i++) 223 | { 224 | cout<< v1[i] << " "; 225 | } 226 | cout<< endl; 227 | 228 | vector v2; // Here, we are not declaring the size of the vector 229 | 230 | int len = v2.size(); // v.size() returns the size of the vector 231 | cout<<"Initial size of v2 is "< 255 | using namespace std; 256 | int main() 257 | { 258 | vector v1(10,"Hello"); // Declaring a vector of of size 10 that holds strings.Each index in the vector 259 | // is initialized to the value "Hello" 260 | for(int i=0 , n = v1.size() ; i<10 ; i++) 261 | { 262 | cout<<"Replacing "< v2 = v1 ; // Here v2 is initialized with the same size and values as v1 271 | 272 | for(int i=0 , n = v2.size() ; i v1 = new ArrayList(Arrays.asList(new Integer[10])); 290 | 291 | for(int i=0;i<10;i++){ 292 | v1.set(i,i); 293 | } 294 | 295 | for(int i=0;i<10;i++){ 296 | System.out.println(v1.get(i)); 297 | } 298 | 299 | ArrayList v2 = new ArrayList(); 300 | 301 | System.out.println("Initial size is "+v2.size()); 302 | 303 | for(int i=0;i<15;i++){ 304 | v2.add(i); // cannot use set() as they cannot be indexed yet 305 | } 306 | 307 | for(int i=0;i<15;i++){ 308 | System.out.println(v2.get(i)); 309 | } 310 | 311 | System.out.println("Length of v1 : "+v1.size()+" and Length of v2 : "+v2.size()); 312 | 313 | v2.ensureCapacity(50); // resize to 50 314 | 315 | if(!v2.isEmpty()) // isEmpty() function to check if arraylist is empty 316 | System.out.println("Size of v2 is "+v2.size()); 317 | 318 | v2.clear(); // clear arraylist 319 | 320 | System.out.println("Size of v2 is now : "+v2.size()); 321 | } 322 | } 323 | ``` 324 | ## 3. Some Useful Functions 325 | 326 | #### 3.1. Sorting 327 | 328 | C++ provides the sort(pointer_to_first_ele , pointer_to_last_ele) function to sort arrays and vectors. The sort function is more efficient than sorting algorithms like bubble sort. It is also easier to use. 329 | 330 | ```cpp 331 | int a[5] = {5 , 4 , 3 , 2 , 1}; 332 | sort(a , a + n); // to sort an array we pass the pointer to the first and last element of the array 333 | 334 | vector v(10); 335 | 336 | for(int i=10 ; i > -1 ; i--) v[i] = i; 337 | sort(v.begin() , v.end()); // Here also, we pass the pointer to the first and last element in the vector. 338 | // v.begin() returns the pointer to the first element and v.end() returns the pointer to the last element 339 | 340 | struct Interval 341 | { 342 | int first, second; 343 | }; 344 | 345 | bool compare(Interval i1, Interval i2) 346 | { 347 | return (i1.first < i2.first); 348 | } 349 | Interval arr[] = { {6,8}, {1,9}, {2,4}, {4,7} }; 350 | int n = 4; 351 | sort(arr, arr+n, compare); // sorts the second element in arr with redpect to the 352 | // first element in the array by passing an instance of the 353 | // compare function to sort(). Note that return type of compare() has to be of type 354 | // boolean for the sorting to occur in increasing order of first element. 355 | 356 | ``` 357 | Java equivalent is using Arrays.sort() and Collections.sort() 358 | ```Java 359 | int a[] = {5 , 4 , 3 , 2 , 1}; 360 | 361 | Arrays.sort(a); // sort an array 362 | 363 | for(int i=0;i<5;i++) 364 | System.out.println(a[i]); 365 | 366 | ArrayList v = new ArrayList(); 367 | 368 | for(int i=4;i>=0;i--) v.add(i); 369 | 370 | Collections.sort(v); // sort an arraylist 371 | 372 | for(int i=0;i<5;i++) 373 | System.out.println(v.get(i)); 374 | 375 | 376 | 377 | 378 | //Sorting with respect to an attribute of a class 379 | 380 | class Student // a class to represent a student 381 | { 382 | int rollno; 383 | String name, address; 384 | 385 | // Constructor 386 | public Student(int rollno, String name, 387 | String address) 388 | { 389 | this.rollno = rollno; 390 | this.name = name; 391 | this.address = address; 392 | } 393 | 394 | } 395 | 396 | 397 | class Sortbyroll implements Comparator 398 | { 399 | // Used for sorting in ascending order of 400 | // roll number 401 | public int compare(Student a, Student b) 402 | { 403 | return a.rollno - b.rollno; 404 | } 405 | } 406 | 407 | 408 | Student [] arr = {new Student(111, "bbbb", "london"), 409 | new Student(131, "aaaa", "nyc"), 410 | new Student(121, "cccc", "jaipur")}; 411 | 412 | System.out.println("Unsorted"); 413 | for (int i=0; iMin, Max 422 | 423 | The min and max functions can be used to find the minimum and maximum of multiple numbers without using many if else statements. 424 | 425 | ```cpp 426 | int a=1 , b=2 , c=3 , d=4; 427 | int maximum = max(max(a , b) , max(c , d)); // maximum of four numbers 428 | int minimum = min(min(a , b) , min(c , d)); // minimum of four numbers 429 | ``` 430 | Java equivalent 431 | ```Java 432 | int a = 1,b = 2,c = 3,d = 4; 433 | int maximum = Math.max( Math.max(a,b) , Math.max(c,d) ); 434 | int minimum = Math.min( Math.min(a,b) , Math.min(c,d) ); 435 | ``` 436 | To use max(), min() directly you can use static imports 437 | ```Java 438 | import static java.lang.Math.*; 439 | ``` 440 | 441 | #### 3.3. Further Reading 442 | A great place to get started would be geeksforgeeks, links for which are provided below. 443 | * [STL](https://www.geeksforgeeks.org/the-c-standard-template-library-stl/) 444 | * [java.util](https://www.geeksforgeeks.org/java-util-package-java/) 445 | * [Strings in C++](https://www.geeksforgeeks.org/strings-library-in-cpp-stl/) , [Strings in Java](https://www.geeksforgeeks.org/string-class-in-java/) 446 | 447 | 448 | ## 4. Recursion 449 | 450 | Imagine you have to build a robot which can perform a certain task, like add A to B. Now you are told to use a unit from an infinite supply of units which can only add and subtract 1 to/from a number provided to it, and also perform logical operations. How will you build a system which adds A to B perfectly. 451 | 452 | You'll give both numbers to the robot, which will pass them to a secondary robot which adds 1 to A and subtracts 1 from B and keep passing along until B is 0, and then the final value is returned. Here we don't violate the rules and still get an answer. 453 | 454 | With recursion you can breakdown a complex problem into a simpler unit which can be solved by calling the same function again and again till a certain stop condition is reached. 455 | 456 | ```cpp 457 | int add(int a,int b) 458 | { 459 | if(b==0) //By the time b becomes 0, a becomes a+b 460 | return a; //As a is now a+b it is safe to return the new value 461 | return add(a+1,b-1); //Here the output of the secondary call is returned from primary call 462 | } //which also applies for that secondary call and further ahead. 463 | ``` 464 | 465 | Recursion is a technique by which a function repeatedly calls itself (Or a different function) to have an effect similar to a loop. 466 | 467 | A Recursive function in it's most basic form consists of two parts. 468 | * Base case 469 | * Recursive call 470 | 471 | This flow chart shows how a basic recursive function works 472 | 473 | ![Recursion.png](https://www.programtopia.net/sites/default/files/recursion.png) 474 | 475 | ###### 7.1. Base case 476 | The base case or the terminal case consists of the final step of the function which marks the end of the recursive function. 477 | 478 | ###### 7.2. Recursive call 479 | 480 | This step usually performs the calculations required and calls a smaller version of the main problem. 481 | This goes on until it reaches the base case. 482 | 483 | ###### 7.3. Choosing base case and recursive call 484 | 485 | The choice of the base case and recursive call for your function is really important as these decide how your function works. 486 | 487 | The recursive call of your function must be such that at each successive recursive call the function reaches closer to your base case, i.e after multiple calls to your function, you should eventually reach your base case. 488 | 489 | The base case of your function decides when your function ends, so your base case should be selected such that your recursive case can never overshoot your base case. 490 | 491 | ### 4.1. Examples 492 | So lets try out a couple of examples on how recursion works. 493 | #### 4.1.1. Example 1: Fibonacci series 494 | 495 | The fibonacci series in mathematics is represented by 496 | F(0) = 1 497 | F(1) = 1 498 | F(x) = F(x-1) + F(x-2). 499 | This problem gives us the perfect example of where to use recursion. 500 | 501 | This code in c++ would be 502 | ```c++ 503 | int fibonacci(int x) 504 | { 505 | if(x == 0 || x == 1) 506 | return 1; 507 | return fibonacci(x - 1) + fibonacci(x - 2); 508 | } 509 | ``` 510 | 511 | The same code in Python would be 512 | ```python 513 | def fibonacci(x): 514 | if x == 0 or x == 1: 515 | return 1 516 | return fibonacci(x - 1) + fibonacci(x - 2) 517 | ``` 518 | The same code in Java would be 519 | ```Java 520 | public int fibonacciRecursion(int n) 521 | { 522 | if(n == 0) 523 | return 0; 524 | if(n == 1 || n == 2) 525 | return 1; 526 | return fibonacciRecursion(n-2) + fibonacciRecursion(n-1); 527 | } 528 | ``` 529 | 530 | Here ``if(x == 0 || x == 1) `` is the base case and it returns when x = 0 or x = 1 and 531 | ``return fibonacci(x - 1) + fibonacci(x - 2)`` is the recursive call. 532 | We can verify that the recursive call can never go below 1 or 0 as long as the initial input is valid because it is taken care of by the base case thus we never go past the base case. 533 | Also we see that with every call to the function x is getting smaller and thus closer to the base case of 0 or 1. 534 | 535 | #### 4.1.2. Example 2: Factorials 536 | 537 | The factorial of a number n is equal to n\*(n-1)\*(n-2)...1 538 | ie, 539 | 540 | ``` F(n) = n*(n-1)*(n-2)...1 ``` 541 | 542 | Thus the code in c++ for this would be 543 | ```c++ 544 | int factorial(int x) 545 | { 546 | if(x <= 1) 547 | return 1; 548 | return x*factorial(x - 1); 549 | } 550 | ``` 551 | 552 | Similarly in python this code becomes 553 | ```python 554 | def factorial(x): 555 | if x <= 1: 556 | return 1 557 | return x*factorial(x - 1) 558 | ``` 559 | 560 | Similarly in Java the code becomes 561 | ```Java 562 | public int factorial(int n) 563 | { 564 | if (n == 0) 565 | return 1; 566 | else 567 | return(n * factorial(n-1)); 568 | } 569 | ``` 570 | 571 | Again here ``if(x == 1)`` is the base case and returns when x is 1 and ``return x*factorial(x - 1)`` 572 | is the recursive call. 573 | Here too we see that x can never go below 1 as long as the initial input is above 1 and we also notice that with every successive recursive call x gets closer to 1. 574 | 575 | ## 5. Time Complexities 576 | 577 | ### 5.1 Introduction 578 | 579 | Thinking of an efficient algorithm to solve a problem is one of the hardest tasks in competitive programming. Assessing your algorithm's efficiency is of utmost importance. This is where Time Complexities are useful. They help us decide whether certain algorithms can solve the problem within the required time and space constraints. Time Complexity is one of the most important metrics of comparison for Algorithms. 580 | 581 | For example consider two different sorting algorithms, bubble and quick sort. [Bubble Sort](https://www.geeksforgeeks.org/bubble-sort/) has a time complexity of O(N2) whereas [Quick Sort](https://www.geeksforgeeks.org/quick-sort/) has a complexity of O(NlogN). Thus, we conclude that quick sort is more efficient than bubble sort. We will get into Big O notation later in this tutorial. 582 | 583 | A lot of you must have faced an issue by now where your code passes some of the test cases, and some you get an error called TLE (Time Limit Exceeded). This is caused by non-efficient code. Every testcase comes with a time limit. Your code needs to produce an output for the given test case in that time limit for it to pass the case. If you encounter this error you need to make your code more efficient. Let us look at a sample code to understand complexities better. 584 | 585 | #### A Sample: 586 | 587 | ```cpp 588 | int func(int n) 589 | { 590 | int sum=0; //line 1 591 | for(int i=0;i arr[j+1]) //line6 621 | swap(&arr[j], &arr[j+1]); //line7 622 | } //line8 623 | } 624 | } 625 | ``` 626 | 627 | Here *n* is the size of the array. 628 | 629 | Let us now compute the number of times a statement is executed for each call of the function. 630 | 631 | Line 1 is a single statement and hence executes in one unit of time each. 632 | 633 | Line 2 has a for loop which executes another for loop. So for every execution of the first for loop, the second for loop is executed. The second for loop, at most will run n-1 times for each execution of the first for loop. 634 | 635 | The first for loop is executed n times. For each time the first for loop is executed, the second for loop, at most, is executed n-1 times. 636 | 637 | Thus the total runtime can be written as a function of the array size squared, i.e. n2. 638 | 639 | ### 5.2 Big O notation 640 | 641 | Big O notation is used in Computer Science to describe the performance or complexity of an algorithm. Big O specifically describes the worst-case scenario, and can be used to describe the execution time required by an algorithm. 642 | 643 | We use the Big O notation for analyzing algorithms because it gives us an upper bound, and we are mostly concerned with the worst case scenarios. 644 | 645 | Let us look at the most common complexities to understand Big O better. 646 | 647 | ##### O(1) or Constant Time 648 | 649 | This is when the algorithm runs in constant time, i.e doesn't depend on the size of the input. 650 | 651 | ```cpp 652 | int start = 10; 653 | int end = 20; 654 | int mid; 655 | mid = (start + end)/2; 656 | ``` 657 | 658 | ##### O(n) or Linear Time 659 | 660 | This is when the runtime of the algorithm grows linearly with the size of the input. For example, 661 | 662 | ```cpp 663 | for(int i=0;i2) or Quadratic Time 668 | 669 | This is when the runtime of the algorithm grows quadratically with respect to the size of the input. For example, 670 | 671 | ```cpp 672 | for(int i=0;i arr[mid]) 689 | return binsearch(arr,mid+1,high); 690 | return binsearch(arr,low,mid-1); 691 | } 692 | ``` 693 | 694 | The logarithm is base 2, i.e, log2N 695 | 696 | ### 5.3 Further Reading 697 | 1. Chapter 1,3 of Introduction to Algorithms, Second Edition, by Thomas Cormen, Charles Leiserson, Ronald Rivest, Clifford Stein. 698 | 2. [Computational Complexity](https://www.topcoder.com/community/data-science/data-science-tutorials/computational-complexity-section-1/) 699 | 3. [Algorithmic Complexity](https://www.cs.cmu.edu/~adamchik/15-121/lectures/Algorithmic%20Complexity/complexity.html) 700 | 4. [Complexity Analysis](https://www.hackerearth.com/practice/basic-programming/complexity-analysis/time-and-space-complexity/tutorial/) 701 | 5. [Big O Cheat Sheet](http://bigocheatsheet.com/) - contains complexities of standard sorting algorithms and standard data structures 702 | 703 | ## 6. Fast IO for Competitive Programming 704 | 705 | In competitive programming, it is important to read input as fast as possible so we save valuable time. 706 | 707 | You must have seen various problem statements saying: “Warning: Large I/O data, be careful with certain languages (though most should be OK if the algorithm is well designed)”. Key for such problems is to use Faster I/O techniques. 708 | 709 | For such problems, the I/O data is extremely large and what we require is fast IO. 710 | 711 | ###### C++ 712 | 713 | Most of you who use C++ would be using cin-cout for IO. However you might find it surprising to know that scanf and printf are actually faster than cin-cout. In fact, scanf is actually almost 5 times faster. You can check out some comparisons [here](https://www.geeksforgeeks.org/cincout-vs-scanfprintf/). 714 | 715 | This is because the C++ library includes the C library, it needs to support the C and C++ I/O at the same time. To synchronize the buffers, cin is synchronizing itself with the underlying C-library’s stdio buffer. As a result, it runs slightly slower. 716 | Although it’s slower, it lets you freely mix C++ and C I/O. However there's a work around for this. 717 | 718 | ```cpp 719 | ios_base::sync_with_stdio(false); //line1 720 | cin.tie(NULL); //line2 721 | ``` 722 | Line 1 toggles on or off the synchronization of all the C++ standard streams with their corresponding standard C streams if it is called before the program performs its first input or output operation. Adding ios_base::sync_with_stdio (false); (which is true by default) before any I/O operation avoids this synchronization. It is a static member of function of std::ios_base. 723 | 724 | tie() is a method which simply guarantees the flushing of std::cout before std::cin accepts an input. This is useful for interactive console programs which require the console to be updated constantly but also slows down the program for large I/O. The NULL part just returns a NULL pointer. 725 | 726 | Just add these two lines at the beginning of main() and you are good to go! 727 | 728 | ###### Java 729 | 730 | Most of you who use Java would be using the Scanner class for IO. It is easy to implement and requires a lot less typing, however it is also very slow. This is because scanner invloves parsing of tokens. What this means is that Scanner breaks what you parse into tokens, the criteria being whitespaces, tabs, new lines, etc. 731 | 732 | There are a few workarounds, check them out: 733 | 734 | - [Fast I/O in Java for Competitive Programming](https://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/) 735 | 736 | We would recommend you make a practice of using Fast IO methods. Sometimes it can happen that no warning is provided and you would be left wondering why your code is not working. 737 | 738 | ## 7. Basic Mathematics for Competitive Programming 739 | 740 | ### 7.1. Greatest Common Divisor and Least Common Multiple 741 | 742 | The GCD (Greatest Common Divisor) of two numbers is defined as the largest integers that divide both the numbers. For example, 2 is the GCD of 4 and 6. From this concept, follows something called co-primes. Two numbers are said to be co-prime if their GCD is 1. For example, 3 and 5 are co-primes because their GCD is 1. 743 | 744 | LCM (Least Common Multiple) is defined as the smallest integer that is divisible by both the numbers. For example, 10 is the LCM of 2 and 5. 745 | 746 | #### Euclid's algorithm 747 | 748 | This is one of the most famous algorithms for computing gcd of two numbers. 749 | Consider two numbers a and b. The procedure of Euclid's algorithm can be broken down into a sequence of equations, 750 | 751 | ![](https://wikimedia.org/api/rest_v1/media/math/render/svg/8b9f7b38708371bce2fee00c52ba4e5138a28d52) 752 | 753 | If a is smaller than b, the first step of the algorithm swaps the numbers. For example, if a < b, the initial quotient is zero and the remainder is a. Thus, rk is smaller than it's predecessor rk-1. 754 | 755 | Since the remainders decrease with every iteration, a remainder rN must eventually equal 0, at which point this algorithm stops. The final non-zero remainder rN-1 is the greatest common divisor for a and b. 756 | 757 | g = gcd(a, b) = gcd(b, r0) = gcd(r0, r1) = … = gcd(rN−2, rN−1) = rN−1. 758 | 759 | For proof of the algorithm, visit [here](https://www.whitman.edu/mathematics/higher_math_online/section03.03.html). 760 | 761 | A simple implementation of Euclid's GCD algorithm in C++ would be, 762 | 763 | ```cpp 764 | int gcd(int a,int b) 765 | { 766 | return b==0?a:gcd(b,a%b); 767 | } 768 | ``` 769 | 770 | Once we calculate the GCD of two numbers, we can calculate the LCM very easily. 771 | 772 | ```cpp 773 | int lcm(int a,int b) 774 | { 775 | return (a*b)/gcd(a,b); 776 | } 777 | ``` 778 | 779 | ### 7.2. Combinatorics 780 | 781 | Combinatorics is the branch of mathematics that deals with combinations of elements belonging to a finite set in accordance with some constraints. 782 | 783 | ###### Principle of Addition 784 | 785 | The principle of addition states if one task can be done in *m* ways and another task which is **mutually exclusive** of the first task can be done in *n* ways, then the the number of possible ways in which either can be done is *m+n*. 786 | 787 | ###### Principle of Multiplication 788 | 789 | The principle of multiplication states that if one task can be done in *m* ways and another task which is **independent** of the first task can be done in *n* ways, after the first task has been performed, then the number of possible ways in which both the tasks can be done is *m×n*. 790 | 791 | ###### Combinations of Objects 792 | 793 | Number of ways in which you can select *n* objects taken *r* at a time. (Order does not matter.) 794 | 795 | *n**C**r* *= n! / r! (n - r)!* 796 | 797 | ###### Permutations of Objects 798 | 799 | Number of ways you can order *n* objects taken *r* at a time. (Order matters.) 800 | 801 | *n**P**r* *= n! / (n - r)!* 802 | 803 | 804 | ###### Stars and Bars 805 | 806 | **Theorem one** 807 | 808 | For any pair of positive integers *n* and *k*, the number of *k*-tuples of positive integers whose sum is *n* is equal to the number of *(k − 1)*-element subsets of a set with *n − 1* elements. 809 | 810 | Let us say that we need to distribute 7 cookies to 4 kids such that they all have at least 1. We can represent it as stars and bars. 811 | 812 | * * * | * | * | * * 813 | 814 | Here the 4 kids get 3, 1, 1 and 2 cookies respectively. We can say that we can place *(k-1)* bars between *(n-1)* spaces between the stars. Thus, the answer is 6*C*3. 815 | 816 | This can be generalised as *(n-1)**C**(k-1)*. 817 | 818 | **Theorem two** 819 | 820 | For any pair of positive integers *n* and *k*, the number of *k*-tuples of non-negative integers whose sum is *n* is equal to the number of multisets of cardinality *k − 1* taken from a set of size *n + 1*. 821 | 822 | Let us say that we need to distribute 7 cookies among 4 kids where each kid may get none or more cookies. We can represent this situation using stars and bars as well. 823 | 824 | * * * | | * * | * * 825 | 826 | Here the 4 kids get 3, 0, 2 and 2 cookies respectively. So there are 10 symbols out of which 3 have to be bars. Thus, the answer is 10*C*3. 827 | 828 | This can be generalised as *(n+k-1)**C**(k-1)*. 829 | 830 | ###### Properties of Combinations 831 | 832 | ![Combinations Properties](https://www.studypage.in/images/maths/algebra/combination-properties.jpg) 833 | 834 | ### 7.3. Bit Manipulation 835 | 836 | Working on bytes, or data types comprising of bytes like ints, floats, doubles or even data structures which stores a large number of bytes is normal for a programmer. In some cases, a programmer needs to go beyond this - that is to say that in a deeper level where the importance of bits is realized. 837 | 838 | Operations with bits are used in Data compression (data is compressed by converting it from one representation to another, to reduce the space), Exclusive-Or Encryption (an algorithm to encrypt the data for safety issues). In order to encode, decode or compress files we have to extract the data at the bit level. Bitwise Operations are faster and closer to the system and sometimes optimize the program to a good level. 839 | 840 | We all know that 1 byte comprises of 8 bits and an integer or character can be represented using bits in computers, which we call its binary form(contains only 1 or 0) or in its base 2 form. 841 | 842 | ``` 843 | Example: 844 | 1) 14 = {1110} 845 | = 1 * 23 + 1 * 22 + 1 * 21 + 0 * 20 846 | = 14. 847 | 848 | 2) 20 = {10100} 849 | = 1 * 24 + 0 * 23 + 1 * 22 + 0 * 21 + 0 * 20 850 | = 20. 851 | ``` 852 | 853 | For characters, we use ASCII representation, which is in the form of integers which again can be represented using bits as explained above. 854 | 855 | #### Bitwise Operators 856 | 857 | There are different bitwise operations used in the bit manipulation. These bit operations operate on the individual bits of the bit patterns. Bit operations are fast and can be used in optimizing time complexity. Some common bit operators are: 858 | 859 | **NOT ( ~ )**: Bitwise NOT is a unary operator that flips the bits of the number i.e., if the ith bit is 0, it will change it to 1 and vice versa. Bitwise NOT is nothing but simply the one’s complement of a number. Let's take an example. 860 | 861 | N = 5 = (101)2 862 | ~N = ~5 = ~(101)2 = (010)2 = 2 863 | 864 | **AND ( & )**: Bitwise AND is a binary operator that operates on two equal-length bit patterns. If both bits in the compared position of the bit patterns are 1, the bit in the resulting bit pattern is 1, otherwise 0. 865 | 866 | A = 5 = (101)2 , B = 3 = (011)2 A & B = (101)2 & (011)2= (001)2 = 1 867 | 868 | **OR ( | )**: Bitwise OR is also a binary operator that operates on two equal-length bit patterns, similar to bitwise AND. If both bits in the compared position of the bit patterns are 0, the bit in the resulting bit pattern is 0, otherwise 1. 869 | 870 | A = 5 = (101)2 , B = 3 = (011)2
871 | A | B = (101)2 | (011)2 = (111)2 = 7 872 | 873 | **XOR ( ^ )**: Bitwise XOR also takes two equal-length bit patterns. If both bits in the compared position of the bit patterns are 0 or 1, the bit in the resulting bit pattern is 0, otherwise 1. 874 | 875 | A = 5 = (101)2
B = 3 = (011)2

876 | A ^ B = (101)2 ^ (011)2 = (110)2 = 6 877 | 878 | **Left Shift ( << )**: Left shift operator is a binary operator which shift some number of bits, in the given bit pattern, to the left and append 0 at the end. Left shift is equivalent to multiplying the bit pattern with 2^k ( if we are shifting k bits ). 879 | 880 | 1 << 1 = 2 = 21
881 | 1 << 2 = 4 = 22
882 | 1 << 3 = 8 = 23
883 | 1 << 4 = 16 = 24
884 | …
885 | 1 << n = 2n
886 | 887 | **Right Shift ( >> )**: Right shift operator is a binary operator which shift the some number of bits, in the given bit pattern, to the right and append 1 at the end. Right shift is equivalent to dividing the bit pattern with 2^k ( if we are shifting k bits ). 888 | 889 | 4 >> 1 = 2
890 | 6 >> 1 = 3
891 | 5 >> 1 = 2
892 | 16 >> 4 = 1
893 | 894 | ![Table](https://he-s3.s3.amazonaws.com/media/uploads/cb985c2.png) 895 | 896 | > Bitwise operators are good for saving space and sometimes to cleverly remove dependencies. 897 | 898 | ###### **How to check if a given number is a power of 2 ?** 899 | 900 | Consider a number N and you need to find if N is a power of 2. A simple solution to this problem is to repeatedly divide N by 2 if N is even. If we end up with a 1 then N is a power of 2, otherwise not. There is a special case also. If N = 0 then it is not a power of 2. 901 | ```cpp 902 | bool isPowerOfTwo(int x) 903 | { 904 | if(x == 0) 905 | return false; 906 | else 907 | { 908 | while(x % 2 == 0) x /= 2; 909 | return (x == 1); 910 | } 911 | } 912 | ``` 913 | 914 | The above function will return true if x is a power of 2, otherwise false. 915 | The time complexity of the above code is O(logN). 916 | 917 | The same problem can be solved using bit manipulation. Consider a number x that we need to check for being a power for 2. Now think about the binary representation of (x-1). (x-1) will have all the bits same as x, except for the rightmost 1 in x and all the bits to the right of the rightmost 1. 918 | Let, x = 4 = (100)2
919 | x - 1 = 3 = (011)2
920 | Let, x = 6 = (110)2
921 | x - 1 = 5 = (101)2
922 | 923 | It might not seem obvious with these examples, but binary representation of (x-1) can be obtained by simply flipping all the bits to the right of rightmost 1 in x and also including the rightmost 1. 924 | 925 | Now think about x & (x-1). x & (x-1) will have all the bits equal to the x except for the rightmost 1 in x. 926 | 927 | Let, x = 4 = (100)2
928 | x - 1 = 3 = (011)2
929 | x & (x-1) = 4 & 3 = (100)2 & (011)2 = (000)2
930 | Let, x = 6 = (110)2
931 | x - 1 = 5 = (101)2
932 | x & (x-1) = 6 & 5 = (110)2 & (101)2 = (100)2
933 | 934 | Properties for numbers which are powers of 2, is that they have one and only one bit set in their binary representation. If the number is neither zero nor a power of two, it will have 1 in more than one place. So if x is a power of 2 then x & (x-1) will be 0. 935 | 936 | ```cpp 937 | bool isPowerOfTwo(int x) 938 | { 939 | // x will check if x == 0 and !(x & (x - 1)) will check if x is a power of 2 or not 940 | return (x && !(x & (x - 1))); 941 | } 942 | ``` 943 | 944 | ###### **Count the number of ones in the binary representation of the given number** 945 | 946 | The basic approach to evaluate the binary form of a number is to traverse on it and count the number of ones. But this approach takes log2N of time in every case. 947 | 948 | Why log2N ? 949 | As to get a number in its binary form, we have to divide it by 2, until it gets 0, which will take log2N of time. 950 | 951 | With bitwise operations, we can use an algorithm whose running time depends on the number of ones present in the binary form of the given number. This algorithm is much better, as it will reach to logN, only in its worst case. 952 | ```cpp 953 | int count_one (int n) 954 | { 955 | while( n ) 956 | { 957 | n = n&(n-1); 958 | count++; 959 | } 960 | return count; 961 | } 962 | ``` 963 | Why does this algorithm work ? 964 | As explained in the previous algorithm, the relationship between the bits of x and x-1. So as in x-1, the rightmost 1 and bits right to it are flipped, then by performing x&(x-1), and storing it in x, will reduce x to a number containing number of ones(in its binary form) less than the previous state of x, thus increasing the value of count in each iteration. 965 | 966 | Example: 967 | n = 23 = {10111}2 . 968 | 1. Initially, count = 0. 969 | 2. Now, n will change to n&(n-1). As n-1 = 22 = {10110}2 , then n&(n-1) will be {10111}2 & {10110}2, which will be {10110}2 which is equal to 22. Therefore n will change to 22 and count to 1. 970 | 3. As n-1 = 21 = {10101}2 , then n&(n-1) will be {10110}2 & {10101}2, which will be {10100}2 which is equal to 20. Therefore n will change to 20 and count to 2. 971 | 4. As n-1 = 19 = {10011}2 , then n&(n-1) will be {10100}2 & {10011}2, which will be {10000}2 which is equal to 16. Therefore n will change to 16 and count to 3. 972 | 5. As n-1 = 15 = {01111}2 , then n&(n-1) will be {10000}2 & {01111}2, which will be {00000}2 which is equal to 0. Therefore n will change to 0 and count to 4. 973 | 6. As n = 0, the the loop will terminate and gives the result as 4. 974 | 975 | Complexity: O(K), where K is the number of one's present in the binary form of the given number. 976 | 977 | ###### **Check if the ith bit is set in the binary form of the given number** 978 | 979 | To check if the ith bit is set or not (1 or not), we can use AND operator. How? 980 | 981 | Let’s say we have a number N, and to check whether it’s ith bit is set or not, we can AND it with the number 2i. The binary form of 2i contains only ith bit as set (or 1), else every bit is 0 there. When we will AND it with N, and if the ith bit of N is set, then it will return a non zero number ( 2i to be specific), else 0 will be returned. 982 | 983 | Using Left shift operator, we can write 2i as 1 << i . Therefore: 984 | ```cpp 985 | bool check (int N) 986 | { 987 | if( N & (1 << i) ) 988 | return true; 989 | else 990 | return false; 991 | } 992 | ``` 993 | 994 | Example: 995 | Let’s say N = 20 = {10100}2.
Now let’s check if it’s 2nd bit is set or not(starting from 0).
For that, we have to AND it with 22 = 1 << 2 = {100}2.

996 | {10100}2 & {100}2 = {100}2 = 22 = 4(non-zero number), which means it’s 2nd bit is set. 997 | 998 | ###### **How to generate all the possible subsets of a set?** 999 | 1000 | A big advantage of bit manipulation is that it can help to iterate over all the subsets of an N-element set. As we all know there are **2N** possible subsets of any given set with N elements. What if we represent each element in a subset with a bit. A bit can be either 0 or 1, thus we can use this to denote whether the corresponding element belongs to this given subset or not. So each bit pattern will represent a subset. 1001 | 1002 | Consider a set A of 3 elements. 1003 | A = {a, b, c} 1004 | 1005 | Now, we need 3 bits, one bit for each element. 1 represent that the corresponding element is present in the subset, whereas 0 represent the corresponding element is not in the subset. Let’s write all the possible combination of these 3 bits. 1006 | 1007 | 0 = (000)2 = {}
1008 | 1 = (001)2 = {c}
1009 | 2 = (010)2 = {b}
1010 | 3 = (011)2 = {b, c}
1011 | 4 = (100)2 = {a}
1012 | 5 = (101)2 = {a, c}
1013 | 6 = (110)2 = {a, b}
1014 | 7 = (111)2 = {a, b, c}
1015 | 1016 | Pseudo Code: 1017 | ```python 1018 | possibleSubsets(A, N): 1019 | for i = 0 to 2^N: 1020 | for j = 0 to N: 1021 | if jth bit is set in i: 1022 | print(A[j]) 1023 | print("\n") 1024 | ``` 1025 | **Implementation:** 1026 | 1027 | ```cpp 1028 | void possibleSubsets(char A[], int N) 1029 | { 1030 | for(int i = 0;i < (1 << N); ++i) 1031 | { 1032 | for(int j = 0;j < N;++j) 1033 | if(i & (1 << j)) 1034 | cout << A[j] << ‘ ‘; 1035 | cout << endl; 1036 | } 1037 | } 1038 | ``` 1039 | 1040 | #### **Tricks with Bits:** 1041 | 1042 | ###### x ^ ( x & (x-1)) 1043 | Returns the rightmost 1 in binary representation of x. 1044 | 1045 | As explained above, (x & (x - 1)) will have all the bits equal to the x except for the rightmost 1 in x. So if we do bitwise XOR of x and (x & (x-1)), it will simply return the rightmost 1. Let’s see an example. 1046 | 1047 | x = 10 = (1010)2
1048 | x & (x-1) = (1010)2 & (1001)2 = (1000)2
1049 | x ^ (x & (x-1)) = (1010)2 ^ (1000)2 = (0010)2
1050 | 1051 | ###### x & (-x) 1052 | 1053 | Returns the rightmost 1 in binary representation of x 1054 | 1055 | (-x) is the two’s complement of x. (-x) will be equal to one’s complement of x plus 1. 1056 | Therefore (-x) will have all the bits flipped that are on the left of the rightmost 1 in x. So x & (-x) will return rightmost 1. 1057 | 1058 | x = 10 = (1010)2 1059 | (-x) = -10 = (0110)2 1060 | x & (-x) = (1010)2 & (0110)2 = (0010)2 1061 | 1062 | ###### x | (1 << n) 1063 | 1064 | Returns the number x with the nth bit set. 1065 | 1066 | (1 << n) will return a number with only nth bit set. So if we OR it with x it will set the nth bit of x.
1067 | x = 10 = (1010)2
1068 | n = 2
1069 | 1 << n = (0100)2
1070 | x | (1 << n) = (1010)2 | (0100)2 = (1110)2
1071 | 1072 | #### Applications of bit operations 1073 | 1074 | 1) They are widely used in areas of graphics, especially **XOR(Exclusive OR)** operations. 1075 | 2) They are widely used in the embedded systems, in situations, where we need to set/clear/toggle just one single bit of a specific register without modifying the other contents. We can do OR/AND/XOR operations with the appropriate mask for the bit position. 1076 | 3) Data structure like n-bit map can be used to allocate n-size resource pool to represent the current status. 1077 | 4) Bits are used in networking, framing the packets of numerous bits which is sent to another system generally through any type of serial interface. 1078 | 1079 | #### Links 1080 | 1081 | 1) Creative use of Bitwise operators - [Link Here!](https://snook.ca/archives/javascript/creative-use-bitwise-operators) 1082 | 1083 | ### 7.4. Primality and Sieve of Eratosthenes 1084 | 1085 | This is one of the most important concepts that you'll encounter in the world of competitive programming. 1086 | 1087 | > A number is said to be prime if it's divisible only by 1 and itself. 1088 | 1089 | For example, 2,3 and 5 are some prime numbers. 1090 | We'll now look into ways to determine whether a number is prime or not. 1091 | 1092 | One of the most naive algorithms to find out if a number n is prime or not would be to run a loop from 2 to n-1, checking if any number divides the number. If any number does divide n, it's a composite number. Else it's a prime. A simple implementation in C++ would be, 1093 | 1094 | ```cpp 1095 | bool isPrime(int x) 1096 | { 1097 | for(int i=2;i a*b = n 1128 | 1129 | We can prove by contradiction that one of them will be lesser than sqrt(n). 1130 | Using this theorem, we can reduce the loop even further to check until sqrt(n) for any possible divisors. The implementation would be, 1131 | 1132 | ```cpp 1133 | bool isPrime(int x) 1134 | { 1135 | for(int i=0;i*i<=x;i++) 1136 | { 1137 | if(x%i == 0) 1138 | return false; 1139 | } 1140 | return true; 1141 | } 1142 | ``` 1143 | 1144 | Notice that in this implementation, we hit only half the number of proper divisors. 1145 | There are many more algorithms for primality test like Fermat's little theorem, Miller-Rabin test, Solovay-Strassen. But we will not look into these just yet. 1146 | 1147 | #### The Sieve 1148 | 1149 | In mathematics, the **Sieve of Eratosthenes** is a very simple algorithm of finding all prime numbers up to a given limit. 1150 | 1151 | In this algorithm, we start from the number 2 and keep marking the composites which are the multiples of a prime. For example, if we were trying to find the primes below 11. Let the flag array be initialized to zero. The flag array signifies the compositeness of each number. It is set to 1 if it is a composite number, otherwise zero. 1152 | 1153 | | Iteration | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Discovering | 1154 | |:---------:|---|---|---|---|---|---|---|---|---|---|----|-------------| 1155 | | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 2 | 1156 | | 2 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 3 | 1157 | | 3 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 4 | 1158 | | 4 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 5 | 1159 | | 5 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 6 | 1160 | | 6 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 7 | 1161 | | 7 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 8 | 1162 | | 8 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 9 | 1163 | | 9 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 10 | 1164 | 1165 | 1166 | As you can notice that after iteration 1, all numbers which are the multiples of 2 have been set to 1, implying that they are composite numbers. When we move to iteration 2, all multiples of 3 have been marked composite. Notice that we do not change the mark of 2 and 3, since they weren't multiples of any smaller number, thus implying that they are primes. Once all the numbers have been visited once, we loop through the flag array and filter out the numbers with flag value set to 0. This gives us all the primes in the range. For example, in this case, the primes are, 1167 | 1168 | 2 3 5 7 1169 | 1170 | The following animation shows the marking for finding the primes within 121. 1171 | 1172 | ![](https://upload.wikimedia.org/wikipedia/commons/b/b9/Sieve_of_Eratosthenes_animation.gif) 1173 | 1174 | Let's look into a simple implementation of the sieve in C++. 1175 | ```cpp 1176 | //Finding all primes within the range [1,n) 1177 | void sieve(int n) 1178 | { 1179 | vector flag(n,0); 1180 | flag[0] = flag[1] = 1; //Setting 0 and 1 as composites. 1181 | //Finding the primes. 1182 | for(int i=2;iModular Arithmetic 1201 | 1202 | Modular Arithmetic is another important concept in the field of computer 1203 | science. For example, we use modular arithmetic to manage the problem of 1204 | overflow in data types. To fully understand modular arithmetic, we'll define a 1205 | relation on the set of integers that is compatible with operations addition, 1206 | subtraction and multiplication. The relation can be defined as, 1207 | 1208 | ``` 1209 | a ≡ b (mod n) 1210 | ``` 1211 | 1212 | The number n is defined as the modulus of congruence. The congruence relation 1213 | can be written as, 1214 | 1215 | ``` 1216 | a = kn+ b, 1217 | ``` 1218 | 1219 | b need not be the remainder of the division of a by n. More precisely, what the 1220 | above statement asserts is that a and b have the same remainder when divide by 1221 | n. That is, 1222 | 1223 | ``` 1224 | a = pn + r, 1225 | 1226 | b = qn + r, 1227 | ``` 1228 | 1229 | Subtracting both the equations, 1230 | 1231 | ``` 1232 | a - b = kn 1233 | ``` 1234 | 1235 | For example, 1236 | 1237 | ``` 1238 | 38 ≡ 14 (mod 12) 1239 | 1240 | ``` 1241 | 1242 | This asserts that both 38 and 14 give us the same remainder when divided by 12. 1243 | Now that we have defined what the relation is, let's define some of the 1244 | important properties of this relation. 1245 | 1246 | - Reflexivity : In mathematics, a binary relation R over a set X is reflexive 1247 | if it relates every element of X to itself. Formally, this may be written ∀x 1248 | ∈ X : x R x, or as I ⊆ R where I is the identity relation on X. 1249 | - Symmetry : An example is the relation "is equal to", because if a = b is 1250 | true then b = a is also true. Formally, a binary relation R over a set X is 1251 | symmetric if and only if: 1252 | ``` 1253 | ∀a, b ∈ X(aRb ⟺ bRa) 1254 | ``` 1255 | 1256 | * Transitivity : a relation between three elements such that if it holds 1257 | between the first and second and it also holds between the second and third 1258 | it must necessarily hold between the first and third 1259 | 1260 | Some properties to note : 1261 | 1262 | 1. if a+b = c, then a (mod N) +b (mod N) ≡ c (mod N) 1263 | 2. if a ≡ b (mod N), then a + k (mod N) = b + k (mod N) for any integer k. 1264 | 3. if a = b (mod N) and c = d (mod N), then a + c ≡ b + d (mod N) 1265 | 4. if a ≡ b (mod N), then -a ≡ -b (mod N) 1266 | 5. [Modular Exponentiation](https://www.geeksforgeeks.org/modular-exponentiation-power-in-modular-arithmetic/) 1267 | , you may find the derivation 1268 | [here](https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/fast-modular-exponentiation). 1269 | 1270 | ### Modular Inverse 1271 | 1272 | What is a modular inverse? 1273 | 1274 | In modular arithmetic we do not have a division operation. However, we do have 1275 | modular inverses. 1276 | 1277 | - The modular inverse of A (mod C) is A^-1 1278 | - (A _ A^-1) ≡ 1 (mod C) or equivalently (A _ A^-1) mod C = 1 1279 | - Only the numbers coprime to C (numbers that share no prime factors with C) 1280 | have a modular inverse (mod C) 1281 | 1282 | How to find the modular inverse? 1283 | 1284 | ###### A naive method of finding a modular inverse for A (mod C) is: 1285 | 1286 | step 1. Calculate A \* B mod C for B values 0 through C-1 1287 | 1288 | step 2. The modular inverse of A mod C is the B value that makes A \* B mod C = 1289 | 1 1290 | 1291 | Note that the term B mod C can only have an integer value 0 through C-1, so 1292 | testing larger values for B is redundant. 1293 | 1294 | Check out the implementation 1295 | [here](https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/) 1296 | 1297 | ###### A better method would be to use Fermat's little theorem 1298 | 1299 | Fermat’s little theorem states that if p is a prime number, then for any integer 1300 | a, the number a^p – a is an integer multiple of p. 1301 | 1302 | We can use this theorem to calculate the modular inverse, 1303 | 1304 | a^(m-1) ≡ 1 (mod m) 1305 | 1306 | If we multiply both sides with a^(-1), we get 1307 | 1308 | a^(-1) ≡ a^(m-2) (mod m) 1309 | 1310 | Check out the implementation 1311 | [here](https://www.geeksforgeeks.org/fermats-little-theorem/) 1312 | 1313 | ## 9. Ad Hoc Problems 1314 | 1315 | Competitive programming problems are generally divided into a number categories, 1316 | each requiring a different skill set, algorithm, or data structure to solve. One 1317 | subdivision of programming problem topics contains problems for which there 1318 | exists no general technique or algorithm, i.e. no well-studied solution. These 1319 | are known as ad-hoc problems. 1320 | 1321 | Each ad-hoc problem is unique, and requires a specialized approach. Some 1322 | competitive programmers consider ad-hoc problems to be the easiest type of 1323 | problem. In reality, ad-hoc problems can be easy or hard! For beginners just 1324 | starting to code competitively, it may be useful to practice lots of these 1325 | problems. 1326 | 1327 | Here is a good source of ad-hoc problems to practice 1328 | with:[Codechef](codechef.com/tags/problems/ad-hoc). For each problem, first try 1329 | to "pseudocode" (planning your solution on paper in non-code words) and solve 1330 | independently. If you find yourself stuck on a problem for longer than several 1331 | hours, it may be helpful to consult the solution in order to thoroughly 1332 | understand the general approach and then code it. 1333 | 1334 | ## 10. Kadane's algorithm and prefix sum 1335 | 1336 | A really common problem encountered in competitive programming can be solved 1337 | using the concept of 1338 | [prefix sum](https://www.geeksforgeeks.org/prefix-sum-array-implementation-applications-competitive-programming/). 1339 | Given an array arr[] of size n, its prefix sum array is another array 1340 | prefixSum[] of same size such that the value of prefixSum[i] is arr[0] + 1341 | arr[1] + arr[2] … arr[i]. 1342 | 1343 | ``` 1344 | arr[] = {10, 20, 10, 5, 15} 1345 | prefixSum[] = {10, 30, 40, 45, 60} 1346 | ``` 1347 | 1348 | This could be used to find the sum of all elements in the range [i,j] ,where 1349 | i<=j using a[j] - a[i-1] thus reducing the time complexity to O(1), whereas if 1350 | you traverse the range [i,j] everytime to find the sum that would be a linear 1351 | complexity. 1352 | 1353 | Another important algorithm is Kadane's algorithm. Now this algorithm is 1354 | considered a DP algorithm but it's pretty easy to understand and is very handy 1355 | when solving problems. This is used to find the Largest Sum Contiguous Subarray 1356 | in a given array. 1357 | 1358 | You can check out the code 1359 | [here](https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/) 1360 | 1361 | ## Further Reading 1362 | 1363 | That brings to the conclusion of this tutorial. We hope you were able to learn all the topics. There is a lot more to be discovered. We are providing you with some links for further reading. And remember, practice is the most important part of Competitive Programming. 1364 | 1365 | 1) [Stacks](https://www.hackerearth.com/practice/data-structures/stacks/basics-of-stacks/tutorial/) 1366 | 2) [Queues](https://www.hackerearth.com/practice/data-structures/queues/basics-of-queues/tutorial/) 1367 | 3) [Graphs](https://www.hackerearth.com/practice/algorithms/graphs/graph-representation/tutorial/) 1368 | 4) [Greedy Algorithms](https://www.hackerearth.com/practice/algorithms/greedy/basics-of-greedy-algorithms/tutorial/) 1369 | 5) [Dynamic Programming](https://www.hackerearth.com/practice/algorithms/dynamic-programming/introduction-to-dynamic-programming-1/tutorial/) 1370 | --------------------------------------------------------------------------------