Repository: MathProgrammer/CodeForces Branch: master Commit: e3483c1ac4a7 Files: 2576 Total size: 3.0 MB Directory structure: gitextract_wq208o93/ ├── 2020/ │ ├── Combined Divisions/ │ │ ├── 621 Div 1 + 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Cow and Fields Explanation.txt │ │ │ │ ├── Cow and Friend Explanation.txt │ │ │ │ ├── Cow and Haybales Explanation.txt │ │ │ │ ├── Cow and Message Explanation.txt │ │ │ │ └── Cows and Treats Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Cow and Fields.cpp │ │ │ ├── Cow and Haybales.cpp │ │ │ ├── Cow and Message.cpp │ │ │ └── Cows and Treats.cpp │ │ ├── CodeForces Global Round 7/ │ │ │ ├── Explanations/ │ │ │ │ ├── Bad Ugly Numbers Explanation.txt │ │ │ │ ├── Maximums Explanation.txt │ │ │ │ ├── Permutation Partitions Explanation.txt │ │ │ │ └── Prefix Suffix Palindrome (Easy Version) Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Bad Ugly Numbers.cpp │ │ │ ├── Maximums.cpp │ │ │ ├── Permutation Partitions.cpp │ │ │ └── Prefix Suffix Palindrome (Easy Version).cpp │ │ └── Ozone Tech Challenge 2020/ │ │ ├── Explanations/ │ │ │ ├── Kuroni and Impossible Calculation Explanation.txt │ │ │ ├── Kuroni and Punishment Explanation.txt │ │ │ ├── Kuroni and Simple Strings Explanation.txt │ │ │ ├── Kuroni and the Celebration Explanation.txt │ │ │ └── Kuroni and the Gifts Explanation.txt │ │ └── Programs/ │ │ ├── Kuroni and Impossible Calculation.cpp │ │ ├── Kuroni and Punishment.cpp │ │ ├── Kuroni and Simple Strings.cpp │ │ ├── Kuroni and the Celebration.cpp │ │ └── Kuroni and the Gifts.cpp │ ├── Div 2/ │ │ ├── 606 Div 2 Technocup 2020 Elimination Round 4/ │ │ │ ├── Explanations/ │ │ │ │ ├── As Simple as One and Two Explanation.txt │ │ │ │ ├── Happy Birthday Polycarp Explanation.txt │ │ │ │ └── Make Them Odd Explanation.txt │ │ │ └── Programs/ │ │ │ ├── As Simple as One and Two.cpp │ │ │ ├── Happy Birthday Polycarp.cpp │ │ │ └── Make Them Odd.cpp │ │ ├── 609 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Domino for Young Explanation.txt │ │ │ │ ├── Equation Explanation.txt │ │ │ │ ├── Long Beautiful Integer Explanation.txt │ │ │ │ └── Modulo Equality Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Domino for Young.cpp │ │ │ ├── Equation.cpp │ │ │ ├── Long Beautiful Integer.cpp │ │ │ └── Modulo Equality.cpp │ │ ├── 612 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Angry Students Explanation.txt │ │ │ │ ├── Hyperset Explanation.txt │ │ │ │ └── Madhouse (Easy Version) Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Angry Students.cpp │ │ │ ├── Hyperset.cpp │ │ │ └── Madhouse (Easy Version).cpp │ │ ├── 613 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Dr Evil Underscores Explanation.txt │ │ │ │ ├── Fadi and LCM Explanation.txt │ │ │ │ ├── Just Eat It Explanation.txt │ │ │ │ └── Mezo Playing Zoma Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Dr Evil Underscores.cpp │ │ │ ├── Fadi and LCM.cpp │ │ │ ├── Just Eat It.cpp │ │ │ └── Mezo Playing Zoma.cpp │ │ ├── 616 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Array Sharpening Explanation.txt │ │ │ │ ├── Even But Not Even Explanation.txt │ │ │ │ └── Mind Control Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Array Sharpening.cpp │ │ │ ├── Even But Not Even.cpp │ │ │ └── Mind Control.cpp │ │ ├── 618 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ └── Anu has a Function Explanation.txt │ │ │ └── Programs/ │ │ │ └── Anu has a Function.cpp │ │ ├── 619 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Ayoub's Function Explanation.txt │ │ │ │ ├── Motarack's Birthday Explanation.txt │ │ │ │ ├── Three Strings Explanation.txt │ │ │ │ └── Time to Run Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Ayoub's Function.cpp │ │ │ ├── Motarack's Birthday.cpp │ │ │ ├── Three Strings.cpp │ │ │ └── Time to Run.cpp │ │ ├── 620 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── 1-Trees and Queries Explanation.txt │ │ │ │ ├── Air Conditioner Explanation.txt │ │ │ │ ├── Longest Palindrome Explanation.txt │ │ │ │ ├── Shortest and Longest LIS Explanation.txt │ │ │ │ └── Two Rabbits Explanation.txt │ │ │ └── Programs/ │ │ │ ├── 1-Trees and Queries.cpp │ │ │ ├── Air Conditioner.cpp │ │ │ ├── Longest Palindrome.cpp │ │ │ ├── Shortest and Longest LIS.cpp │ │ │ └── Two Rabbits.cpp │ │ ├── 622 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Fast Food Restaurant Explanation.txt │ │ │ │ ├── Sky Scrapers (Hard Version) Explanation.txt │ │ │ │ └── Skyscrapers (Easy Version) Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Fast Food Restaurants.cpp │ │ │ ├── Skyscrapers (Easy Version).cpp │ │ │ └── Skyscrapers (Hard Version).cpp │ │ ├── 623 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Dead Pixel Explanation.txt │ │ │ │ ├── Homecoming Explanation.txt │ │ │ │ ├── Recommendations Explanation.txt │ │ │ │ └── Restoring Permutation Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Dead Pixel.cpp │ │ │ ├── Homecoming.cpp │ │ │ ├── Recommendations.cpp │ │ │ └── Restoring Permutations.cpp │ │ ├── 625 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Contest for Robots Explanation.txt │ │ │ │ ├── Journey Planning Explanation.txt │ │ │ │ ├── Navigation System Explanation.txt │ │ │ │ └── Remove Adjacent Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Contest for Robotos.cpp │ │ │ ├── Journey Planning.cpp │ │ │ ├── Navigation System.cpp │ │ │ └── Remove Adjacent.cpp │ │ ├── 626 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Count Subrectangles Explanation.txt │ │ │ │ ├── Even Subset Sum Problem Explanation.txt │ │ │ │ └── Unusual Competitions Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Counting Subrectangles.cpp │ │ │ ├── Even Subset Sum Problem.cpp │ │ │ └── Unusual Competitions.cpp │ │ ├── 628 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Copy Copy Copy Copy Copy Explanation.txt │ │ │ │ ├── Ehab and GCD Explanation.txt │ │ │ │ ├── Ehab and Path-etic MEX Explanation.txt │ │ │ │ └── Ehab and XORcist Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Copy Copy Copy Copy Copy.cpp │ │ │ ├── Ehab and GCD.cpp │ │ │ ├── Ehab and Pathetic MEX.cpp │ │ │ └── Ehab and XORcist.cpp │ │ ├── 630 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Composite Coloring Explanation.txt │ │ │ │ ├── Exercising Walk Explanation.txt │ │ │ │ ├── Height All The Same Explanation.txt │ │ │ │ ├── K Complete Word Explanation.txt │ │ │ │ └── Walk on Matrix Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Composite Coloring.cpp │ │ │ ├── Exercising Walk.cpp │ │ │ ├── Height All the Same.cpp │ │ │ ├── K Complete Word.cpp │ │ │ └── Walk on Matrix.cpp │ │ ├── 631 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Dreamoon Likes Coloring Explanation.txt │ │ │ │ ├── Dreamoon Likes Permutations Explanation.txt │ │ │ │ ├── Dreamoon Likes Sequences Explanation.txt │ │ │ │ └── Dreamoon and Ranking Collection Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Dreamoon Likes Coloring.cpp │ │ │ ├── Dreamoon Likes Permutations.cpp │ │ │ ├── Dreamoon Likes Sequences.cpp │ │ │ └── Dreamoon and Ranking Collection.cpp │ │ ├── 632 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Eugene and Array Explanation.txt │ │ │ │ ├── Kate and Imperfection Explanation.txt │ │ │ │ ├── Kind Anton Explanation.txt │ │ │ │ └── Little Artem Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Eugene and Array.cpp │ │ │ ├── Kate and Imperfection.cpp │ │ │ ├── Kind Anton.cpp │ │ │ └── Little Artem.cpp │ │ ├── 633 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Filling Diamonds Explanation.txt │ │ │ │ ├── Powered Addition Explanation.txt │ │ │ │ └── Sorted Adjacent Differences Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Filling Diamonds.cpp │ │ │ ├── Powered Addition.cpp │ │ │ └── Sorted Adjacent Differences.cpp │ │ ├── 635 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Ichime and Triangle Explanation.txt │ │ │ │ ├── Kana and Dragon Quest Game Explanation.txt │ │ │ │ ├── Linova and Kingdom Explanation.txt │ │ │ │ └── Xenia and Colourful Gems Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Ichihime and Triangle.cpp │ │ │ ├── Kana and Dragon Quest game.cpp │ │ │ ├── Linova and Kingdom.cpp │ │ │ └── Xenia and Colourful Gems.cpp │ │ ├── 637 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Nastya and Door Explanation.txt │ │ │ │ ├── Nastya and Rice Explanation.txt │ │ │ │ ├── Nastya and Scoreboard Explanation.txt │ │ │ │ └── Nastya and Strange Generator Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Nastya and Door.cpp │ │ │ ├── Nastya and Rice.cpp │ │ │ ├── Nastya and Scoreboard.cpp │ │ │ └── Nastya and Strange Generator.cpp │ │ ├── 638 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ └── Pheonix and Balance Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Pheonix and Balance.cpp │ │ │ └── Phoenix and Balance.cpp │ │ ├── 639 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Card Construction Explanation.txt │ │ │ │ ├── Hilbert Hotel Explanation.txt │ │ │ │ ├── Monopole Magnets Explanation.txt │ │ │ │ ├── Puzzle Pieces Explanation.txt │ │ │ │ ├── Quantifier Question Explanation.txt │ │ │ │ ├── Resume Review Explanation.txt │ │ │ │ └── Resume Review.cpp │ │ │ └── Programs/ │ │ │ ├── Card Construction.cpp │ │ │ ├── Hilbert Hotel.cpp │ │ │ ├── Monopole Magnets.cpp │ │ │ ├── Puzzle Pieces.cpp │ │ │ ├── Quantifier Question.cpp │ │ │ └── Resume Review.cpp │ │ ├── 641 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Orac and Factors Explanation.txt │ │ │ │ ├── Orac and LCM Explanation.txt │ │ │ │ └── Orac and Models Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Orac and Factors.cpp │ │ │ ├── Orac and LCM.cpp │ │ │ └── Orac and Models.cpp │ │ ├── 643 Div 2/ │ │ │ ├── Explanation/ │ │ │ │ ├── Counting Triangles Explanation.txt.txt │ │ │ │ ├── Game with Array Explanation.txt │ │ │ │ ├── Restorer Distance Explanation.txt │ │ │ │ ├── Sequence with Digits Explanation.txt │ │ │ │ └── Young Explorer Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Counting Triangles.cpp │ │ │ ├── Game with Array.cpp │ │ │ ├── Restorer Distance.cpp │ │ │ ├── Sequence with Digits.cpp │ │ │ └── Young Explorer.cpp │ │ ├── 647 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Johnny and Ancient Computers Explanation.txt │ │ │ │ ├── Johnny and Another Rating Drop Explanation.txt │ │ │ │ ├── Johnny and Contribution Explanation.txt │ │ │ │ └── Johnny and His Hobbies Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Johnny and Ancient Computers.cpp │ │ │ ├── Johnny and Another Rating Drop.cpp │ │ │ ├── Johnny and Contribution.cpp │ │ │ └── Johnny and His Hobbies.cpp │ │ ├── 648 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Maximum Subsequence Value Explanation.txt │ │ │ │ ├── Secure Password Explanation.txt.txt │ │ │ │ └── Swaps Again Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Matrix Game.cpp │ │ │ ├── Maximum Subsequence Value.cpp │ │ │ ├── Rotation Matching.cpp │ │ │ ├── Secure Password.cpp │ │ │ ├── Swaps Again.cpp │ │ │ └── Trouble Sort.cpp │ │ ├── 651 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Binary Subsequence Rotation Explanation.txt │ │ │ │ ├── GCD Compression Explanation.txt │ │ │ │ ├── Maximum GCD Explanation.txt │ │ │ │ ├── Number Game Explanation.txt │ │ │ │ └── Odd Even Subsequence Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Binary Subsequence Rotation.cpp │ │ │ ├── GCD Compression.cpp │ │ │ ├── Maximum GCD.cpp │ │ │ ├── Number Game.cpp │ │ │ └── Odd-Even Subsequence.cpp │ │ ├── 658 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Common Subsequence Explanation.txt │ │ │ │ ├── Sequential Nim Explanation.txt │ │ │ │ └── Unmerge Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Common Subsequence.cpp │ │ │ ├── Sequential Nim.cpp │ │ │ └── Unmerge.cpp │ │ ├── 659 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Common Prefix Explanation.txt │ │ │ │ ├── Prefix Flip (Easy Version) Explanation.txt │ │ │ │ ├── Prefix Flip (Hard Version) Explanation.txt │ │ │ │ └── String Transformation 1 Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Common Prefixes.cpp │ │ │ ├── Prefix Flip (Easy Version).cpp │ │ │ ├── Prefix Flip (Hard Version).cpp │ │ │ └── String Transformation 1.cpp │ │ ├── 660 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Captain Flint and Crew Recruitment Explanation.txt │ │ │ │ └── Captain Flint and a Long Voyage Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Captain Flint and Crew Recruitment.cpp │ │ │ └── Captain Flint and a Long Voyage.cpp │ │ ├── 662 Div 2/ │ │ │ └── Programs/ │ │ │ └── Rainbow Dash, Fluttershy and Chess Coloring.cpp │ │ ├── 678 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Bandit in a City Explanation.txt │ │ │ │ ├── Binary Search Explanation.txt │ │ │ │ ├── Complicated Computations Explanation.txt │ │ │ │ ├── Prime Square Explanation.txt │ │ │ │ ├── Reorder Explanation.txt │ │ │ │ └── Sum Over Subsets Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Bandit in a City.cpp │ │ │ ├── Binary Search.cpp │ │ │ ├── Complicated Computations.cpp │ │ │ ├── Prime Square.cpp │ │ │ ├── Reorder.cpp │ │ │ └── Sum Over Subsets.cpp │ │ ├── 684 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Binary Table Explanation.txt │ │ │ │ ├── Buy the String Explanation.txt │ │ │ │ ├── Graph Subset Problem Explanation.txt │ │ │ │ ├── Greedy Shopping Explanation.txt │ │ │ │ └── Sum of Medians Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Binary Table.cpp │ │ │ ├── Buy the String.cpp │ │ │ ├── Graph Subset Problem.cpp │ │ │ ├── Greedy Shopping.cpp │ │ │ └── Sum of Medians.cpp │ │ ├── 685 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Bitwise Queries Explanation.txt │ │ │ │ ├── Circle Game Explanation.txt │ │ │ │ ├── Non Substring Subsequence Explanation.txt │ │ │ │ ├── Nullify the Matrix Explanation.txt │ │ │ │ ├── String Equality Explanation.txt │ │ │ │ └── Subtract or Divide Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Bitwise Queries (Hard Version).cpp │ │ │ ├── Bitwise Queries.cpp │ │ │ ├── Circle Game.cpp │ │ │ ├── Non-Substring Subsequence .cpp │ │ │ ├── Nullify the Matrix.cpp │ │ │ ├── String Equality.cpp │ │ │ └── Subtract or Divide .cpp │ │ ├── 687 Div 2 Technocup 2021 Elimination Round 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Bouncing Ball Explanation.txt │ │ │ │ ├── New Game Plus Explanation.txt │ │ │ │ ├── Prison Break Explanation.txt │ │ │ │ ├── Repainting Street Explanation.txt │ │ │ │ └── XOR Gun Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Bouncing Ball.cpp │ │ │ ├── New Game Plus.cpp │ │ │ ├── Prison Break.cpp │ │ │ ├── Repainting Street.cpp │ │ │ └── XOR Gun.cpp │ │ ├── 688 Div 2/ │ │ │ ├── Explanation/ │ │ │ │ └── Suffix Operations Explanation.txt │ │ │ └── Programs/ │ │ │ └── Suffix Operations.cpp │ │ ├── 689 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Divide and Summarize Explanation.txt │ │ │ │ ├── Find a Spruce Explanation.txt │ │ │ │ ├── Mathematical Expression Explanation.txt │ │ │ │ ├── Random Events Explanation.txt │ │ │ │ ├── String Generation Explanation.txt │ │ │ │ └── Water Level Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Divide and Summarize.cpp │ │ │ ├── Find the Spruce.cpp │ │ │ ├── Mathematical Expression.cpp │ │ │ ├── Random Events.cpp │ │ │ ├── String Generation.cpp │ │ │ └── Water Level.cpp │ │ ├── 691 Div 2/ │ │ │ ├── Explanation/ │ │ │ │ ├── Move and Turn Explanation.txt │ │ │ │ ├── Red Blue Shuffle Explanation.txt │ │ │ │ └── Row GCD Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Move and Turn.cpp │ │ │ ├── Red Blue Shuffle.cpp │ │ │ └── Row GCD.cpp │ │ ├── 692 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── Fair Numbers Explanation.txt │ │ │ │ └── In Game Chat Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Fair Numbers.cpp │ │ │ └── In Game Chat.cpp │ │ └── CodeCraft 2020/ │ │ ├── Explanations/ │ │ │ ├── Grade Allocation Explanation.txt │ │ │ ├── Nash Matrix Explanation.txt │ │ │ ├── Primitive Primes Explanation.txt │ │ │ ├── String Modification Explanation.txt │ │ │ └── Team Building Explanation.txt │ │ └── Programs/ │ │ ├── Grade Allocation.cpp │ │ ├── Nash Matrix.cpp │ │ ├── Primitive Primes.cpp │ │ ├── String Modification.cpp │ │ └── Team Building.cpp │ ├── Div 3/ │ │ ├── 605 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Nearly Opposite Parity.cpp │ │ │ │ └── Remove One Element Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Nearly Opposite Parity.cpp │ │ │ └── Remove One Element.cpp │ │ ├── 611 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Candies Division Explanation.txt │ │ │ │ ├── Christmas Trees Explanation.txt │ │ │ │ ├── DIY Garland Explanation.txt │ │ │ │ ├── Friends and Gifts Explanation.txt │ │ │ │ ├── Minutes Before the New Year Explanation.txt │ │ │ │ └── New Year Parties Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Candies Division.cpp │ │ │ ├── Christmas Trees.cpp │ │ │ ├── DIY Garland.cpp │ │ │ ├── Friends and Gifts.cpp │ │ │ ├── Minutes Before the New Year.cpp │ │ │ └── New Year Parties.cpp │ │ ├── 615 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Collecting Coins Explanation.txt │ │ │ │ ├── Collecting Packages Explanation.txt │ │ │ │ ├── MEX Maximising Explanation.txt │ │ │ │ ├── Obtain a Permutation Explanation.txt │ │ │ │ ├── Product of Three Numbers Explanation.txt │ │ │ │ └── Three Paths on a Tree Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Collecting Coins.cpp │ │ │ ├── Collecting Packages.cpp │ │ │ ├── MEX Maximising.cpp │ │ │ ├── Obtain a Permutation.cpp │ │ │ ├── Paths on a Tree.cpp │ │ │ └── Product of Three Numbers.cpp │ │ ├── 617 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Array with Odd Sum Explanation.txt │ │ │ │ ├── Fight with Monsters Explanation.txt │ │ │ │ ├── Food Buying Explanation.txt │ │ │ │ ├── String Colouring (Easy Version) Explanation.txt │ │ │ │ ├── String Colouring (Hard Version) Explanation.txt │ │ │ │ └── Yet Another Walking Robot Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Array with Odd Sum.cpp │ │ │ ├── Fight with Monsters.cpp │ │ │ ├── Food Buying.cpp │ │ │ ├── String Coloring (Hard Version).cpp │ │ │ ├── String Colouring (Easy Version).cpp │ │ │ └── Yet Another Walking Robot.cpp │ │ ├── 624 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Add Odd or Subtract Even Explanation.txt │ │ │ │ ├── Construct the Binary Tree Explanation.txt │ │ │ │ ├── Moving Points Explanation.txt │ │ │ │ ├── Perform the Combo Explanation.txt │ │ │ │ ├── Three Integers Explanation.txt │ │ │ │ └── WeirdSort Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Add Odd or Subtract Even.cpp │ │ │ ├── Construct the Binary Tree.cpp │ │ │ ├── Moving Points.cpp │ │ │ ├── Perform the Combo.cpp │ │ │ ├── Three Integers.cpp │ │ │ └── Weirdsort.cpp │ │ ├── 627 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Frog Jumps Explanation.txt │ │ │ │ ├── Maximum White Subtree Explanation.txt │ │ │ │ ├── Pair of Topics Explanation.txt │ │ │ │ ├── Sleeping Schedule Explanation.txt │ │ │ │ ├── Yet Another Palindrome Problem Explanation.txt │ │ │ │ └── Yet Another Tetris Problem Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Frog Jumps.cpp │ │ │ ├── Maximum White Subtree.cpp │ │ │ ├── Pair of Topics.cpp │ │ │ ├── Sleeping Schedule.cpp │ │ │ ├── Yet Another Palindrome Problem.cpp │ │ │ └── Yet Another Tetris Problem.cpp │ │ ├── 629 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Carousel Explanation.txt │ │ │ │ ├── Divisibility Problem Explanation.txt │ │ │ │ ├── Kth Beautiful String Explanation.txt │ │ │ │ ├── Ternary XOR Explanation.txt │ │ │ │ └── Tree Queries Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Carousel.cpp │ │ │ ├── Divisibility Problem.cpp │ │ │ ├── Kth Beautiful String.cpp │ │ │ ├── Ternary XOR.cpp │ │ │ └── Tree Queries.cpp │ │ ├── 634 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Anti Sudoku Explanation.txt │ │ │ │ ├── Candies and Two Sisters Explanation.txt │ │ │ │ ├── Construct the String Explanation.txt │ │ │ │ ├── Robots on a Grid Explanation.txt │ │ │ │ ├── Three Blocks Palindrome Explanation.txt │ │ │ │ └── Two Teams Composing Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Anti Sudoku.cpp │ │ │ ├── Candies and Two Sisters.cpp │ │ │ ├── Construct the String.cpp │ │ │ ├── Robots on a Grid.cpp │ │ │ ├── Three Blocks Palindrome.cpp │ │ │ └── Two Teams Composing.cpp │ │ ├── 636 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ └── Constant Palindrome Sum Explanation.txt │ │ │ └── Programs/ │ │ │ └── Constant Palindrome Sum.cpp │ │ ├── 661 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Binary String to Subsequence Explanation.txt │ │ │ │ ├── Boats Competition Explanation.txt │ │ │ │ ├── Gifts Fixing Explanation.txt │ │ │ │ └── Remove Smallest Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Binary String to Subsequences.cpp │ │ │ ├── Boats Competition.cpp │ │ │ ├── Gifts Fixing.cpp │ │ │ └── Remove Smallest.cpp │ │ ├── 674 Div 3/ │ │ │ └── Programs/ │ │ │ └── Number of Subsequences.cpp │ │ ├── 686 Div 3/ │ │ │ ├── Explanations/ │ │ │ │ ├── Array Partition Explanation.txt │ │ │ │ ├── Number Into Sequence Explanation.txt │ │ │ │ ├── Number of Simple Paths Explanation.txt │ │ │ │ ├── Sequence Transformation Explanation.txt │ │ │ │ ├── Special Permutation Explanation.txt │ │ │ │ └── Unique Bid Auction Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Array Partition.cpp │ │ │ ├── Number Into Sequence.cpp │ │ │ ├── Number of Simple Paths.cpp │ │ │ ├── Sequence Transformation.cpp │ │ │ ├── Special Permutation.cpp │ │ │ └── Unique Bid Auction.cpp │ │ └── Explanations/ │ │ └── Number of Subsequences Explanation.txt │ ├── Educational Rounds/ │ │ ├── Educational Round 78/ │ │ │ ├── Explanations/ │ │ │ │ ├── Berry Jam Explanation.txt │ │ │ │ ├── Cards Explanation.txt │ │ │ │ ├── Shuffle Hashing Explanation.txt │ │ │ │ └── Tests for Problem D Explanation.txt │ │ │ └── Programs/ │ │ │ ├── A and B.cpp │ │ │ ├── Berry Jam.cpp │ │ │ ├── Shuffle Hashing.cpp │ │ │ └── Tests for Problem D.cpp │ │ ├── Educational Round 79/ │ │ │ ├── Explanations/ │ │ │ │ ├── New Year Garland Explanation.txt │ │ │ │ ├── Stack of Presents Explanation.txt │ │ │ │ └── Verse for Santa Explanation.txt │ │ │ └── Programs/ │ │ │ ├── New Year Garland.cpp │ │ │ ├── Stack of Presents.cpp │ │ │ └── Verse for Santa.cpp │ │ ├── Educational Round 80/ │ │ │ ├── Explanations/ │ │ │ │ ├── Deadline Explanation.txt │ │ │ │ ├── Minimax Problem Explanation.txt │ │ │ │ ├── Two Arrays Alternate Solution Explanation.txt │ │ │ │ ├── Two Arrays Explanation.txt │ │ │ │ └── Yet Another Meme Problem Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Deadline.cpp │ │ │ ├── Minimax Problem.cpp │ │ │ ├── Two Arrays Alternate Solution.cpp │ │ │ ├── Two Arrays.cpp │ │ │ └── Yet Another Meme Problem.cpp │ │ ├── Educational Round 81/ │ │ │ ├── Explanation/ │ │ │ │ ├── Display the Number Explanation.txt │ │ │ │ ├── Infinite Prefixes Explanation.txt │ │ │ │ ├── Obtain the String Explanation.txt │ │ │ │ └── Same GCDs Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Display the Number.cpp │ │ │ ├── Infinite Prefixes.cpp │ │ │ ├── Obtain the String.cpp │ │ │ └── Same GCDs.cpp │ │ ├── Educational Round 82/ │ │ │ ├── Explanations/ │ │ │ │ ├── Erasing Zeroes Explanation.txt │ │ │ │ ├── National Project Explanation.txt │ │ │ │ └── Perfect Keyboard Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Erasing Zeroes.cpp │ │ │ ├── Fill the Bag.cpp │ │ │ ├── National Project.cpp │ │ │ └── Perfect Keyboard.cpp │ │ ├── Educational Round 83/ │ │ │ ├── Explanations/ │ │ │ │ ├── Adding Powers Explanation.txt │ │ │ │ ├── Array Shrinking Explanation.txt │ │ │ │ ├── Bogosort Explanation.txt │ │ │ │ ├── Count the Arrays Explanation.txt │ │ │ │ └── Two Regular Polygons Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Adding Powers.cpp │ │ │ ├── Array Shrinking.cpp │ │ │ ├── Bogosort.cpp │ │ │ ├── Count the Arrays.cpp │ │ │ └── Two Regular Polygons.cpp │ │ ├── Educational Round 84/ │ │ │ ├── Explanations/ │ │ │ │ ├── Count the Blocks Explanation.txt │ │ │ │ └── Sum of Odd Integers Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Count the Blocks.cpp │ │ │ └── Sum of Odd Integers.cpp │ │ ├── Educational Round 85/ │ │ │ ├── Explanations/ │ │ │ │ ├── Circle of Monsters Explanation.txt │ │ │ │ ├── Divisor Paths Explanation.txt │ │ │ │ ├── Level Statistics Explanation.txt │ │ │ │ ├── Middle Class Explanation.txt │ │ │ │ └── Minimum Euler Cycle Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Circle of Monsters.cpp │ │ │ ├── Divisor Paths.cpp │ │ │ ├── Level Statistics.cpp │ │ │ ├── Middle Class.cpp │ │ │ └── Minimum Euler Cycle.cpp │ │ ├── Educational Round 86/ │ │ │ ├── Explanations/ │ │ │ │ ├── Binary Period Explanation.txt │ │ │ │ ├── Road to Zero Explanation.txt │ │ │ │ └── Yet Another Counting Problem Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Binary Period.cpp │ │ │ ├── Road to Zero.cpp │ │ │ └── Yet Another Counting Problem.cpp │ │ ├── Educational Round 90/ │ │ │ ├── Explanations/ │ │ │ │ ├── 01 Game Explanation.txt │ │ │ │ ├── Donut Shops Explanation.txt │ │ │ │ ├── Maximum Sum on Even Positions Explanation.txt │ │ │ │ └── Pluses and Minuses Explanation.txt │ │ │ └── Programs/ │ │ │ ├── 01 Game.cpp │ │ │ ├── Donut Shops.cpp │ │ │ ├── Maximum Sum on Even Positions.cpp │ │ │ └── Pluses and Minuses.cpp │ │ ├── Educational Round 92/ │ │ │ ├── Explanations/ │ │ │ │ └── Good String Explanation.txt │ │ │ └── Programs/ │ │ │ └── Good String.cpp │ │ └── Educational Round 93/ │ │ ├── Explanations/ │ │ │ ├── Bad Triangle Explanation.txt │ │ │ ├── Colored Rectangles Explanation.txt │ │ │ ├── Good Subarrays Explanation.txt │ │ │ └── Substring Removal Game Explanation.txt │ │ └── Programs/ │ │ ├── Bad Triangle.cpp │ │ ├── Colored Rectangles.cpp │ │ ├── Good Subarrays.cpp │ │ └── Substring Removal Game.cpp │ ├── Good Bye 2019/ │ │ ├── Explanations/ │ │ │ ├── Card Game Explanation.txt │ │ │ ├── Interesting Subarray Explanation │ │ │ └── Make Good Explanation.txt │ │ └── Programs/ │ │ ├── Card Game.cpp │ │ ├── Interesting Subarray.cpp │ │ └── Make Good.cpp │ ├── Hello 2020/ │ │ ├── Explanations/ │ │ │ ├── New Year and Ascent Sequences Explanation.txt │ │ │ ├── New Year and Conferences Explanation.txt │ │ │ ├── New Year and Naming Explanation │ │ │ └── New Year and Permutation Explanation.txt │ │ └── Programs/ │ │ ├── New Year and Ascent Sequences.cpp │ │ ├── New Year and Conferences.cpp │ │ ├── New Year and Naming.cpp │ │ └── New Year and Permutation.cpp │ └── Practice/ │ ├── Explanations/ │ │ ├── Alternative Thinking Explanation.txt │ │ ├── Ant Colony Explanation.txt │ │ ├── Anton and Chess Explanation.txt │ │ ├── Anton and Ira Explanation.txt │ │ ├── Ants in Leaves Explanation.txt │ │ ├── Army Creation Explanation.txt │ │ ├── Bargain Explanation.txt │ │ ├── Concatenated Multiples Explanation.txt │ │ ├── Count Pairs Explanation.txt │ │ ├── Cram Time Explanation.txt │ │ ├── Cycles Explanation.txt │ │ ├── Elections Explanation.txt │ │ ├── Fight Against Traffic Explanation.txt │ │ ├── Hacker, Pack your Bags Explanation.txt │ │ ├── Imbalance Array Explanation.txt │ │ ├── Laboratory Work Explanation.txt │ │ ├── Lieges of Legendre Explanation.txt │ │ ├── Line Explanation.txt │ │ ├── Marina and Vyasa Explanation.txt │ │ ├── Match Points Explanation.txt │ │ ├── Molly and Chemicals Explanation.txt │ │ ├── Moodular Arithmetic Explanation.txt │ │ ├── Mouse Hunt Explanation.txt │ │ ├── Multiplicity Explanation.txt │ │ ├── Multipliers Explanation.txt │ │ ├── My Pretty Girl Nora Explanation.txt │ │ ├── Optimal Number Permutation Explanation.txt │ │ ├── Pair of Numbers Explanation.txt │ │ ├── Pashmak and Graph Explanation.txt │ │ ├── Pavel and Triangles Explanation.txt │ │ ├── Plus and XOR Explanation.txt │ │ ├── Points Explanation.txt │ │ ├── Prime Number Explanation.txt │ │ ├── Ramesses and Corner Inversion Explanation.txt │ │ ├── Scheme.cpp │ │ ├── Secret Passwords Explanation.txt │ │ ├── Segments Explanation.txt │ │ ├── Special Segments of Permutation Explanation.txt │ │ ├── The Sum of the k-th Powers Explanation.txt │ │ ├── The Treasure of Segments Explanation.txt │ │ └── Winter is Here Explanation.txt │ └── Programs/ │ ├── Alternative Thinking.cpp │ ├── Ant Colony.cpp │ ├── Anton and Chess.cpp │ ├── Anton and Ira.cpp │ ├── Ants in Leaves.cpp │ ├── Army Creation.cpp │ ├── Bargain.cpp │ ├── Concatenated Multiples.cpp │ ├── Count Pairs.cpp │ ├── Cram Time.cpp │ ├── Cycles.cpp │ ├── Elections.cpp │ ├── Fight Against Traffic.cpp │ ├── Hacker, pack your Bags.cpp │ ├── Imbalanced Array.cpp │ ├── Laboratory Work.cpp │ ├── Lieges of Legendre.cpp │ ├── Line.cpp │ ├── Marina and Vyasa.cpp │ ├── Match Points.cpp │ ├── Molly and Chemicals.cpp │ ├── Moodular Arithmetic.cpp │ ├── Mouse Hunt.cpp │ ├── Multiplicity.cpp │ ├── Multipliers.cpp │ ├── My Pretty Girl Nora.cpp │ ├── Optimal Number Permutation.cpp │ ├── Pair of Numbers.cpp │ ├── Pashmak and Graph.cpp │ ├── Pavel and Triangles.cpp │ ├── Plus and Xor.cpp │ ├── Points.cpp │ ├── Prime Number.cpp │ ├── Ramesses and Corner Inversion.cpp │ ├── Scheme.cpp │ ├── Secret Passwords.cpp │ ├── Segments.cpp │ ├── Special Segments of Permutation.cpp │ ├── The Sum of the k-th Powers.cpp │ ├── The Treasure of Segments.cpp │ └── Winter is Here.cpp ├── 2021/ │ ├── Combined Divisions/ │ │ └── Deltix Round Summer 2021/ │ │ ├── Explanations/ │ │ │ └── Take a Guess Explanation.txt │ │ └── Programs/ │ │ └── Take a Guess.cpp │ ├── Div 2/ │ │ ├── 694/ │ │ │ ├── Explanations/ │ │ │ │ ├── Strange Definition Explanation.txt │ │ │ │ ├── Strange Housing Explanation.txt │ │ │ │ └── Strange Shuffle Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Strange Birthday Party.cpp │ │ │ ├── Strange Definition.cpp │ │ │ ├── Strange Housing.cpp │ │ │ ├── Strange List.cpp │ │ │ ├── Strange Partition.cpp │ │ │ └── Strange Shuffle.cpp │ │ ├── 708/ │ │ │ ├── Explanations/ │ │ │ │ ├── Genius Explanation.txt │ │ │ │ ├── M Arrays Explanation.txt.txt │ │ │ │ ├── Meximization Explanation.txt.txt │ │ │ │ ├── Square Free Division Explanation.txt.txt │ │ │ │ └── k-LCM Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── Genius.cpp │ │ │ ├── M Arrays.cpp │ │ │ ├── Meximization.cpp │ │ │ ├── Square Free Division.cpp │ │ │ └── k-LCM.cpp │ │ ├── 711 CodeCraft 2021/ │ │ │ ├── Explanations/ │ │ │ │ ├── Bananas in a MIrcorwave Explanation.txt.txt │ │ │ │ ├── Box Fitting Explanation.txt │ │ │ │ ├── GCD Sum Explanation.txt.txt │ │ │ │ └── Two Houses Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── Bananas in a Microwave.cpp │ │ │ ├── Box Fitting.cpp │ │ │ ├── GCD Sum.cpp │ │ │ └── Two Houses.cpp │ │ ├── 712 Div 2/ │ │ │ ├── Explanations/ │ │ │ │ ├── 3 Colouring Explanation.txt │ │ │ │ ├── Deja Vu Explanation.txt.txt │ │ │ │ └── Flip the Bits Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── 3 Colouring.cpp │ │ │ ├── Déjà Vu.cpp │ │ │ └── Flip the Bits.cpp │ │ ├── 714 Division by Zero 2021/ │ │ │ ├── Explanations/ │ │ │ │ ├── AND Sequences Explanation.txt.txt │ │ │ │ ├── Add One Explanation.txt.txt │ │ │ │ ├── Arrays and Peaks Explanation.txt.txt │ │ │ │ ├── Cost Equilibrium Explanation.txt.txt │ │ │ │ ├── GCD and MST Explanation.txt │ │ │ │ ├── GCD and MST Explanation.txt.txt │ │ │ │ └── Swapping Problem Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── AND Sequences.cpp │ │ │ ├── Add One.cpp │ │ │ ├── Arrays and Peaks.cpp │ │ │ ├── Cost Equilibrium.cpp │ │ │ ├── GCD and MST.cpp │ │ │ └── Swapping Problem.cpp │ │ ├── 716 Div 2/ │ │ │ └── Programs/ │ │ │ └── Product 1 mod N.cpp │ │ ├── 722/ │ │ │ ├── Explanations/ │ │ │ │ └── Parsa and Humungous Tree Explanation.txt │ │ │ └── Programs/ │ │ │ └── Parsa and Humungous Tree.cpp │ │ ├── 724/ │ │ │ ├── Diluc and Kaeye Explanation.txt │ │ │ ├── Explanations/ │ │ │ │ └── Diluc and Kaeye Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Diluc and Kaeya.cpp │ │ │ ├── Omkar and Bad Story.cpp │ │ │ ├── Omkar and Forest.cpp │ │ │ └── Prinzessin der Verurteilung.cpp │ │ ├── 726/ │ │ │ ├── Explanations/ │ │ │ │ ├── Arithemtic Array Explanation.txt.txt │ │ │ │ ├── Bad Boy Explanation.txt.txt │ │ │ │ ├── Challenging Cliffs Explanation.txt.txt │ │ │ │ ├── Deleting Divisors Explanation.txt.txt │ │ │ │ └── Erase and Extend (Easy Version) Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Arithmetic Array.cpp │ │ │ ├── Bad Boy.cpp │ │ │ ├── Challenging Cliffs.cpp │ │ │ ├── Deleting Divisors.cpp │ │ │ ├── Erase and Extend (Easy Version).cpp │ │ │ └── Figure Fixing.cpp │ │ ├── 727/ │ │ │ ├── Explanations/ │ │ │ │ ├── Constest Start Time Explanation.txt │ │ │ │ ├── Love Song Explanation.txt.txt │ │ │ │ ├── Price Fixed Explanation.txt.txt │ │ │ │ └── Stable Groups Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── Contest Start.cpp │ │ │ ├── Love Song.cpp │ │ │ ├── PriceFixed.cpp │ │ │ └── Stable Groups.cpp │ │ ├── 740/ │ │ │ └── Programs/ │ │ │ ├── Deep Down Below Binary Search.cpp │ │ │ └── Deep Down Below.cpp │ │ ├── 742/ │ │ │ ├── Explanations/ │ │ │ │ └── Carrying Conundrum Explanation.txt │ │ │ └── Programs/ │ │ │ └── Carrying Conundrum.cpp │ │ └── 750/ │ │ ├── Explanations/ │ │ │ └── Pchelyonok and Segments Explanation.txt │ │ └── Programs/ │ │ └── Pchelyonok and Segments.cpp │ ├── Div 3/ │ │ ├── 710/ │ │ │ ├── Explanations/ │ │ │ │ ├── Double Ended Strings Explanation.txt.txt │ │ │ │ ├── Epic Transformation Explanation.txt.txt │ │ │ │ ├── Maximize the Remaining String Explanation.txt │ │ │ │ ├── Partial Replacement.txt.txt │ │ │ │ ├── Strange Table Explanation.txt.txt │ │ │ │ └── Triangular Paths Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── Double Ended Strings.cpp │ │ │ ├── Epic Transformation.cpp │ │ │ ├── Maximize the Remaining String.cpp │ │ │ ├── Partial Replacement.cpp │ │ │ ├── Strange Table.cpp │ │ │ └── Triangular Paths.cpp │ │ ├── 713/ │ │ │ ├── Explanations/ │ │ │ │ ├── A-B Palindrome Explanation.txt.txt │ │ │ │ ├── Almost Rectange Explanation.txt.txt │ │ │ │ ├── Corrupted Array Explanation.txt.txt │ │ │ │ ├── Education Explanation.txt.txt │ │ │ │ ├── Short Task Explanation.txt │ │ │ │ └── Spy Detected Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── A-B Palindrome.cpp │ │ │ ├── Almost Rectangle.cpp │ │ │ ├── Corrupted Array.cpp │ │ │ ├── Education.cpp │ │ │ ├── Short Task.cpp │ │ │ └── Spy Detected.cpp │ │ └── 744/ │ │ └── Programs/ │ │ └── Array Optimization by Deque.cpp │ ├── Educational Round 109/ │ │ ├── Explanations/ │ │ │ └── Permutation Sort Explanation.txt │ │ └── Programs/ │ │ └── Permutation Sort.cpp │ └── Practice/ │ ├── Explanations/ │ │ ├── Anton and Making Potions Explanation.txt │ │ ├── Anton and Tree Explanation.txt.txt │ │ ├── Counter Attack Explanation.txt.txt │ │ ├── Game of Stones Explanation.txt.txt │ │ ├── Lost Tree Explanation.txt.txt │ │ └── Maximum Absurdity Explanation.txt.txt │ └── Programs/ │ ├── Anton and Making Potions.cpp │ ├── Anton and Tree.cpp │ ├── Counter Attack.cpp │ ├── Game of Stones.cpp │ ├── Lost Tree.cpp │ └── Maximum Absurdity.cpp ├── 2022/ │ └── Contests/ │ ├── Combined Divisions/ │ │ └── CodeTON/ │ │ ├── Explanations/ │ │ │ ├── Good Pairs Explanation.txt.txt │ │ │ ├── Make Equal with Mod Explanation.txt.txt │ │ │ └── Subtract Operations Explanation.txt │ │ └── Programs/ │ │ ├── Good Pairs.cpp │ │ ├── K-good.cpp │ │ ├── Make Equal With Mod.cpp │ │ └── Subtract Operation.cpp │ ├── Div 2/ │ │ ├── 766/ │ │ │ └── Programs/ │ │ │ ├── Not Adding.cpp │ │ │ ├── Not Assigning.cpp │ │ │ ├── Not Shading.cpp │ │ │ └── Not Sitting.cpp │ │ ├── 767/ │ │ │ ├── Explanations/ │ │ │ │ └── Meximum Array Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Download More RAM.cpp │ │ │ ├── GCD Arrays.cpp │ │ │ ├── Game On Sum Easy Version.cpp │ │ │ ├── Game on Sum Hard Version.cpp │ │ │ ├── Grid XOR.cpp │ │ │ ├── Meximum Array.cpp │ │ │ └── Peculiar Movie Preferences.cpp │ │ ├── 777/ │ │ │ └── Programs/ │ │ │ ├── Madoka and Math Dad.cpp │ │ │ └── Makoda and Childish Pranks.cpp │ │ ├── 778/ │ │ │ ├── Explanations/ │ │ │ │ ├── Alice and the Cake Explanation.txt.txt │ │ │ │ ├── Maximum Cake Tastiness Explanation.txt │ │ │ │ └── Prefix Removals Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── Alice and the Cake.cpp │ │ │ ├── Maximum Cake Tastiness.cpp │ │ │ └── Prefix Removals.cpp │ │ ├── 789/ │ │ │ ├── Explanation/ │ │ │ │ ├── Tokitsukaze and All Zero Sequence Explanation.txt.txt │ │ │ │ ├── Tokitsukaze and Good 01-String (easy version) Explanation.txt.txt │ │ │ │ └── Tokitsukaze and Strange Inequality Explanation.txt │ │ │ └── Programs/ │ │ │ ├── Tokitsukaze and Good 01-String (easy version).cpp │ │ │ └── Tokitsukaze and Strange Inequality.cpp │ │ ├── 792/ │ │ │ ├── Explanations/ │ │ │ │ ├── AvtoBus Explanation.txt │ │ │ │ ├── Rooks Defenders Explanation.txt.txt │ │ │ │ └── Stone Age Problem Explanation.txt.txt │ │ │ └── Programs/ │ │ │ ├── AvtoBus.cpp │ │ │ ├── Rooks Defenders.cpp │ │ │ └── Stone Age Problem.cpp │ │ └── 809/ │ │ └── Programs/ │ │ └── Qpwoeirut And The City.cpp │ ├── Div 3/ │ │ └── 828/ │ │ └── Programs/ │ │ ├── Divisibility by 2^n.cpp │ │ ├── Divisible Numbers Easy Version.cpp │ │ ├── Even-Odd Increments.cpp │ │ ├── Number Replacement.cpp │ │ └── Traffic Light.cpp │ ├── Educational Round 125/ │ │ ├── Explanations/ │ │ │ ├── By Gamers For Gamers Explanation.txt │ │ │ ├── Integer Moves Explanation.txt.txt │ │ │ └── XY Sequence Explanation.txt.txt │ │ └── Programs/ │ │ ├── Bracket Sequence Deletion.cpp │ │ ├── By Gamers For Gamers.cpp │ │ ├── Integer Moves.cpp │ │ └── XY Sequence.cpp │ └── Educational Rounds/ │ ├── Educational Round 125/ │ │ └── EExplanations/ │ │ └── Bracket Sequence Deletion Explanation.txt │ └── Educational Round 127/ │ ├── Explanations/ │ │ ├── Consecutive Points Segment Explanation.txt.txt │ │ ├── Dolce Vita Explanation.txt.txt │ │ ├── Insert a Progression Explanation.txt │ │ └── String Building Explanation.txt.txt │ └── Programs/ │ ├── Consecutive Points Segment.cpp │ ├── Dolce Vita.cpp │ ├── Insert a Progression.cpp │ └── String Building.cpp ├── 2023/ │ └── Contests/ │ └── Div 2/ │ ├── 810/ │ │ ├── Explanations/ │ │ │ └── XOR Triangle Explanation.txt │ │ └── Programs/ │ │ └── XOR Triangle.cpp │ └── 857/ │ └── Programs/ │ ├── Buying Gifts.cpp │ ├── Likes.cpp │ ├── Settlement of Guinea Pigs.cpp │ └── The Very Beautiful Blanket.cpp ├── C Programs/ │ ├── C Programs - 1/ │ │ ├── Bear_and_Big_Brother.c │ │ ├── Beautiful_Matrix.c │ │ ├── Boy_or_Girl.c │ │ ├── Complicated_GCD.c │ │ ├── Compote.c │ │ ├── Dasha_and_Stairs.c │ │ ├── Elephant.c │ │ ├── Even_Odds.c │ │ ├── Fancy_Fence.c │ │ ├── Holiday_of_Equality.c │ │ ├── I_Love_Username.c │ │ ├── Ilya_Bank_Account.c │ │ ├── Little_Elephant_Rozdil.c │ │ ├── Lucky_Division.c │ │ ├── Memory_and_Crow.c │ │ ├── Nearly_Lucky_Number.c │ │ ├── Opponents.c │ │ ├── Petr_and_Calendar.c │ │ ├── Shell_Game.c │ │ ├── Sherlock_New_Girlfriend.c │ │ ├── Taymr_is_Calling_You.c │ │ ├── The_Wall.c │ │ ├── Translation.c │ │ ├── Vitya_in_the_Countryside.c │ │ └── Vladik_and_Flights.c │ ├── C Programs - 2/ │ │ ├── A_and_B_Chess.c │ │ ├── Again_Twenty_Five.c │ │ ├── Anton_and_Danik.c │ │ ├── Bachgold_Problem.c │ │ ├── Bit++.c │ │ ├── Buy_a_Shovel.c │ │ ├── Chat_Room.c │ │ ├── Chips.c │ │ ├── Cinema_Line.c │ │ ├── Domino_Piling.c │ │ ├── Drazil_and_Date.c │ │ ├── George_and_Accomodation.c │ │ ├── Gravity_Flip.c │ │ ├── Infinite_Sequence.c │ │ ├── Interview_with_Oleg.c │ │ ├── Pasha_and_Stick.c │ │ ├── Pineapple_Incident.c │ │ ├── Serial_Killer.c │ │ ├── Soldier_and_Bananas.c │ │ ├── Spider_Man.c │ │ ├── Stones_on_a_Table.c │ │ ├── Transform_A_to_B.c │ │ ├── Triangular_Numbers.c │ │ ├── Watermelon.c │ │ └── Word_Capitalisation.c │ ├── C Programs - 3/ │ │ ├── Anton_and_Polyhedron.c │ │ ├── Calculating_Function.c │ │ ├── Cheap_Travel.c │ │ ├── Checking_the_Calendar.c │ │ ├── Currency_System_in_Geraldion.c │ │ ├── Die_Roll.c │ │ ├── Domino_Effect.c │ │ ├── Expression.c │ │ ├── Fedya_and_Maths.c │ │ ├── Filya_and_Homework.c │ │ ├── Game.c │ │ ├── Initial_Bet.c │ │ ├── LCM_Challenge.c │ │ ├── Maximum_Increase.c │ │ ├── Mishka_and_Game.c │ │ ├── Multiplication_Table.c │ │ ├── Next_Round.c │ │ ├── Party.c │ │ ├── Police_Recruits.c │ │ ├── Raising_Bacteria.c │ │ ├── Save_Luke.c │ │ ├── Taxes.c │ │ ├── Tennis_Tournament.c │ │ ├── The_Number_of_Positions.c │ │ └── Theatre_Square.c │ ├── C Programs - 4/ │ │ ├── Aloyna_Numbers.c │ │ ├── Arpa_Hard_Problem_Mehrad_Naive_Cheat.c │ │ ├── Benches.c │ │ ├── Challenge_Pendants.c │ │ ├── Chewbacca_and_Number.c │ │ ├── Chocolate.c │ │ ├── Design_Tutorial_Learn_From_Math.c │ │ ├── Divisibility.c │ │ ├── Fedor_and_New_Game.c │ │ ├── Game_test.c │ │ ├── Hexagons.c │ │ ├── Hulk.c │ │ ├── Indivisibility.c │ │ ├── Interview.c │ │ ├── King_Moves.c │ │ ├── Lineland_Mail.c │ │ ├── Lucky_Numbers.c │ │ ├── PolandBall_and_Hypothesis.c │ │ ├── Professor_Gukiz_Robot.c │ │ ├── Random_Teams.c │ │ ├── Reconnaissance_2.c │ │ ├── Selection_of_Personnel.c │ │ ├── Tetrahedron.c │ │ ├── Vasya_and_Petya_Game.c │ │ └── Way_Too_Long_Words.c │ ├── C Programs - 5/ │ │ ├── Bear_and_Poker.c │ │ ├── Boredom.c │ │ ├── Cut_Ribbon.c │ │ ├── Display_Size.c │ │ ├── Duff_in_Love.c │ │ ├── Flipping_Game.c │ │ ├── Flowers.cpp │ │ ├── Fox_and_Dividing_Cheese.c │ │ ├── Hungry_Sequence.c │ │ ├── K_Interesting_Pair_of_Integers.c │ │ ├── Kefa_and_First_Step.c │ │ ├── Making_a_String.c │ │ ├── Non_Square_Equation.c │ │ ├── Odd_Sum.c │ │ ├── Parking_Lot.c │ │ ├── Perfect_Permutation.c │ │ ├── Preparing_for_Olympiad.c │ │ ├── Star.c │ │ ├── Table_Tennis_Game_2.c │ │ ├── Tavas_and_Saddas.c │ │ ├── Team.c │ │ ├── Tetrahedron_Efficiently.c │ │ ├── Tricky_Sum.c │ │ ├── Vacations.c │ │ └── Vanya_and_Table.c │ ├── C Programs - 6/ │ │ ├── A_Shell_Game.c │ │ ├── Accounting.c │ │ ├── Anton_and_Digits.c │ │ ├── Black_Square.c │ │ ├── Dinner_with_Emma.c │ │ ├── Ebony_and_Ivory.c │ │ ├── Find Amir.c │ │ ├── Game_with_Sticks.c │ │ ├── Increasing_Sequence.c │ │ ├── Insomnia_Cure.c │ │ ├── Jumping_Ball.c │ │ ├── K_Tree.c │ │ ├── Lovely_Palindromes.c │ │ ├── Luxurious_Buildings.c │ │ ├── Meeting_of_Old_Friends.c │ │ ├── Oleg_and_Shares.c │ │ ├── Patrick_and_Shopping.c │ │ ├── Plate_Game.c │ │ ├── Rewards.c │ │ ├── Round_House.c │ │ ├── System_of_Equations.c │ │ ├── Vanya_and_Fence.c │ │ ├── Vanya_and_Lanterns.c │ │ ├── Vasya_and_Hipster.c │ │ └── Wizard_Duel.c │ ├── C Programs - 7/ │ │ ├── 3_Palindrome.c │ │ ├── Alena_Schedule.c │ │ ├── Alice_and_Bob.c │ │ ├── An_Abandoned_Sentiment_From_Past.c │ │ ├── Andrushya_and_Socks.c │ │ ├── Combination Lock.cpp │ │ ├── Devu_Singer_Charu_Joker.c │ │ ├── Fake_NP.c │ │ ├── Fence.c │ │ ├── Find_Marble.c │ │ ├── Free Ice Cream.cpp │ │ ├── Hexadecimal's Theorem Alternate Solution.cpp │ │ ├── Hexadecimal's Theorem.cpp │ │ ├── IQ_Test.c │ │ ├── Magnets.c │ │ ├── Mahmod_Longest_Uncommon_Subsequence.c │ │ ├── Monster_and_Squirrel.c │ │ ├── New Year Transportation.cpp │ │ ├── Optimal_Point_on_a_Line.cpp │ │ ├── Pashmak_and_Flowers.c │ │ ├── Potions_Homework.cpp │ │ ├── Pythagorean Triples.cpp │ │ ├── Red_Blue_Balls.c │ │ ├── The_Contest.c │ │ └── Young_Physicist.c │ ├── C Programs - 8/ │ │ ├── A and B Team Training.cpp │ │ ├── Almost Prime.cpp │ │ ├── Brian's Photos.cpp │ │ ├── Caisa and Pylons.cpp │ │ ├── Choosing Teams.cpp │ │ ├── Ciel and Flowers.cpp │ │ ├── Diverse Permutation.cpp │ │ ├── HQ9+.cpp │ │ ├── Hexadecimal's Numbers.cpp │ │ ├── Infinite Sequence.cpp │ │ ├── Jzzhu and Sequences.cpp │ │ ├── K-Factorisation.cpp │ │ ├── Noldbach Problem.cpp │ │ ├── Olesya and Rodion.cpp │ │ ├── Petr and Book.cpp │ │ ├── Petya and Strings.cpp │ │ ├── Sum of Digits.cpp │ │ ├── T Primes Alternate Solution.cpp │ │ ├── T-Primes.cpp │ │ ├── The Golden Age.cpp │ │ ├── Two Bags of Potatos.cpp │ │ ├── Vanya and Cards.cpp │ │ ├── Vitaly and Night.cpp │ │ ├── Wet Shark and Odd and Even.cpp │ │ └── Yaroslav and Permutations.cpp │ ├── C Programs - 9/ │ │ ├── Alyona and Copybooks.cpp │ │ ├── Appleman and Toastman.cpp │ │ ├── Array.cpp │ │ ├── Bear and Five Cards.cpp │ │ ├── Bus to Udayland.cpp │ │ ├── Case of the Zeroes and Ones.cpp │ │ ├── Circle Line.cpp │ │ ├── Crazy Computer.cpp │ │ ├── Crossword Solving.cpp │ │ ├── Divisibility.cpp │ │ ├── Fox and Number Game.cpp │ │ ├── Haiku.cpp │ │ ├── I'm Bored with Life.cpp │ │ ├── Is your Horseshoe on the other hoof.cpp │ │ ├── Kitahara Haruki's Gift.cpp │ │ ├── Little Elephant and Function.cpp │ │ ├── Little Elephant and Problem.cpp │ │ ├── New Year and Days.cpp │ │ ├── One Dimensional Japanese Crossword.cpp │ │ ├── Present from Lena.cpp │ │ ├── Prime Matrix.cpp │ │ ├── String Task.cpp │ │ ├── Subtractions.cpp │ │ ├── Toy Army.cpp │ │ └── k-th_Divisor.cpp │ ├── C Programs 10/ │ │ ├── A and B Compilation Errors.cpp │ │ ├── Amr and Music.cpp │ │ ├── Arrival of General.cpp │ │ ├── Bear and Game.cpp │ │ ├── Beautiful Year.cpp │ │ ├── Black Square.cpp │ │ ├── Counterexample.cpp │ │ ├── Difference Row.cpp │ │ ├── Eugene and Array.cpp │ │ ├── Interesting Drink.cpp │ │ ├── Keyboard Layouts.cpp │ │ ├── Life Without Zeroes.cpp │ │ ├── Modified GCD.cpp │ │ ├── Multi Judge Solving.cpp │ │ ├── Next Test.cpp │ │ ├── Presents.cpp │ │ ├── Serega and Coat Rack.cpp │ │ ├── Serega and Suffixes.cpp │ │ ├── Slightly Decreasing Permutation.cpp │ │ ├── SwapSort.cpp │ │ ├── Taxi.cpp │ │ ├── Toy Cars.cpp │ │ ├── Unimodal Arrays.cpp │ │ ├── Valera and Plates.cpp │ │ └── Vanya and Cubes.cpp │ ├── C Programs 11/ │ │ ├── BerSU Ball.cpp │ │ ├── Elections.cpp │ │ ├── Five in a Row.cpp │ │ ├── Football.cpp │ │ ├── Fortune Telling.cpp │ │ ├── Free Cash Alternate Solution.cpp │ │ ├── Free Cash.cpp │ │ ├── Games.cpp │ │ ├── Good Number.cpp │ │ ├── Johnny Likes Numbers.cpp │ │ ├── Lever.cpp │ │ ├── Lunch Rush.cpp │ │ ├── Magic Spheres.cpp │ │ ├── New Year and Hurry.cpp │ │ ├── Nicholas and Permutation.cpp │ │ ├── Petya and Staircases.cpp │ │ ├── Playing with Dice.cpp │ │ ├── Saitama Destroys Hotel.cpp │ │ ├── Sasha and Sticks.cpp │ │ ├── Soft Drinking.cpp │ │ ├── The Child and The Homework.cpp │ │ ├── The New Year Meeting Friends Alternate Solution.cpp │ │ ├── The New Year Meeting Friends.cpp │ │ ├── Word.cpp │ │ └── inc ARG.cpp │ ├── C Programs 12/ │ │ ├── Anastasia and Pebbles.cpp │ │ ├── Bear and Three Balls.cpp │ │ ├── Buggy Sorting.cpp │ │ ├── Co Prime Array.cpp │ │ ├── Dima and Friends.cpp │ │ ├── Dima and Sequence.cpp │ │ ├── Dreamoon and Stairs Alternate Solution.cpp │ │ ├── Dreamoon and Stairs.cpp │ │ ├── Fashion in Berland.cpp │ │ ├── Inbox (100500).cpp │ │ ├── Key Races.cpp │ │ ├── Ksusha and Arrays.cpp │ │ ├── Lecture.cpp │ │ ├── Little Elephant and Chess.cpp │ │ ├── Little Girl and Maximum Sum.cpp │ │ ├── Minimum Difficulty.cpp │ │ ├── Pasha and Pixels.cpp │ │ ├── Puzzles.cpp │ │ ├── Santa Claus and Candies.cpp │ │ ├── Sereja and Dima.cpp │ │ ├── Shaas and Oskols.cpp │ │ ├── Sleuth.cpp │ │ ├── The Festive Evening.cpp │ │ ├── The Number on The Board.cpp │ │ └── Watching a Movie.cpp │ ├── C Programs 13/ │ │ ├── A Good Contest.cpp │ │ ├── Arpa's Obvious Problem and Mehrad's Terrible Solution.cpp │ │ ├── Arrays.cpp │ │ ├── Arya and Bran.cpp │ │ ├── Bear and Elections.cpp │ │ ├── Business Trip.cpp │ │ ├── Cards.cpp │ │ ├── Code Obfuscation.cpp │ │ ├── Drinks.cpp │ │ ├── Epic Game.cpp │ │ ├── Functions Again.cpp │ │ ├── Generous Kefa.cpp │ │ ├── George and Job.cpp │ │ ├── Godsend.cpp │ │ ├── Ilya and Queries.cpp │ │ ├── Kuriyama Mirai's Stones.cpp │ │ ├── Lights Out.cpp │ │ ├── Little Dima and Equation.cpp │ │ ├── Little Elephant and Bits.cpp │ │ ├── New Skateboard.cpp │ │ ├── Oath of the Night's Watch.cpp │ │ ├── Sort the Array.cpp │ │ ├── Star Sky.cpp │ │ ├── Vanya and Books.cpp │ │ └── Vasya and Digital Root.cpp │ ├── C Programs 14/ │ │ ├── Asphalting Roads.cpp │ │ ├── Bicycle Chain.cpp │ │ ├── Borze.cpp │ │ ├── Building Permutation.cpp │ │ ├── Chess Tourney.cpp │ │ ├── Cormen - The Best Friend of Man.cpp │ │ ├── DZY Loves Sequences.cpp │ │ ├── Dragons.cpp │ │ ├── Drazil and Factorial.cpp │ │ ├── Football.cpp │ │ ├── Helpful Maths.cpp │ │ ├── Increase and Decrease.cpp │ │ ├── Jeff and Digits.cpp │ │ ├── Jzzhu and Children.cpp │ │ ├── Modulo Sum.cpp │ │ ├── Odds and Ends.cpp │ │ ├── Panoramix's Prediction.cpp │ │ ├── Permutation.cpp │ │ ├── Powers of Two.cpp │ │ ├── Queue at the School.cpp │ │ ├── Rectangles.cpp │ │ ├── Supercentral Point.cpp │ │ ├── Tram.cpp │ │ ├── Ultra Fast Mathematician.cpp │ │ └── Vasya and String.cpp │ ├── C Programs 15/ │ │ ├── Army.cpp │ │ ├── Between the Offices.cpp │ │ ├── Cableway.cpp │ │ ├── Ciferia.cpp │ │ ├── Coins.cpp │ │ ├── Divisibility by Eight.cpp │ │ ├── Exams.cpp │ │ ├── Given Length and Sum of Digits.cpp │ │ ├── Ilya and Sticks.cpp │ │ ├── Inna and Huge Candy Matrix.cpp │ │ ├── K-Multiple Free Set.cpp │ │ ├── Kefa and Park.cpp │ │ ├── Mahmoud and Ehab and the MEX.cpp │ │ ├── Mahmoud and Ehab and the bipartiteness.cpp │ │ ├── Mahmoud and Ehab and the xor.cpp │ │ ├── Number of Ways.cpp │ │ ├── Pearls in a Row.cpp │ │ ├── Pie Rules.cpp │ │ ├── Quasi-palindrome.cpp │ │ ├── Soldier and Number Game.cpp │ │ ├── Tanya and Toys.cpp │ │ ├── Team.cpp │ │ ├── The Eternal Immortality.cpp │ │ ├── Triangle.cpp │ │ └── USB Flash Drives.cpp │ ├── C Programs 16/ │ │ ├── Amusing Joke.cpp │ │ ├── Anton and Letters.cpp │ │ ├── Cards with Numbers.cpp │ │ ├── Classroom Watch.cpp │ │ ├── Cupboards.cpp │ │ ├── Dishonest Sellers.cpp │ │ ├── Dubstep.cpp │ │ ├── Easy Number Challenge.cpp │ │ ├── Fox and Snake.cpp │ │ ├── Greg and Array.cpp │ │ ├── Hacking Cypher.cpp │ │ ├── I Wanna Be The Guy.cpp │ │ ├── IQ Test.cpp │ │ ├── Jeff and Periods.cpp │ │ ├── Pashmak and Garden.cpp │ │ ├── Primes or Palindromes.cpp │ │ ├── Quasi Binary.cpp │ │ ├── Sereja and Bottles.cpp │ │ ├── Team Olympiad.cpp │ │ ├── The Fibonacci Segment.cpp │ │ ├── Twins.cpp │ │ ├── Valera and Tubes.cpp │ │ ├── Xenia and Bit Operations.cpp │ │ ├── Xenia and Ringroad.cpp │ │ └── k-String.cpp │ ├── C Programs 17/ │ │ ├── Adding Digits.cpp │ │ ├── Christmas Spruce.cpp │ │ ├── Dreamoon and Wi-Fi.cpp │ │ ├── Exams - 122.cpp │ │ ├── Garden.cpp │ │ ├── Jamie and Alarm Snooze.cpp │ │ ├── Jamie and Interesting Graph.cpp │ │ ├── Kolya and Tanya.cpp │ │ ├── Mashmokh and ACM.cpp │ │ ├── Maximum Splitting.cpp │ │ ├── Minimum Sum.cpp │ │ ├── Modular Exponentiation.cpp │ │ ├── New Year and Domino.cpp │ │ ├── New Year's Eve.cpp │ │ ├── Palindrome Pairs.cpp │ │ ├── Perfect Number.cpp │ │ ├── QAQ.cpp │ │ ├── Seat Arrangements.cpp │ │ ├── Supermarket.cpp │ │ ├── Swap Adjacent Elements.cpp │ │ ├── Tea Queue.cpp │ │ ├── Testing Pants for Sadness.cpp │ │ ├── The World is a Theatre.cpp │ │ ├── Tricky Alchemy.cpp │ │ └── Water the Gardens.cpp │ ├── C Programs 18/ │ │ ├── Art Union.cpp │ │ ├── Bear and Colours.cpp │ │ ├── Cave Painting.cpp │ │ ├── Cloning Toys.cpp │ │ ├── Eternal Victory.cpp │ │ ├── Hard Problem.cpp │ │ ├── Joystick.cpp │ │ ├── K-Special Tables.cpp │ │ ├── Lucky Sum.cpp │ │ ├── Magic Forest.cpp │ │ ├── Marvolo Gaunt's Ring Alternate Solution.cpp │ │ ├── Marvolo Gaunt's Ring.cpp │ │ ├── Not Equal on a Segment.cpp │ │ ├── Perfect Squares.cpp │ │ ├── Petya and Inequiations.cpp │ │ ├── Polo the Penguin and Matrix.cpp │ │ ├── Polo the Penguin and Strings.cpp │ │ ├── Replacement.cpp │ │ ├── Robot Vaccuum Cleaner.cpp │ │ ├── Rumour.cpp │ │ ├── Search for Pretty Integers.cpp │ │ ├── Tom Riddle's Diary.cpp │ │ ├── Two Substrings.cpp │ │ ├── Vladik and Fractions.cpp │ │ └── Woodcutter.cpp │ ├── C Programs 19/ │ │ ├── A Compatible Pair.cpp │ │ ├── A Prosperous Lot.cpp │ │ ├── Almost Identity Permutations.cpp │ │ ├── Amr and Large Array.cpp │ │ ├── Beautiful Sets of Points.cpp │ │ ├── Buggy Robot.cpp │ │ ├── Cellular Network.cpp │ │ ├── Coder.cpp │ │ ├── Diversity.cpp │ │ ├── Guest From The Past.cpp │ │ ├── Hamster Farm.cpp │ │ ├── K-Dominant Character.cpp │ │ ├── Little Artem and Grasshopper.cpp │ │ ├── Longest K-Good Segment.cpp │ │ ├── Love Triangle.cpp │ │ ├── Nuts.cpp │ │ ├── Palindrome Transformation.cpp │ │ ├── Palindromic Supersequence.cpp │ │ ├── Recursive Queries.cpp │ │ ├── Run For Your Prize.cpp │ │ ├── Simple Strings.cpp │ │ ├── The Useless Toy.cpp │ │ ├── Vasya and Socks.cpp │ │ ├── Watchmen.cpp │ │ └── Word Correction.cpp │ ├── C Programs 20/ │ │ ├── Alena and the Heater.cpp │ │ ├── Fafa and Ancient Alphabet.cpp │ │ ├── Fafa and His Company.cpp │ │ ├── Fafa and the Gates.cpp │ │ ├── Fixing Typos.cpp │ │ ├── Gargari and Bishops.cpp │ │ ├── Gargari and Permutations Alternate Solution.cpp │ │ ├── Gargari and Permutations.cpp │ │ ├── Hard Process.cpp │ │ ├── Lisa and Dima.cpp │ │ ├── Love Rescue.cpp │ │ ├── Mashmokh and Numbers.cpp │ │ ├── Non-Secret Cypher.cpp │ │ ├── Olympiad.cpp │ │ ├── Partition.cpp │ │ ├── Petya and His Friends Alternate Solution.cpp │ │ ├── Petya and His Friends.cpp │ │ ├── Phone Numbers.cpp │ │ ├── Pocket Book.cpp │ │ ├── Points on the Line.cpp │ │ ├── Protect Sheep.cpp │ │ ├── String Transformation.cpp │ │ ├── Sum and Replace.cpp │ │ ├── Vile Grasshoppers.cpp │ │ └── Weird Subtraction Process.cpp │ ├── C Programs 21/ │ │ ├── Aramic Script Bitmask Solution.cpp │ │ ├── Aramic Script.cpp │ │ ├── Arithmetic Progression.cpp │ │ ├── Bash and a Tough Math Puzzle.cpp │ │ ├── Consecutive Subsequences.cpp │ │ ├── Cyclic Components.cpp │ │ ├── Divide by Three, Multiply by Two Alternate Solution.cpp │ │ ├── Divide by Three, Multiply by Two.cpp │ │ ├── Dreamoon and Sets.cpp │ │ ├── File Name.cpp │ │ ├── Fox and Box Accumulation.cpp │ │ ├── Ghosts.cpp │ │ ├── Less or Equal.cpp │ │ ├── Little Girl and Maximum XOR.cpp │ │ ├── Lucky Sum of Digits.cpp │ │ ├── Mahmoud and Ehab and another array construction task.cpp │ │ ├── Mahmoud and Ehab and Even Odd Game.cpp │ │ ├── Mahmoud and a Triangle.cpp │ │ ├── Make a Square Alternate Solution.cpp │ │ ├── Make a Square.cpp │ │ ├── Mancala.cpp │ │ ├── Mentors.cpp │ │ ├── Pairs of Lines.cpp │ │ ├── Two Gram.cpp │ │ ├── Valhalla Seige.cpp │ │ └── Wrong Subtraction.cpp │ ├── C Programs 22/ │ │ ├── AND Graph.cpp │ │ ├── Almost Arithmetic Progression.cpp │ │ ├── Antipalindrome Alternate Solution.cpp │ │ ├── Antipalindrome.cpp │ │ ├── Ball.cpp │ │ ├── Bits.cpp │ │ ├── Bookshelves.cpp │ │ ├── Businessman Problems.cpp │ │ ├── Chess Placing.cpp │ │ ├── Correct Solution.cpp │ │ ├── Counting Kangaroos is Fun.cpp │ │ ├── Fruits.cpp │ │ ├── High School Become Human.cpp │ │ ├── Infinity Gauntlet.cpp │ │ ├── Knights of a Polygonal Table.cpp │ │ ├── Letters.cpp │ │ ├── Local Extrema.cpp │ │ ├── Remove Duplicates.cpp │ │ ├── Super Agent.cpp │ │ ├── Switches and Lamps.cpp │ │ ├── Tafurama.cpp │ │ ├── Three Displays Segment Tree Solution.cpp │ │ ├── Three Displays.cpp │ │ └── Useful Decomposition.cpp │ ├── C Programs 23/ │ │ ├── An Impassioned Circulation of Affection.cpp │ │ ├── Another Problem on Strings.cpp │ │ ├── Babaei and Birthday Cake.cpp │ │ ├── Bear and Prime Numbers.cpp │ │ ├── Cirriculum Vitae.cpp │ │ ├── Classy Numbers Precomputing Solution.cpp │ │ ├── Counting Arrays.cpp │ │ ├── Crazy Town.cpp │ │ ├── Find Maximum.cpp │ │ ├── Fish.cpp │ │ ├── Garbage Disposal.cpp │ │ ├── Guest From The Past.cpp │ │ ├── Ice Skater.cpp │ │ ├── Lazyland.cpp │ │ ├── Lesha and Array Splitting.cpp │ │ ├── Lost Array.cpp │ │ ├── Maximum Value.cpp │ │ ├── Maze.cpp │ │ ├── Minesweeper.cpp │ │ ├── Minimum Diameter Tree.cpp │ │ ├── No To Palindromes.cpp │ │ ├── On Number of Decompositions into Multipliers.cpp │ │ ├── Summarise to Powers of Two.cpp │ │ ├── The Fair Nut and String.cpp │ │ └── The Meaningless Game.cpp │ └── C Programs 24/ │ ├── Brutality.cpp │ ├── Connect.cpp │ ├── Div Times Mod.cpp │ ├── Diverse Garland.cpp │ ├── Division and Union.cpp │ ├── Finite or Not.cpp │ ├── Illya and Escalator.cpp │ ├── Increasing by Modulo.cpp │ ├── Nice Garland.cpp │ ├── Planning the Expedition.cpp │ ├── Playing Piano.cpp │ ├── Posterized.cpp │ ├── Powers of Two.cpp │ ├── Splitting into Digits.cpp │ ├── Stages.cpp │ ├── Tanya and Candies.cpp │ ├── The Way to Home.cpp │ ├── Vanya and Label.cpp │ ├── Where_Do_I_Turn.c │ └── Zero Quantity Maximisation.cpp ├── Contests/ │ ├── 463 Div 1 + 2 ICM Technex/ │ │ ├── Explanations/ │ │ │ └── Team Work Explanation.txt │ │ └── Programs/ │ │ └── Team Work.cpp │ ├── 607 Div 1 + 2/ │ │ ├── Explanations/ │ │ │ ├── Azamon Web Services Explanation.txt │ │ │ ├── Beingawesomeism Explanation.txt │ │ │ ├── Cut and Paste Explanation.txt │ │ │ ├── Jeremy Bearimy Explanation.txt │ │ │ └── Suffix Three Explanation.txt │ │ └── Programs/ │ │ ├── Azamon Web Services.cpp │ │ ├── Beingawesomeism.cpp │ │ ├── Cut and Paste.cpp │ │ ├── Jeremy Bearimy.cpp │ │ └── Suffix Three.cpp │ ├── 609 Div 2/ │ │ ├── Explanations/ │ │ │ └── Equation Explanation.txt │ │ └── Programs/ │ │ └── Equation.cpp │ ├── Avito Code Challenge 2018/ │ │ ├── Explanations/ │ │ │ ├── Antipalindrome Alternate Solution Explanation.txt │ │ │ ├── Antipalindrome Explanation.txt │ │ │ ├── Bookshelves Explanation.txt │ │ │ ├── Businessman Problems Explanation.txt │ │ │ └── Useful Decomposition Explanation.txt │ │ └── Programs/ │ │ ├── Antipalindrome Alternate Solution.cpp │ │ ├── Antipalindrome.cpp │ │ ├── Bookshelves.cpp │ │ ├── Businessman Problems.cpp │ │ └── Useful Decomposition.cpp │ ├── Avito Cool Challenge 2018/ │ │ ├── Explanation/ │ │ │ ├── Colourful Bricks Explanation.txt │ │ │ └── Definite Game Explanation.txt │ │ └── Programs/ │ │ ├── Colourful Bricks.cpp │ │ └── Definite Game.cpp │ ├── Barcelona Bootcamp 2018/ │ │ ├── Explanation/ │ │ │ ├── Maximum Sum of Digits Explanation.txt │ │ │ ├── Phone Numbers Explanation.txt │ │ │ └── Social Circles Explanation.txt │ │ └── Programs/ │ │ ├── Maximum Sum of Digits.cpp │ │ ├── Phone Numbers.cpp │ │ └── Social Circles.cpp │ ├── CodeForces Global Round 1/ │ │ ├── Explanations/ │ │ │ ├── Magic Stones Explanation.txt │ │ │ ├── Meaningless Operations Explanation.txt │ │ │ ├── Parity Explanation.txt │ │ │ └── Tape Explanation.txt │ │ └── Programs/ │ │ ├── Magic Stones.cpp │ │ ├── Meaningless Operations.cpp │ │ ├── Parity.cpp │ │ └── Tape.cpp │ ├── CodeForces Global Round 3/ │ │ ├── Explanations/ │ │ │ ├── Another One Bites the Dust Explanation.txt │ │ │ ├── Born This Way Explanation.txt │ │ │ ├── Crazy Diamond Explanation.txt │ │ │ └── Dirty Deeds Done Dirt Cheap Explanation.txt │ │ ├── Programs/ │ │ │ ├── Another One Bites the Dust.cpp │ │ │ ├── Born This Way.cpp │ │ │ ├── Crazy Diamond.cpp │ │ │ └── Dirty Deeds Done Dirt Cheap.cpp │ │ └── Rough Notes Link │ ├── CodeForces Global Round 5/ │ │ ├── Explanations/ │ │ │ ├── Balanced Rating Changes Explanation.txt │ │ │ └── Balanced Tunnel Explanation.txt │ │ └── Programs/ │ │ ├── Balanced Rating Changes.cpp │ │ └── Balanced Tunnel.cpp │ ├── Dasha Code Championship Elimination Round 2019/ │ │ ├── Explanations/ │ │ │ ├── Cows and Snacks Explanation.txt │ │ │ ├── Koala and Lights Explanation │ │ │ ├── Paint The Digits Explanation │ │ │ └── Paint Your Numbers Explanation │ │ ├── Programs/ │ │ │ ├── Cows and Snacks.cpp │ │ │ ├── Koala and Lights.cpp │ │ │ ├── Paint The Digits.cpp │ │ │ ├── Paint The Numbers.cpp │ │ │ └── Paint Your Numbers.cpp │ │ └── Rough Notes │ ├── Div 1 492/ │ │ ├── Explanations/ │ │ │ ├── Game 995 Explanation.txt │ │ │ ├── Leaving the Bar Explanation.txt │ │ │ └── Suit and Tie Explanation.txt │ │ └── Programs/ │ │ ├── Game 995D.cpp │ │ ├── Leaving The Bar.cpp │ │ └── Suit and Tie.cpp │ ├── Div 2 12/ │ │ ├── Explanations/ │ │ │ ├── Ball Explanation.txt │ │ │ ├── Correct Solution Explanation.txt │ │ │ ├── Fruits Explanation.txt │ │ │ └── Super Agent Explanation.txt │ │ └── Programs/ │ │ ├── Ball.cpp │ │ ├── Correct Solution.cpp │ │ ├── Fruits.cpp │ │ └── Super Agent.cpp │ ├── Div 2 136/ │ │ ├── Explanations/ │ │ │ ├── Little Elephant And Array Segment Tree Explanation.txt │ │ │ ├── Little Elephant and Arrays Explanation.txt │ │ │ ├── Little Elephant and Function Explanation.txt │ │ │ ├── Little Elephant and Numbers Explanation.txt │ │ │ └── Little Elephant and Problem Explanation.txt │ │ └── Programs/ │ │ ├── Little Elephant And Array Segment Tree Solution.cpp │ │ ├── Little Elephant and Array.cpp │ │ ├── Little Elephant and Function.cpp │ │ ├── Little Elephant and Numbers.cpp │ │ └── Little Elephant and Problem.cpp │ ├── Div 2 197/ │ │ ├── Explanations/ │ │ │ ├── Helpful Maths Explanation.txt │ │ │ ├── Xenia and Bit Operations Explanation.txt │ │ │ ├── Xenia and Ringroad Explanation.txt │ │ │ └── Xenia and Weights Explanation.txt │ │ └── Programs/ │ │ ├── Helpful Maths.cpp │ │ ├── Xenia and Bit Operations.cpp │ │ ├── Xenia and Ringroad.cpp │ │ └── Xenia and Weights.cpp │ ├── Div 2 205/ │ │ ├── Explanation/ │ │ │ ├── Little Elephant and Cards Explanation.txt │ │ │ └── Little Elephant and Rozdil - Explanation.txt │ │ └── Programs/ │ │ ├── Little Elephant and Cards.cpp │ │ ├── Little Elephant and Sorting.cpp │ │ └── Little_Elephant_Rozdil.c │ ├── Div 2 261/ │ │ ├── Explanation/ │ │ │ ├── Pashmak and Buses Explanation.txt │ │ │ ├── Pashmak and Buses.cpp │ │ │ ├── Pashmak and Flowers - Explanation.txt │ │ │ ├── Pashmak and Garden Explanation.txt │ │ │ ├── Pashmak and Graph Explanation.txt │ │ │ └── Pashmak and Parmida's Problem Explanation.txt │ │ └── Programs/ │ │ ├── Pashmak and Buses.cpp │ │ ├── Pashmak and Garden.cpp │ │ ├── Pashmak and Graph.cpp │ │ ├── Pashmak and Parmida's Problem.cpp │ │ └── Pashmak_and_Flowers.c │ ├── Div 2 276/ │ │ ├── Explanations/ │ │ │ ├── Little Girl and Maximum Sum Explanation.txt │ │ │ ├── Little Girl and Maximum XOR Explanation.txt │ │ │ └── Lunch Rush Explanation.txt │ │ └── Programs/ │ │ ├── Little Girl and Maximum Sum.cpp │ │ ├── Little Girl and Maximum XOR.cpp │ │ └── Lunch Rush.cpp │ ├── Div 2 321/ │ │ └── Programs/ │ │ ├── Kefa and Company.cpp │ │ ├── Kefa and Park.cpp │ │ └── Kefa_and_First_Step.c │ ├── Div 2 367/ │ │ ├── Explanation/ │ │ │ ├── Hard Problem Explanation.txt │ │ │ └── Interesting Drink Explanation.txt │ │ └── Programs/ │ │ ├── Hard Problem.cpp │ │ └── Interesting Drink.cpp │ ├── Div 2 371/ │ │ ├── Explanations/ │ │ │ ├── Filya and Homework - Explanation.txt │ │ │ ├── Meeting of Old Friends - Explanation.txt │ │ │ └── Sonya and Queries Explanation.txt │ │ └── Programs/ │ │ ├── Filya_and_Homework.c │ │ ├── Meeting_of_Old_Friends.c │ │ └── Sonya and Queries.cpp │ ├── Div 2 461/ │ │ ├── Explanations/ │ │ │ └── Cave Paintings Explanation.txt │ │ └── Programs/ │ │ └── Cave Paintings.cpp │ ├── Div 2 464/ │ │ └── Programs/ │ │ └── Love Triangle.cpp │ ├── Div 2 473/ │ │ ├── Explanation/ │ │ │ ├── Mahmoud and Ehab and Another Array Construction Task Explanation.txt │ │ │ └── Mahmoud and Ehab and Even Odd Game Explanation.txt │ │ └── Programs/ │ │ ├── Mahmoud and Ehab and Another Array Construction Task.cpp │ │ └── Mahmoud and Ehab and Even Odd Game.cpp │ ├── Div 2 478/ │ │ ├── Explanations/ │ │ │ ├── Aramic Script Bitmask Solution.txt │ │ │ ├── Aramic Script Explanation.txt │ │ │ ├── Ghosts Explanation.txt │ │ │ ├── Mancala Explanation.txt │ │ │ └── Valhalla Siege Explanation.txt │ │ └── Programs/ │ │ ├── Aramic Script Bitmask Solution.cpp │ │ ├── Aramic Script.cpp │ │ ├── Ghosts.cpp │ │ ├── Mancala.cpp │ │ └── Valhalla Siege.cpp │ ├── Div 2 485/ │ │ ├── Explanations/ │ │ │ ├── AND Graph Explanation.txt │ │ │ ├── Fair Explanation.txt │ │ │ ├── High Schooll Become Human Explanation.txt │ │ │ ├── Infinity Gauntlet Explanation.txt │ │ │ ├── Petr and Permutations Explanation.txt │ │ │ ├── Three Displays Explanation.txt │ │ │ └── Three Displays Segment Tree Solution Explanation.txt │ │ └── Programs/ │ │ ├── AND Graph.cpp │ │ ├── Fair.cpp │ │ ├── High School Become Human.cpp │ │ ├── Infinity Gauntlet.cpp │ │ ├── Petr and Permutations.cpp │ │ ├── Three Displays Segment Tree Solution.cpp │ │ └── Three Displays.cpp │ ├── Div 2 489/ │ │ ├── Explanations/ │ │ │ ├── Nastya Studies Informatics Explanation.txt │ │ │ ├── Nastya and Game Explanation.txt │ │ │ ├── Nastya and King Shamans Alternate Solution Explanation.txt │ │ │ ├── Nastya and King Shamans Explanation.txt │ │ │ ├── Nastya and a Wardrobe Explanation.txt │ │ │ └── Nastya and an Array Explanation.txt │ │ └── Programs/ │ │ ├── Nastya Studies Informatics.cpp │ │ ├── Nastya and Game.cpp │ │ ├── Nastya and King-Shamans Alternate Solution.cpp │ │ ├── Nastya and King-Shamans.cpp │ │ ├── Nastya and a Wardrobe.cpp │ │ └── Nastya and an Array.cpp │ ├── Div 2 491/ │ │ ├── Explanations/ │ │ │ ├── Bishwock Explanation.txt │ │ │ ├── Bus Number Explanation.txt │ │ │ ├── Candies Explanation.txt │ │ │ ├── Getting an A Explanation.txt │ │ │ └── If At First You Don't Succeed Explanation.txt │ │ └── Programs/ │ │ ├── Bishwock.cpp │ │ ├── Bus Number.cpp │ │ ├── Candies.cpp │ │ ├── Getting an A.cpp │ │ └── If At First You Don't Succeed.cpp │ ├── Div 2 492/ │ │ ├── Explanation/ │ │ │ ├── Game 995 Explanation.txt │ │ │ ├── Hit the Lottery Explanation.txt │ │ │ ├── Leaving the Bar Explanation.txt │ │ │ ├── Suit and Tie Explanation.txt │ │ │ ├── Tesla Explanation.txt │ │ │ └── World Cup Explanation.txt │ │ └── Programs/ │ │ ├── Game 995D.cpp │ │ ├── Hit the Lottery.cpp │ │ ├── Leaving The Bar.cpp │ │ ├── Suit and Tie.cpp │ │ ├── Tesla.cpp │ │ └── World Cup.cpp │ ├── Div 2 497/ │ │ ├── Explanation/ │ │ │ ├── Reorder the Array Explanation.txt │ │ │ ├── Romaji Explanation.txt │ │ │ └── Turn The Rectangle Explanation.txt │ │ └── Programs/ │ │ ├── Reorder the Array.cpp │ │ ├── Romaji.cpp │ │ └── Turn the Rectangle.cpp │ ├── Div 2 508/ │ │ ├── Explanation/ │ │ │ ├── Equality Explanation.txt │ │ │ ├── Gambling Explanation.txt │ │ │ └── Non Coprime Partition Explanation.txt │ │ └── Programs/ │ │ ├── Equality.cpp │ │ ├── Gambling.cpp │ │ └── Non Coprime Partition.cpp │ ├── Div 2 511/ │ │ ├── Explanation/ │ │ │ ├── Enlarge GCD Explanation.txt │ │ │ └── Little C Loves 3 I Explanation.txt │ │ └── Programs/ │ │ └── Little C Loves 3 I.cpp │ ├── Div 2 533/ │ │ ├── Explanations/ │ │ │ ├── Ayoub and Lost Array Explanation.txt │ │ │ ├── Ayoub and Lost Array Matrix Exponentiation Explanation.txt │ │ │ ├── Salem and Sticks Explanation.txt │ │ │ └── Zuhair and Strings Explanation.txt │ │ └── Programs/ │ │ ├── Ayoub and Lost Array Matrix Exponentiation.cpp │ │ ├── Ayoub and Lost Array.cpp │ │ ├── Salem and Sticks.cpp │ │ └── Zuhair and Strings.cpp │ ├── Div 2 538/ │ │ ├── Explanations/ │ │ │ ├── Arithmetic Progression Explanation.txt.txt │ │ │ ├── Flood Fill Explanation.txt │ │ │ ├── Got Any Grapes Explanation.txt │ │ │ ├── Please Another Queries on Array Explanation.txt │ │ │ ├── Trailing Loves Explanation.txt │ │ │ ├── Yet Another Subarray Alternate Solution Explanation.txt │ │ │ └── Yet Another Subarray Explanation.txt │ │ └── Programs/ │ │ ├── Arithmetic Progression.cpp │ │ ├── Flood Fill.cpp │ │ ├── Got Any Grapes.cpp │ │ ├── Please Another Queries on Array.cpp │ │ ├── Trailing Loves.cpp │ │ ├── Yet Another Subarray Problem Alternate Solution.cpp │ │ └── Yet Another Subarray Problem.cpp │ ├── Div 2 539/ │ │ ├── Explanations/ │ │ │ ├── Sasha and A Bit of Relax Explanation.txt │ │ │ ├── Sasha and His Trip Explanation.txt │ │ │ ├── Sasha and Magnetic Machine Explanation.txt │ │ │ └── Sasha and One More Name Explanation.txt │ │ └── Programs/ │ │ ├── Sasha and A Bit of Relax.cpp │ │ ├── Sasha and His Trip.cpp │ │ ├── Sasha and Magnetic Machine.cpp │ │ └── Sasha and One More Name.cpp │ ├── Div 2 546/ │ │ ├── Explanations/ │ │ │ ├── Nastya is Playing Computer Games Explanation.txt │ │ │ └── Nastya is Transposing Matrices Explanation.txt │ │ └── Programs/ │ │ ├── Nastya is Playing Computer Games.cpp │ │ └── Nastya is Transposing Matrices.cpp │ ├── Div 2 554/ │ │ ├── Explanations/ │ │ │ └── Neko Does Math Explanation.txt │ │ └── Programs/ │ │ └── Neko Does Math.cpp │ ├── Div 2 562/ │ │ ├── Explanations/ │ │ │ ├── Good Triple Explanation.txt │ │ │ └── Pairs Explanation.txt │ │ ├── Programs/ │ │ │ ├── Good Triple.cpp │ │ │ ├── Increasing by Modulo.cpp │ │ │ └── Pairs.cpp │ │ └── Rough Notes Link │ ├── Div 2 566/ │ │ ├── Explanations/ │ │ │ ├── Filing Shapes Explanation.txt │ │ │ └── Plus From Picture Explanation.txt │ │ ├── Programs/ │ │ │ ├── Filing Shapes.cpp │ │ │ └── Plus From Picture.cpp │ │ └── Rough Notes Link │ ├── Div 2 585/ │ │ ├── Explanations/ │ │ │ ├── Swap Letters Explanation.txt │ │ │ ├── The Number of Products Explanation.txt │ │ │ └── Yellow Cards Explanation │ │ ├── Programs/ │ │ │ ├── Swap Letters.cpp │ │ │ ├── The Number of Products.cpp │ │ │ └── Yellow Cards.cpp │ │ └── Rough Notes │ ├── Div 2 588/ │ │ ├── Explanations/ │ │ │ ├── Anadi and Domino Explanation.txt │ │ │ ├── Ania and Minimizing Explanation.txt │ │ │ ├── Dawid and Bags of Candies Explanation.txt │ │ │ ├── Kamil and Making a Stream Explanation.txt │ │ │ ├── Konrad and Company Evaluation Explanation.txt │ │ │ └── Marcin and Training Camp Explanation.txt │ │ └── Programs/ │ │ ├── Anadi and Domino.cpp │ │ ├── Ania and Minimizing.cpp │ │ ├── Dawid and Bags of Candies.cpp │ │ ├── Kamil and Making a Stream.cpp │ │ ├── Konrad and Company Evaluation.cpp │ │ └── Marcin and Training Camp.cpp │ ├── Div 2 589/ │ │ ├── Explanations/ │ │ │ ├── Complete Tripartite Explanation.txt │ │ │ ├── Distinct Digits Explanation.txt │ │ │ ├── Filing the Grid Explanation.txt │ │ │ └── Primes and Multiplication Explanation.txt │ │ └── Programs/ │ │ ├── Complete Tripartite.cpp │ │ ├── Distinct Digits.cpp │ │ ├── Filing the Grid.cpp │ │ └── Primes and Multiplication.cpp │ ├── Div 2 592/ │ │ ├── Explanations/ │ │ │ ├── Minimizing Difference Explanation.txt │ │ │ ├── Pens and Pencils Explanation.txt │ │ │ ├── Rooms and Staircases Explanation.txt │ │ │ └── The Football Season Explanation.txt │ │ └── Programs/ │ │ ├── Minimizing Difference.cpp │ │ ├── Pens and Pencils.cpp │ │ ├── Rooms and Staircases.cpp │ │ └── The Football Season.cpp │ ├── Div 2 596/ │ │ ├── Explanations/ │ │ │ ├── Forgetting Things Explanation.txt │ │ │ ├── P Binary Explanation.txt │ │ │ ├── Power Products Explanation.txt │ │ │ └── TV Subscriptions Explanation.txt │ │ └── Programs/ │ │ ├── Forgetting Things.cpp │ │ ├── P-Binary.cpp │ │ ├── Power Products.cpp │ │ └── TV Subscriptions.cpp │ ├── Div 2 597/ │ │ ├── Explanations/ │ │ │ ├── Constanze's Machine Explanation.txt │ │ │ ├── Good Ol Number Colouring Explanation.txt │ │ │ └── Restricted RPS Explanation.txt │ │ └── Programs/ │ │ ├── Constanze's Machine.cpp │ │ ├── Good Ol Number Colouring.cpp │ │ └── Restricted RPS.cpp │ ├── Div 2 599/ │ │ ├── Explanations/ │ │ │ ├── Character Swap Explanation.txt │ │ │ ├── Maximum Square Explanation.txt │ │ │ └── Tile Painting Explanation.txt │ │ └── Programs/ │ │ ├── Character Swap.cpp │ │ ├── Maximum Square.cpp │ │ └── Tile Painting.cpp │ ├── Div 2 600/ │ │ ├── Explanations/ │ │ │ ├── Antenna Coverage Explanation.txt.txt │ │ │ ├── Harmonious Graph Explanation.txt │ │ │ ├── Silly Mistakes Explanation.txt │ │ │ ├── Single Push Explanation.txt │ │ │ └── Sweets Eating Explanation.txt │ │ └── Programs/ │ │ ├── Antenna Coverage.cpp │ │ ├── Harmonious Graph.cpp │ │ ├── Silly Mistakes.cpp │ │ ├── Single Push.cpp │ │ └── Sweets Eating.cpp │ ├── Div 2 608/ │ │ └── Programs/ │ │ └── Shwarma Tent.cpp │ ├── Div 2 85/ │ │ ├── Explanation/ │ │ │ ├── Petya and Divisors Explanation.txt │ │ │ ├── Petya and Inequiations Explanation.txt │ │ │ └── Petya and Strings Explanation.txt │ │ └── Programs/ │ │ ├── Petya and Divisors.cpp │ │ ├── Petya and Inequiations.cpp │ │ └── Petya and Strings.cpp │ ├── Div 3 479/ │ │ ├── Explanations/ │ │ │ ├── Consecutive Subsequences Explanation.txt │ │ │ ├── Cyclic Components Explanation.txt │ │ │ ├── Divide by Three Multiply by Two Alternate Solution Explanation.txt │ │ │ ├── Divide by Three, Multiply by Two Explanation.txt │ │ │ ├── Less or Equal Explanation.txt │ │ │ ├── Two Gram Explanation.txt │ │ │ └── Wrong Subtraction Explanation.txt │ │ └── Programs/ │ │ ├── Consecutive Subsequences.cpp │ │ ├── Cyclic Components.cpp │ │ ├── Divide by Three, Multiply by Two Alternate Solution.cpp │ │ ├── Divide by Three, Multiply by Two.cpp │ │ ├── Less or Equal.cpp │ │ ├── Two Gram.cpp │ │ └── Wrong Subtraction.cpp │ ├── Div 3 481/ │ │ ├── Explanations/ │ │ │ ├── Almost Arithmetic Progression Explanation.txt │ │ │ ├── File Name Explanation.txt │ │ │ ├── Letters Explanation.txt │ │ │ ├── Mentors Explanation.txt │ │ │ └── Remove Duplicates Explanation.txt │ │ └── Programs/ │ │ ├── Almost Arithmetic Progression.cpp │ │ ├── File Name.cpp │ │ ├── Letters.cpp │ │ ├── Mentors.cpp │ │ └── Remove Duplicates.cpp │ ├── Div 3 486/ │ │ ├── Explanation/ │ │ │ ├── Diverse Team Explanation.txt │ │ │ ├── Divisibility by 25 Explanation.txt │ │ │ ├── Equal Sums Explanation.txt │ │ │ ├── Points and Powers of Two Explanation.txt │ │ │ └── Substring Sort Explanation.txt │ │ └── Programs/ │ │ ├── Diverse Team.cpp │ │ ├── Divisibility by 25.cpp │ │ ├── Equal Sums.cpp │ │ ├── Points and Powers of Two.cpp │ │ └── Substring Sort.cpp │ ├── Div 3 490/ │ │ ├── Explanations/ │ │ │ ├── Alphabetic Removals Explanation.txt │ │ │ ├── Equalise the Remainders Explanation.txt │ │ │ ├── Mishika and Contests Explanation.txt │ │ │ ├── Reachability from Capital Explanation.txt │ │ │ └── Reversing Encryption Explanation.txt │ │ └── Programs/ │ │ ├── Alphabetic Removals.cpp │ │ ├── Equalise the Remainders.cpp │ │ ├── Mishika and Contests.cpp │ │ ├── Reachability from Capital.cpp │ │ └── Reversing Encryption.cpp │ ├── Div 3 494/ │ │ ├── Explanations/ │ │ │ ├── Binary String Constructing Explanation.txt │ │ │ ├── Coins and Queries Explanation.txt │ │ │ ├── Intense Heat Explanation.txt │ │ │ └── Polycarp's Pockets Explanation.txt │ │ └── Programs/ │ │ ├── Binary String Constructing.cpp │ │ ├── Coins and Queries.cpp │ │ ├── Intense Heat.cpp │ │ └── Polycarp's Pockets.cpp │ ├── Div 3 521/ │ │ ├── Explanations/ │ │ │ ├── Cutting Out Explanation.txt │ │ │ ├── Disturbed People.txt │ │ │ ├── Frog Jumping.txt │ │ │ ├── Good Array.txt │ │ │ └── Thematic Contests Explanation.txt │ │ └── Programs/ │ │ ├── Cutting Out.cpp │ │ ├── Disturbed People.cpp │ │ ├── Frog Jumping.cpp │ │ ├── Good Array.cpp │ │ ├── Pictures with Kittens (Easy Version).cpp │ │ └── Thematic Contests.cpp │ ├── Div 3 531/ │ │ ├── Explanations/ │ │ │ ├── Array K Colouring Explanation.txt │ │ │ └── Balanced Ternary String Explanation.txt │ │ └── Programs/ │ │ ├── Array K Colouring.cpp │ │ └── Balanced Ternary String.cpp │ ├── Div 3 547/ │ │ ├── Explanations/ │ │ │ ├── Colored Boots Explanation.txt │ │ │ ├── Game 23 Explanation.txt │ │ │ ├── Maximal Continuous Rest Explanation.txt │ │ │ ├── Polycarp Restores Permutation Explanation.txt │ │ │ ├── Privatization of Roads in Berland Explanation.txt │ │ │ ├── Same Sum Blocks Explanation.txt │ │ │ └── Superhero Battle Explanation.txt │ │ └── Programs/ │ │ ├── Colored Boots.cpp │ │ ├── Game 23.cpp │ │ ├── Maximal Continuous Rest.cpp │ │ ├── Polycarp Restores Permutation.cpp │ │ ├── Privatization of Roads in Berland.cpp │ │ ├── Same Sum Blocks.cpp │ │ └── Superhero Battle.cpp │ ├── Div 3 590/ │ │ ├── Explanations/ │ │ │ ├── Special Permutations Explanation.txt │ │ │ └── Yet Another Substring Reverse Explanation.txt │ │ └── Programs/ │ │ ├── Special Permutations.cpp │ │ └── Yet Another Substring Reverse.cpp │ ├── Div 3 593/ │ │ ├── Explanations/ │ │ │ ├── Books Exchange Explanation.txt │ │ │ ├── By Elevator or Stairs Explanation.txt │ │ │ ├── Good Numbers Explanation.txt │ │ │ └── Yet Another Dividing Into Teams Explanation.txt │ │ └── Programs/ │ │ ├── Books Exchange.cpp │ │ ├── Elevator or Stairs.cpp │ │ ├── Good Numbers.cpp │ │ └── Yet Another Dividing Into Teams.cpp │ ├── Div 3 595/ │ │ ├── Explanations/ │ │ │ ├── Books Exchange Explanation.txt │ │ │ ├── Good Numbers Explanation.txt │ │ │ └── Yet Another Dividing Into Teams Explanation.txt │ │ └── Programs/ │ │ ├── Books Exchange.cpp │ │ ├── Good Numbers.cpp │ │ └── Yet Another Dividing Into Teams.cpp │ ├── Div 3 598/ │ │ ├── Explanations/ │ │ │ ├── Equalizing Two Strings Explanation.txt │ │ │ ├── Minimize the Permutation Explanation.txt │ │ │ └── Payment Without Change Explanation.txt │ │ └── Programs/ │ │ ├── Binary String Minimizing.cpp │ │ ├── Equalizing Two Strings.cpp │ │ ├── Minimize the Permutation.cpp │ │ └── Payment Without Change.cpp │ ├── Educational Round 11/ │ │ ├── Explanations/ │ │ │ ├── Co Prime Array Explanation.txt │ │ │ ├── Hard Process Explanation.txt │ │ │ └── Number of Parallelograms Explanation.txt │ │ └── Programs/ │ │ ├── Co Prime Array.cpp │ │ ├── Hard Process.cpp │ │ └── Number of Parallelograms.cpp │ ├── Educational Round 32/ │ │ ├── Explanations/ │ │ │ ├── Almost Identity Permutations Explanation.txt │ │ │ ├── Buggy Robot.cpp │ │ │ ├── K-Dominant Character Explanation.txt │ │ │ └── Local Extrema Explanation.txt │ │ └── Programs/ │ │ ├── Almost Identity Permutations.cpp │ │ ├── Buggy Robot.cpp │ │ ├── K-Dominant Character.cpp │ │ └── Local Extrema.cpp │ ├── Educational Round 37/ │ │ ├── Explanation/ │ │ │ ├── Connected Components Explanation.txt.txt │ │ │ ├── List of Integer Explanation.txt │ │ │ ├── Sum and Replace Explanation.txt │ │ │ ├── Swap Adjacent Elements Explanation.txt │ │ │ ├── Tanks Explanation.txt.txt │ │ │ ├── Tea Queue Explanation.txt │ │ │ └── Water the Gardens Explanation.txt │ │ └── Programs/ │ │ ├── Connected Components.cpp │ │ ├── List of Integers.cpp │ │ ├── Sum and Replace.cpp │ │ ├── Swap Adjacent Elements.cpp │ │ ├── Tanks.cpp │ │ ├── Tea Queue.cpp │ │ └── Water the Gardens.cpp │ ├── Educational Round 44/ │ │ ├── Explanations/ │ │ │ ├── Chess Placing Explanation.txt │ │ │ └── Switches and Lamps Explanation.txt │ │ └── Programs/ │ │ ├── Chess Placing.cpp │ │ └── Switches and Lamps.cpp │ ├── Educational Round 46/ │ │ ├── Explanations/ │ │ │ ├── CodeHorses T Shirts Explanation.txt │ │ │ ├── Covered Points Count Explanation.txt │ │ │ └── Yet Another Problem on Subsequence Explanation.txt │ │ └── Programs/ │ │ ├── CodeHorses T Shirts.cpp │ │ ├── Covered Points Count.cpp │ │ └── Yet Another Problem on Subsequence.cpp │ ├── Educational Round 51/ │ │ ├── Explanation/ │ │ │ ├── Bicolourings Explanation.txt │ │ │ ├── Relatively Prime Pairs Explanation.txt │ │ │ ├── Vasya and Multisets Explanation.txt │ │ │ └── Vasya and Password Explanation.txt │ │ └── Programs/ │ │ ├── Bicolourings.cpp │ │ ├── Relatively Prime Pairs.cpp │ │ ├── Vasya and Multisets.cpp │ │ └── Vasya and Password.cpp │ ├── Educational Round 52/ │ │ ├── Explanations/ │ │ │ ├── Vasya and Chocolates Explanation.txt │ │ │ └── Vasya and Isolated Vertices Explanation.txt │ │ └── Programs/ │ │ ├── Vasya and Chocolates.cpp │ │ └── Vasya and Isolated Vertices.cpp │ ├── Educational Round 54/ │ │ ├── Explanation/ │ │ │ ├── Divisor Subtraction Explanation.txt │ │ │ ├── Meme Problem Explanation.txt │ │ │ └── Minimizing the String Explanation.txt │ │ └── Programs/ │ │ ├── Divisor Subtraction.cpp │ │ ├── Meme Problem.cpp │ │ └── Minimizing the String.cpp │ ├── Educational Round 55/ │ │ ├── Explanation/ │ │ │ └── Increasing Frequency Explanation.txt │ │ └── Programs/ │ │ └── Increasing Frequency.cpp │ ├── Educational Round 56/ │ │ ├── Explanations/ │ │ │ ├── Beautiful Graph Explanation.txt │ │ │ ├── Dice Rolling Explanation.txt │ │ │ ├── Letters Rearranging Explanation.txt │ │ │ └── Mishka and Last Exam Explanation.txt │ │ └── Programs/ │ │ ├── Beautiful Graph.cpp │ │ ├── Dice Rolling.cpp │ │ ├── Letters Rearranging.cpp │ │ └── Mishka and Last Exam.cpp │ ├── Educational Round 60/ │ │ ├── Explanations/ │ │ │ ├── Best Subsegment Explanation.txt │ │ │ └── Emotes Explanation.txt │ │ └── Programs/ │ │ ├── Best Subsegment.cpp │ │ └── Emotes.cpp │ ├── Educational Round 62/ │ │ ├── Explanations/ │ │ │ ├── Detective Book Explanation.txt │ │ │ ├── Good Strings Explanation.txt │ │ │ ├── Minimum Triangulation Explanation.txt │ │ │ └── Playlist Explanation.txt │ │ └── Programs/ │ │ ├── Detective Book.cpp │ │ ├── Good Strings.cpp │ │ ├── Minimum Triangulation.cpp │ │ └── Playlist.cpp │ ├── Educational Round 69/ │ │ ├── Explanations/ │ │ │ ├── Array Splitting Explanation.txt │ │ │ ├── DIY Wooden Ladder Explanation.txt │ │ │ └── Pillars Explanation.txt │ │ ├── Programs/ │ │ │ ├── Array Splitting.cpp │ │ │ ├── DIY Wooden Ladder.cpp │ │ │ └── Pillars.cpp │ │ └── Rough Notes Link │ ├── Educational Round 73/ │ │ ├── Explanations/ │ │ │ ├── 2048 Game Explanation.txt │ │ │ ├── Game With String Explanation.txt │ │ │ ├── Knights Explanation.txt │ │ │ ├── Make The Fence Great Again Explanation.txt │ │ │ └── Perfect Team Explanation.txt │ │ └── Programs/ │ │ ├── 2048 Game.cpp │ │ ├── Game With String.cpp │ │ ├── Knights.cpp │ │ ├── Make The Fence Great Again.cpp │ │ └── Perfect Team.cpp │ ├── Educational Round 74/ │ │ ├── Explanations/ │ │ │ ├── AB String Explanation.txt │ │ │ ├── Keyboard Purchase Explanation.txt │ │ │ ├── Kill Em All Explanation.txt │ │ │ └── Prime Subtraction Explanation.txt │ │ └── Programs/ │ │ ├── AB String.cpp │ │ ├── Keyboard Purchase.cpp │ │ ├── Kill Em All Explanation.txt │ │ └── Prime Subtraction.cpp │ ├── Educational Round 77/ │ │ ├── Explanations/ │ │ │ └── Yet Another Monster Killing Problem Explanation.txt │ │ └── Programs/ │ │ ├── Dominated Subarray.cpp │ │ ├── Magic Stick.cpp │ │ ├── Two Rival Students.cpp │ │ └── Yet Another Monster Killing Problem.cpp │ ├── Lyft Level 5 Challenge 2018 - Elimination Round/ │ │ ├── Explanation/ │ │ │ ├── Divisors.txt │ │ │ ├── King Escape Explanation.txt │ │ │ ├── Permutation Game Explanation.txt │ │ │ └── Square Difference Explanation.txt │ │ └── Programs/ │ │ ├── Divisors.cpp │ │ ├── King Escape.cpp │ │ ├── Permutation Game.cpp │ │ └── Square Difference.cpp │ ├── Mail.Ru Cup 2018 Round 1/ │ │ ├── Explanation/ │ │ │ ├── Appending Mex.txt │ │ │ ├── Candies Distribution.txt │ │ │ └── Changing the Array Explanation.txt │ │ └── Programs/ │ │ ├── Appending Mex.cpp │ │ ├── Candy Distribution.cpp │ │ └── Changing the Array.cpp │ ├── Manthan 2018/ │ │ ├── Explanation/ │ │ │ ├── Equalize Explanation.txt │ │ │ ├── Packets Explanation.txt │ │ │ ├── Reach Median Explanation.txt │ │ │ └── Valid BFS Explanation.txt │ │ └── Programs/ │ │ ├── Equalize.cpp │ │ ├── Packets.cpp │ │ ├── Reach Median.cpp │ │ └── Valid BFS.cpp │ ├── Moscow Team Olympiad 2018/ │ │ ├── Explanation/ │ │ │ ├── Equations of Mathematical Magic Explanation.txt │ │ │ ├── Make a Triangle Explanation.txt │ │ │ └── Oh Those Palindromes Explanation.txt │ │ └── Programs/ │ │ ├── Equations of Mathematical Magic.cpp │ │ ├── Make a Triangle.cpp │ │ └── Oh Those Palindromes.cpp │ ├── Technocup 2019 Elimination Round 1/ │ │ ├── Explanation/ │ │ │ ├── In Search of An Easy Problem Explanation.txt │ │ │ ├── Vasya and Cornfield.txt │ │ │ ├── Vasya and Golden Ticket Explanation.txt │ │ │ ├── Vasya and Good Sequences Explanation.txt │ │ │ └── Vasya and Triangle Explanation.txt │ │ └── Programs/ │ │ ├── In Search of An Easy Problem.cpp │ │ ├── Vasya and Cornfield.cpp │ │ ├── Vasya and Golden Ticket.cpp │ │ ├── Vasya and Good Sequences.cpp │ │ └── Vasya and Triangle.cpp │ └── Technocup 2019 Elimination Round 2/ │ ├── Explanation/ │ │ ├── Curiosity Has No Limits.txt │ │ └── Golden Plate.txt │ └── Programs/ │ ├── Curiosity Has No Limits.cpp │ └── Golden Plate.cpp ├── Explanations/ │ ├── Explanations - 1/ │ │ ├── Again Twenty Five - Explanation.txt │ │ ├── Bear and Big Brother - Explanation.txt │ │ ├── Beautiful Matrix - Explanation.txt │ │ ├── Boy or Girl - Explanation.txt │ │ ├── Complicated GCD - Explanation.txt │ │ ├── Compote - Explanation.txt │ │ ├── Dasha and Stairs - Explanation.txt │ │ ├── Elephant - Explanation.txt │ │ ├── Even Odds - Explanation.txt │ │ ├── Fancy Fence - Explanation.txt │ │ ├── Holiday of Equality - Explanation.txt │ │ ├── I Love Username - Explanation.txt │ │ ├── Ilya Bank Account - Explanation.txt │ │ ├── Little Elephant and Rozdil - Explanation.txt │ │ ├── Lucky Division - Explanation.txt │ │ ├── Nearly Lucky Number - Explanation.txt │ │ ├── Opponents - Explanation.txt │ │ ├── Petr and a Calendar - Explanation.txt │ │ ├── Shell Game - Explanation.txt │ │ ├── Sherlock's New Girlfriend - Explanation.txt │ │ ├── Taymr is Calling You - Explanation.txt │ │ ├── The Wall - Explanation.txt │ │ ├── Translation - Explanation.txt │ │ ├── Vitya in the Countryside - Explanation.txt │ │ └── Vladik and Flights - Explanation.txt │ ├── Explanations - 10/ │ │ ├── A and B Compilation Errors Explanation.txt │ │ ├── Amr and Music Explanation.txt │ │ ├── Arrival of General Explanation.txt │ │ ├── Bear and Game Explanation.txt │ │ ├── Beautiful Year Explanation.txt │ │ ├── Black Square Explanation.txt │ │ ├── Counterexample Explanation.txt │ │ ├── Difference Row.txt │ │ ├── Eugene and Array Explanation.txt │ │ ├── Interesting Drink Explanation.txt │ │ ├── Keyboard Layouts Explanation.txt │ │ ├── Life Without Zeroes Explanation.txt │ │ ├── Modified GCD Explanation.txt │ │ ├── Multi Judge Solving Explanation.txt │ │ ├── Next Test Explanation.txt │ │ ├── Presents Explanation.txt │ │ ├── Serega and Coat Rack Explanation.txt │ │ ├── Serega and Suffixes Explanation.txt │ │ ├── Slightly Decreasing Permutation Explanation.txt │ │ ├── Swap Sort Explanation.txt │ │ ├── Taxi Explanation.txt │ │ ├── Toy Cars Explanation.txt │ │ ├── Unimodal Arrays Explanation.txt │ │ ├── Valera and Plates Explanation.txt │ │ └── Vanya and Cubes Explanation.txt │ ├── Explanations - 11/ │ │ ├── BerSU Ball Explanation.txt │ │ ├── Elections Explanation.txt │ │ ├── Five in a Row Explanation.txt │ │ ├── Football Explanation.txt │ │ ├── Fortune Telling Explanation.txt │ │ ├── Free Cash Alternate Solution Explanation.txt │ │ ├── Free Cash Explanation.txt │ │ ├── Games.txt │ │ ├── Good Number Explanation.txt │ │ ├── Johnny Likes Numbers Explanation.txt │ │ ├── Lever Explanation.txt │ │ ├── Lunch Rush Explanation.txt │ │ ├── Magic Spheres Explanation.txt │ │ ├── New Year and Hurry Explanation.txt │ │ ├── Nicholas and Permutation Explanation.txt │ │ ├── Petya and Staircases Explanation.txt │ │ ├── Playing with Dice Explanation.txt │ │ ├── Saitama Destroys Hotel Explanation.txt │ │ ├── Sasha and Sticks Explanation.txt │ │ ├── Soft Drinking Explanation.txt │ │ ├── The Child and The Homework Explanation.txt │ │ ├── The New Year Meeting Friends Alternate Solution.txt │ │ ├── The New Year Meeting Friends Explanation.txt │ │ ├── Word Explanation.txt │ │ └── inc ARG Explanation.txt │ ├── Explanations - 2/ │ │ ├── A and B Chess - Explanation.txt │ │ ├── Anton and Danik - Explanation.txt │ │ ├── Bachgold Problem - Explanation.txt │ │ ├── Bit++ - Explanation.txt │ │ ├── Buy a Shovel - Explanation.txt │ │ ├── Chat Room - Explanation.txt │ │ ├── Chips - Explanation.txt │ │ ├── Cinema Line - Explanation.txt │ │ ├── Domino Piling - Explanation.txt │ │ ├── Drazil and Date - Explanation.txt │ │ ├── George and Accomodation - Explanation.txt │ │ ├── Gravity Flip - Explanation.txt │ │ ├── Infinite Sequence - Explanation.txt │ │ ├── Interview with Oleg - Explanation.txt │ │ ├── Memory and Crow - Explanation.txt │ │ ├── Pasha and Stick - Explanation.txt │ │ ├── Pineapple Incident - Explanation.txt │ │ ├── Serial Killer - Explanation.txt │ │ ├── Soldier and Bananas - Explanation.txt │ │ ├── Spider Man - Explanation.txt │ │ ├── Stones on a Table - Explanation.txt │ │ ├── Transform A to B - Explanation.txt │ │ ├── Triangular Numbers - Explanation.txt │ │ ├── Watermelon - Explanation.txt │ │ └── Word Capitalisation - Explanation.txt │ ├── Explanations - 3/ │ │ ├── Anton and Polyhedron - Explanation.txt │ │ ├── Calculating Function - Explanation.txt │ │ ├── Cheap Travel - Explanation.txt │ │ ├── Checking the Calendar - Expanation.txt │ │ ├── Currency System in Geraldion - Explanation.txt │ │ ├── Die Roll - Explanation.txt │ │ ├── Domino Effect - Explanation.txt │ │ ├── Expression - Explanation.txt │ │ ├── Fedya and Maths - Explanation.txt │ │ ├── Filya and Homework - Explanation.txt │ │ ├── Game - Explanation.txt │ │ ├── Initial Bet - Explanation.txt │ │ ├── LCM Challenge - Explanation.txt │ │ ├── Maximum Increase - Explanation.txt │ │ ├── Mishka and Game - Explanation.txt │ │ ├── Multiplication Table - Explanation.txt │ │ ├── Next Round - Explanation.txt │ │ ├── Party - Explanation.txt │ │ ├── Police Recruits - Explanation.txt │ │ ├── Raising Bacteria - Explanation.txt │ │ ├── Save Luke - Explanation.txt │ │ ├── Taxes - Explanation.txt │ │ ├── Tennis Tournament - Explanation.txt │ │ ├── The Number of Positions - Explanation.txt │ │ └── Theatre Square - Explanation.txt │ ├── Explanations - 4/ │ │ ├── Aloyna Numbers - Explanation.txt │ │ ├── Arpa's Hard Problem and Mehrad's Naive Cheat - Explanation.txt │ │ ├── Benches - Explanation.txt │ │ ├── Challenge Pendants - Explanation.txt │ │ ├── Chewbecca and Number - Explanation.txt │ │ ├── Chocolate - Explanation.txt │ │ ├── Design Tutorial - Learn From Math - Explanation.txt │ │ ├── Divisibility - Explanation.txt │ │ ├── Fedor and New Game - Explanation.txt │ │ ├── Game-Test - Explanation.txt │ │ ├── Hexagons - Explanation.txt │ │ ├── Hulk - Explanation.txt │ │ ├── Indivisibility - Explanation.txt │ │ ├── Interview - Explanation.txt │ │ ├── King Moves - Explanation.txt │ │ ├── Lineland Mail - Explanation.txt │ │ ├── Lucky Numbers - Explanation.txt │ │ ├── Poland Ball and Hypothesis - Explanation.txt │ │ ├── Professor Gukiz's Robot - Explanation.txt │ │ ├── Random Teams- Explanation.txt │ │ ├── Reconnaissance 2 - Explanation.txt │ │ ├── Selection of Personnel - Explanation.txt │ │ ├── Tetrahedron - Explanation.txt │ │ ├── Vasya and Petya's Game - Explanation.txt │ │ └── Way Too Long Words - Explanation.txt │ ├── Explanations - 5/ │ │ ├── Bear and Poker - Explanation.txt │ │ ├── Boredom - Explanation.txt │ │ ├── Cut Ribbon - Explanation.txt │ │ ├── Display Size - Explanation.txt │ │ ├── Duff in Love - Explanation.txt │ │ ├── Flipping Game - Explanation.txt │ │ ├── Flowers - Explanation.txt │ │ ├── Fox and Dividing Cheese - Explanation.txt │ │ ├── Hungry Sequence - Explanation.txt │ │ ├── K Interesting Pair of Integers - Explanation.txt │ │ ├── Kefa and First Step - Explanation.txt │ │ ├── Making a String - Explanation.txt │ │ ├── Non Square Equation - Explanation.txt │ │ ├── Odd Sum - Explanation.txt │ │ ├── Parking Lot - Explanation.txt │ │ ├── Perfect Permutation - Explanation.txt │ │ ├── Preparing for Olympiad - Explanation.txt │ │ ├── Star - Explanation.txt │ │ ├── Table Tennis Game 2 - Explanation.txt │ │ ├── Tavas and Saddas - Explanation.txt │ │ ├── Team - Explanation.txt │ │ ├── Tetrahedron - Efficiently Explanation.txt │ │ ├── Tricky Sum - Explanation.txt │ │ ├── Vacations - Explanation.txt │ │ └── Vanya and Table.txt │ ├── Explanations - 6/ │ │ ├── A Shell Game - Explanation.txt │ │ ├── Accounting - Explanation.txt │ │ ├── Anton and Digits - Explanation.txt │ │ ├── Black Square - Explanation.txt │ │ ├── Dinner with Emma - Explanation.txt │ │ ├── Ebony and Ivory - Explanation.txt │ │ ├── Find Amir - Explanation.txt │ │ ├── Game with Sticks - Explanation.txt │ │ ├── Increasing Sequence - Explanation.txt │ │ ├── Insomnia Cure - Explanation.txt │ │ ├── Jumping Ball - Explanation.txt │ │ ├── K Tree - Explanation.txt │ │ ├── Lovely Palindromes - Explanation.txt │ │ ├── Luxurious Buildings - Explanation.txt │ │ ├── Meeting of Old Friends - Explanation.txt │ │ ├── Oleg and Shares - Explanation.txt │ │ ├── Patrick and Shopping - Explanation.txt │ │ ├── Plate Game - Explanation.txt │ │ ├── Rewards - Explanation.txt │ │ ├── Round House - Explanation.txt │ │ ├── System of Equations - Explanation.txt │ │ ├── Vanya and Fence - Explanation.txt │ │ ├── Vanya and Lanterns - Explanation.txt │ │ ├── Vasya and Hipster - Explanation.txt │ │ └── Wizard's Duel - Explanation.txt │ ├── Explanations - 7/ │ │ ├── 3 - Palindrome - Explanation.txt │ │ ├── Alena's Schedule - Explanation.txt │ │ ├── Alice and Bob - Explanation.txt │ │ ├── An Abandoned Sentiment From The Past - Explanation.txt │ │ ├── Andrushya and Socks - Explanation.txt │ │ ├── Combination Lock Explanation.txt │ │ ├── Devu, the Singer and Churu, the Joker - Explanation.txt │ │ ├── Fake NP - Explanation.txt │ │ ├── Fence - Explanation.txt │ │ ├── Find Marble - Explanation.txt │ │ ├── Free Ice Cream Explanation.txt │ │ ├── Hexadecimal's Theorem Alternate Solution Explanation.txt │ │ ├── Hexadecimal's Theorem Explanation.txt │ │ ├── IQ Test - Explanation.txt │ │ ├── Magnets - Explanation.txt │ │ ├── Mahmod and Longest Uncommon Subsequence - Explanation.txt │ │ ├── Monster and Squirrel - Explanation.txt │ │ ├── New Year Transportation Explanation.txt │ │ ├── Optimal Point on a Line - Explanation.txt │ │ ├── Pashmak and Flowers - Explanation.txt │ │ ├── Potions Homework - Explanation.txt │ │ ├── Pythagorean Triples Explanation.txt │ │ ├── Red and Blue Balls - Explanation.txt │ │ ├── The Contest - Explanation.txt │ │ └── Young Physicist - Explanation.txt │ ├── Explanations - 8/ │ │ ├── A and B Team Training Explanation.txt │ │ ├── Almost Primes Explanation.txt │ │ ├── Brian's Photos.txt │ │ ├── Caisa and Pylons Explanation.txt │ │ ├── Ceil and Flowers Explanation.txt │ │ ├── Choosing Teams Explanation.txt │ │ ├── Diverse Permutation Explanation.txt │ │ ├── Golden Age Explanation.txt │ │ ├── HQ9+ Explanation.txt │ │ ├── Hexadecimal's Numbers Explanation.txt │ │ ├── Jzzhu and Sequences Explanation.txt │ │ ├── K Factorisation Explanation.txt │ │ ├── Noldbach Problem Explanation.txt │ │ ├── Oleysa and Rodion Explanation.txt │ │ ├── Petr and Book Explanation.txt │ │ ├── Petya and Strings Explanation.txt │ │ ├── Sum of Digits Explanation.txt │ │ ├── T Primes Alternate Solution Explanation.txt │ │ ├── T Primes Explanation.txt │ │ ├── Two Bags of Potatos - Explanation.txt │ │ ├── Vanya and Cards Explanation.txt │ │ ├── Vitaly and Night Explanation.txt │ │ ├── Wet Shark and Odd and Even Explanation.txt │ │ └── Yarslav and Permutations Explanation.txt │ ├── Explanations - 9/ │ │ ├── Alyona and Copybooks Explanation.txt │ │ ├── Appleman and Toastman Explanation.txt │ │ ├── Array Explanation.txt │ │ ├── Bear and Five Cards Explanation.txt │ │ ├── Bus to Udayland Explanation.txt │ │ ├── Case of the Zeroes and Ones Explanation.txt │ │ ├── Circle Line Explanation.txt │ │ ├── Crazy Computer Explanation.txt │ │ ├── Crossword Solving Explanation.txt │ │ ├── Divisibility Explanation.txt │ │ ├── Fox and Number Game Explanation.txt │ │ ├── Haiku Explanation.txt │ │ ├── I'm Bored with Life Explanation.txt │ │ ├── Is your Horseshow on the Other Hoof Explanation.txt │ │ ├── K-th Divisor Explanation.txt │ │ ├── Kitahara Haruki's Gift Explanation.txt │ │ ├── Little Elephant and Function Explanation.txt │ │ ├── Little Elephant and Problem Explanation.txt │ │ ├── New Year and Days Explanation.txt │ │ ├── One Dimensional Japanese Crossword Explanation.txt │ │ ├── Present from Lena Explanation.txt │ │ ├── Prime Matrix.txt │ │ ├── String Task Explanation.txt │ │ ├── Subtractions Explanation.txt │ │ └── Toy Army Explanation.txt │ ├── Explanations 12/ │ │ ├── Anastasia and Pebbles Explanation.txt │ │ ├── Bear and Three Balls Explanation.txt │ │ ├── Buggy Sorting Explanation.txt │ │ ├── Co Prime Array Explanation.txt │ │ ├── Dima and Friends Explanation.txt │ │ ├── Dima and Sequence Explanation.txt │ │ ├── Dreamoon and Stairs Alternate Solution Explanation.txt │ │ ├── Dreamoon and Stairs Explanation.txt │ │ ├── Fashion in Berland Explanation.txt │ │ ├── Inbox (100500) Explanation.txt │ │ ├── Key Races Explanation.txt │ │ ├── Ksusha and Arrays Explanation.txt │ │ ├── Lecture Explanation.txt │ │ ├── Little Elephant and Chess Explanation.txt │ │ ├── Little Girl and Maximum Sum.txt │ │ ├── Minimum Difficulty Explanation.txt │ │ ├── Pahsa and Pixels Explanation.txt │ │ ├── Puzzles Explanation.txt │ │ ├── Santa Claus and Candies Explanation.txt │ │ ├── Sergey and Dima Explanation.txt │ │ ├── Shaas and Oskols Explanation.txt │ │ ├── Sleuth Explanation.txt │ │ ├── The Festive Evening Explanation.txt │ │ ├── The Number on the Board Explanation.txt │ │ └── Watching a Movie Explanation.txt │ ├── Explanations 13/ │ │ ├── A Good Contest Explanation.txt │ │ ├── Arpa's Obvious Problem and Mehrad's Terrible Solution Explanation.txt │ │ ├── Arrays Explanation.txt │ │ ├── Arya and Bran Explanation.txt │ │ ├── Bear and Elections Explanation.txt │ │ ├── Business Trip.txt │ │ ├── Cards Explanation.txt │ │ ├── Code Obfuscation Explanation.txt │ │ ├── Drinks Explanation.txt │ │ ├── Epic Game Explanation.txt │ │ ├── Functions Again Explanation.txt │ │ ├── Generous Kefa Explanation.txt │ │ ├── George and Job Explanation.txt │ │ ├── Godsend Explanation.txt │ │ ├── Ilya and Queries Explanation.txt │ │ ├── Kuriyama Mirai's Stones Explanation.txt │ │ ├── Lights Out Explanation.txt │ │ ├── Little Dima and Equation Explanation.txt │ │ ├── Little Elephant and Bits Explanation.txt │ │ ├── New Skateboard Explanation.txt │ │ ├── Oath of the Night's Watch Explanation.txt │ │ ├── Sort the Array Explanation.txt │ │ ├── Star Sky Explanation.txt │ │ ├── Vanya and Books Explanation.txt │ │ └── Vasya and Digital Root Explanation.txt │ ├── Explanations 14/ │ │ ├── Asphalting Roads Explanation.txt │ │ ├── Bicycle Chain Explanation.txt │ │ ├── Borze Explanation.txt │ │ ├── Building Permutation Explanation.txt │ │ ├── Chess Tourney Explanation.txt │ │ ├── Cormen - The Best Friend of Man Explanation.txt │ │ ├── DZY Loves Sequences Explanation.txt │ │ ├── Dragons Explanation.txt │ │ ├── Drazil and Factorial Explanation.txt │ │ ├── Football Explanation.txt │ │ ├── Helpful Maths Explanation.txt │ │ ├── Increase and Decrease Explanation.txt │ │ ├── Jeff and Digits Explanation.txt │ │ ├── Jzzhu and Children Explanation.txt │ │ ├── Modulo Sum Explanation.txt │ │ ├── Odds and Ends Explanation.txt │ │ ├── Panoramix's Prediction Explanation.txt │ │ ├── Permutation Explanation.txt │ │ ├── Powers of Two.txt │ │ ├── Queue at the School Explanation.txt │ │ ├── Rectangles Explanation.txt │ │ ├── Supercentral Point Explanation.txt │ │ ├── Tram Explanation.txt │ │ ├── Ultra Fast Mathematician.txt │ │ └── Vasya and String Explanation.txt │ ├── Explanations 15/ │ │ ├── Army Explanation.txt │ │ ├── Between the Offices Explanation.txt │ │ ├── Cableway Explanation.txt │ │ ├── Ciferia Explanation.txt │ │ ├── Coins Explanation.txt │ │ ├── Divisibility by Eight Explanation.txt │ │ ├── Exams Explanation.txt │ │ ├── Given Length and Sum of Digits.txt │ │ ├── Ilya and Sticks Explanation.txt │ │ ├── Inna and Huge Candy Matrix Explanation.txt │ │ ├── K-Multiple Free Set Explanation.txt │ │ ├── Kefa and Park Explanation.txt │ │ ├── Mahmoud and Ehab and the MEX Explanation.txt │ │ ├── Mahmoud and Ehab and the bipartiteness Explanation.txt │ │ ├── Mahmoud and Ehab and the xor Explanation.txt │ │ ├── Number of Ways Explanation.txt │ │ ├── Pearls in a Row Explanation.txt │ │ ├── Pie Rules Explanation.txt │ │ ├── Quasi-palindrome Explanation.txt │ │ ├── Soldier and Number Game Explanation.txt │ │ ├── Tanya and Toys Explanation.txt │ │ ├── Team Explanation.txt │ │ ├── The Eternal Immortality Explanation.txt │ │ ├── Triangle Explanation.txt │ │ └── USB Flash Drives Explanation.txt │ ├── Explanations 16/ │ │ ├── Amusing Joke Explanation.txt │ │ ├── Anton and Letters Explanation.txt │ │ ├── Cards with Numbers Explanation.txt │ │ ├── Classroom Watch Explanation.txt │ │ ├── Cupboards Explanation.txt │ │ ├── Dishonest Sellers Explanation.txt │ │ ├── Dubstep Explanation.txt │ │ ├── Easy Number Challenge Explanation.txt │ │ ├── Fox and Snake Explanation.txt │ │ ├── Greg and Array Explanation.txt │ │ ├── Hacking Cypher Explanation.txt │ │ ├── I Wanna Be The Guy Explanation.txt │ │ ├── IQ Test Explanation.txt │ │ ├── Jeff and Periods Explanation.txt │ │ ├── Pashmak and Garden Explanation.txt │ │ ├── Primes or Palindromes Explanation.txt │ │ ├── Quasi Binary Explanation.txt │ │ ├── Sereja and Bottles Explanation.txt │ │ ├── Team Olympiad Explanation.txt │ │ ├── The Fibonacci Segment Explanation.txt │ │ ├── Twins Explanation.txt │ │ ├── Valera and Tubes Explanation.txt │ │ ├── Xenia and Bit Operations.txt │ │ ├── Xenia and Ringroad Explanation.txt │ │ └── k-String Explanation.txt │ ├── Explanations 17/ │ │ ├── Adding Digits Explanation.txt │ │ ├── Christmas Spruce Explanation.txt │ │ ├── Dreamoon and Wi-Fi Explanation.txt │ │ ├── Exams Explanation.txt │ │ ├── Garden Explanation.txt │ │ ├── Jamie and Alarm Snooze Explanation.txt │ │ ├── Jamie and Interesting Graph Explanation.txt │ │ ├── Kolya and Tanya Explanation.txt │ │ ├── Mashmokh and ACM Explanation.txt │ │ ├── Maxmium Splitting Explanation.txt │ │ ├── Minimum Sum Explanation.txt │ │ ├── Modular Exponentiation Explanation.txt │ │ ├── New Year and Domino Explanation.txt │ │ ├── New Year's Eve Explanation.txt │ │ ├── Palindrome Pairs Explanation.txt │ │ ├── Perfect Number Explanation.txt │ │ ├── QAQ Explanation.txt │ │ ├── Seat Arrangements Explanation.txt │ │ ├── Supermarket Explanation.txt │ │ ├── Swap Adjacent Elements Explanation.txt │ │ ├── Tea Queue Explanation.txt │ │ ├── Testing Pants for Sadness Explanation.txt │ │ ├── The World is a Theatre Explanation.txt │ │ ├── Tricky Alchemy Explanation.txt │ │ └── Water the Gardens Explanation.txt │ ├── Explanations 18/ │ │ ├── Art Union Explanation.txt │ │ ├── Bear and Colours Explanation.txt │ │ ├── Cave Painting Explanation.txt │ │ ├── Cloning Toys Explanation.txt │ │ ├── Eternal Victory Explanation.txt │ │ ├── Hard Problem Explanation.txt │ │ ├── Joystick Explanation.txt │ │ ├── K-Special Tables Explanation.txt │ │ ├── Lucky Sum Explanation.txt │ │ ├── Magic Forest Explanation.txt │ │ ├── Marvolo Gaunt's Ring Alternate Solution Explanation.txt │ │ ├── Marvolo Gaunt's Ring Explanation.txt │ │ ├── Not Equal on a Segment Explanation.txt │ │ ├── Perfect Squares Explanation.txt │ │ ├── Petya and Inequiations Explanation.txt │ │ ├── Polo the Penguin and Matrix Explanation.txt │ │ ├── Polo the Penguin and Strings Explanation.txt │ │ ├── Replacement Explanation.txt │ │ ├── Robot Vaccuum Cleaner Explanation.txt │ │ ├── Rumour Explanation.txt │ │ ├── Search for Pretty Integers Explanation.txt │ │ ├── Tom Riddle's Diary Explanation.txt │ │ ├── Two Substrings Explanation.txt │ │ ├── Vladik and Fractions Explanation.txt │ │ └── Woodcutter.txt │ ├── Explanations 19/ │ │ ├── A Compatipble Pair Explanation.txt │ │ ├── A Prosperous Lot Explanation.txt │ │ ├── Almost Identity Permutations Explanation.txt │ │ ├── Amr and Large Array Explanation.txt │ │ ├── Beautiful Sets of Points Explanation.txt │ │ ├── Buggy Robot Explanation.txt │ │ ├── Cellular Network Explanation.txt │ │ ├── Coder Explanation.txt │ │ ├── Diversity Explanation.txt │ │ ├── Hamster Farm Explanation.txt │ │ ├── K-Dominant Character Explanation.txt │ │ ├── Little Artem and Grasshopper Explanation.txt │ │ ├── Longest K Good Segment Explanation.txt │ │ ├── Love Triangle Explanation.txt │ │ ├── Nuts Explanation.txt │ │ ├── Palindrome Transformation Explanation.txt │ │ ├── Palindromic Supersequence Explanation.txt │ │ ├── Recursive Queries Explanation.txt │ │ ├── Run For Your Prize Explanation.txt │ │ ├── Simple Strings Explanation.txt │ │ ├── The Useless Toy Explanation.txt │ │ ├── Vasya and Socks Explanation.txt │ │ ├── Watchmen Explanation.txt │ │ └── Word Correction Explanation.txt │ ├── Explanations 20/ │ │ ├── Alena and the Heater Explanation.txt │ │ ├── Fafa and Ancient Alphabet Explanation.txt │ │ ├── Fafa and His Company Explanation.txt │ │ ├── Fafa and the Gates Explanation.txt │ │ ├── Fixing Typos Explanation.txt │ │ ├── Gargari and Bishops Explanation.txt │ │ ├── Gargari and Permutations Alternate Solution Explanation.txt │ │ ├── Gargari and Permutations Explanation.txt │ │ ├── Hard Process Explanation.txt │ │ ├── Lisa and Dima Explanation.txt │ │ ├── Love Rescue Explanation.txt │ │ ├── Mashmok and Numbers Explanation.txt │ │ ├── Non-Secret Cypher Explanation.txt │ │ ├── Olympiad Explanation.txt │ │ ├── Partition Explanation.txt │ │ ├── Petya and His Friends Alternate Solution Explanation.txt │ │ ├── Petya and His Friends Explanation.txt │ │ ├── Phone Numbers Explanation.txt │ │ ├── Pocket Book Explanation.txt │ │ ├── Points on the Line Explanation.txt │ │ ├── Protect Sheep Explanation.txt │ │ ├── String Transformation Explanation.txt │ │ ├── Sum and Replace Explanation.txt │ │ ├── Vile Grasshoppers Explanation.txt │ │ └── Weird Subtraction Process Explanation.txt │ ├── Explanations 21/ │ │ ├── Aramic Script Bitmask Solution.txt │ │ ├── Aramic Script Explanation.txt │ │ ├── Arithmetic Progression Explanation.txt │ │ ├── Bash and a Tough Math Puzzle Explanation.txt │ │ ├── Consecutive Subsequences Explanation.txt │ │ ├── Cyclic Components Explanation.txt │ │ ├── Divide by Three Multiply by Two Alternate Solution Explanation.txt │ │ ├── Divide by Three, Multiply by Two Explanation.txt │ │ ├── Dreamoon and Sets Explanation.txt │ │ ├── File Name Explanation.txt │ │ ├── Fox and Box Accumulation Explanation.txt │ │ ├── Ghosts Explanation.txt │ │ ├── Less or Equal Explanation.txt │ │ ├── Little Girl and Maximum XOR Explanation.txt │ │ ├── Lucky Sum of Digits Explanation.txt │ │ ├── Mahmoud and Ehab and Another Array Construction Test Explanation.txt │ │ ├── Mahmoud and Ehab and Even Odd Game Explanation.txt │ │ ├── Mahmoud and a Triangle Explanation.txt │ │ ├── Make a Square Alternate Solution Explanation.txt │ │ ├── Make a Square Explanation.txt │ │ ├── Mancala Explanation.txt │ │ ├── Pairs of Lines Explanation.txt │ │ ├── Two Gram Explanation.txt │ │ ├── Valhalla Siege Explanation.txt │ │ └── Wrong Subtraction Explanation.txt │ ├── Explanations 22/ │ │ ├── AND Graph Explanation.txt │ │ ├── Almost Arithmetic Progression Explanation.txt │ │ ├── Antipalindrome Alternate Solution Explanation.txt │ │ ├── Antipalindrome Explanation.txt │ │ ├── Ball Explanation.txt │ │ ├── Bits Explanation.txt │ │ ├── Bookshelves Explanation.txt │ │ ├── Businessman Problems Explanation.txt │ │ ├── Chess Placing Explanation.txt │ │ ├── Correct Solution Explanation.txt │ │ ├── Couting Kangaroos is Fun Explanation.txt │ │ ├── Fruits Explanation.txt │ │ ├── High Schooll Become Human Explanation.txt │ │ ├── Infinity Gauntlet Explanation.txt │ │ ├── Knights of a Polygonal Table Explanation.txt │ │ ├── Letters Explanation.txt │ │ ├── Local Extrema Explanation.txt │ │ ├── Remove Duplicates Explanation.txt │ │ ├── Super Agent Explanation.txt │ │ ├── Switches and Lamps Explanation.txt │ │ ├── Three Displays Explanation.txt │ │ ├── Three Displays Segment Tree Solution Explanation.txt │ │ ├── Tufurama Explanation.txt │ │ └── Useful Decomposition Explanation.txt │ ├── Explanations 23/ │ │ ├── An Impassioned Circulation of Affection Explanation.txt │ │ ├── Another Problem on Strings Explanation.txt │ │ ├── Babaei and Birthday Cake Explanation.txt │ │ ├── Bear and Prime Numbers Explanation.txt │ │ ├── Cirriculum Vitae Explanation.txt │ │ ├── Classy Numbers Explanation.txt │ │ ├── Counting Arrays Explanation.txt │ │ ├── Crazy Town Explanation.txt │ │ ├── Find Maximum Explanation.txt │ │ ├── Fish Explanation.txt │ │ ├── Garbage Disposal Explanation.txt │ │ ├── Guest from the Past Explanation.txt │ │ ├── Ice Skater Explanation.txt │ │ ├── Lazyland Explanation.txt │ │ ├── Lesha and Array Splitting Explanation.txt │ │ ├── Lost Array Explanation.txt │ │ ├── Maze Explanation.txt │ │ ├── Minesweeper Explanation.txt │ │ ├── Minimum Diameter Tree Explanation.txt │ │ ├── No To Palindromes Explanation.txt │ │ ├── On Number of Decompositions into Multipliers Explanation.txt │ │ ├── Summarise to Powers of Two Explanation.txt │ │ ├── The Fair Nut and String Explanation.txt │ │ └── The Meaningless Game Explanation.txt │ └── Explanations 24/ │ ├── Brutality Explanation.txt │ ├── Connect Explanation.txt │ ├── Div Times Mod Explanation.txt │ ├── Diverse Garland Explanation.txt │ ├── Division and Union Explanation.txt │ ├── Finite or Not Explanation.txt │ ├── Ilya and Escalator Explanation.txt │ ├── Increasing by Modulo Explanation.txt │ ├── Nice Garland Explanation.txt │ ├── Planning the Expedition Explanation.txt │ ├── Playing Piano Explanation.txt │ ├── Posterized Explanation.txt │ ├── Powers of Two Explanation.txt │ ├── Splitting into Digits Explanation.txt │ ├── Stages Explanation.txt │ ├── Tanya and Candies Explanation.txt │ ├── The Way to Home Explanation.txt │ ├── Vanya and Label Explanation.txt │ ├── Where Do I Turn Explanation.txt │ └── Zero Quantity Maximisation Explanation.txt └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Explanations/Cow and Fields Explanation.txt ================================================ Let S[i] denote the distance of vertex i from source Let T[i] denote the distance of vertex i from the target We can determine both with a BFS. ----- void bfs(int source, vector &distance) { queue Q; Q.push(source); distance[source] = 0; while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(distance[child] >= oo) { distance[child] = distance[v] + 1; Q.push(child); } } } } ----- When we draw an edge between (x, y) the distance between (1, n) becomes S[x] + 1 + T[y] We will draw an edge so as to maximise this distance since we want to maximise the length of the shortest path. Ultimately the shortest path will not be more than S[n] Note that we can never increase the length of the shortest path. So we will choose the edge which maximises the length (S[x] + 1 + T[y]) We can sort the vertices according to S[x] - T[x] Since (S[x] + T[y] < S[y] + T[x]). As we visit the vertices in order, for every i, we will take the prefix maximum of T[i] ----- int main() { int no_of_vertices, no_of_edges, no_of_special_vertices; cin >> no_of_vertices >> no_of_edges >> no_of_special_vertices; vector special_vertices(no_of_special_vertices); for(int i = 0; i < no_of_special_vertices; i++) { cin >> special_vertices[i]; } for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } vector distance_1(no_of_vertices + 1, oo); bfs(1, distance_1); vector distance_n(no_of_vertices + 1, oo); bfs(no_of_vertices, distance_n); sort(special_vertices.begin(), special_vertices.end(), [&] (int a, int b) { return (distance_1[a] - distance_n[a] < distance_1[b] - distance_n[b]); }); int maximum_distance = 0; int furthest_1 = distance_1[special_vertices[0]]; for(int i = 1; i < no_of_special_vertices; i++) { maximum_distance = max(maximum_distance, furthest_1 + distance_n[special_vertices[i]] + 1); furthest_1 = max(furthest_1, distance_1[special_vertices[i]]); } maximum_distance = min(maximum_distance, distance_n[1]); cout << maximum_distance << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Explanations/Cow and Friend Explanation.txt ================================================ First of all, if x exists in the original array, then the answer is 1. If there is at least one element A[i] such that is 2A[i]>= x, then we can reach in 2 moves by making a triangle. If even the greatest element x 2 < x, then we will keep on making linear steps of length A[i] till x is within A[i]'s range. Then if x = A[i], we will take a linear step. Otherwise, we will make a triangle. It is important to check if x [0, 2A[i]] as 2A[i] is the furthest we can get using A[i] ----- void solve() { int no_of_elements; long long distance; cin >> no_of_elements >> distance; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } sort(all(A)); if(binary_search(all(A), distance)) { cout << "1\n"; return; } for(int i = 0; i < no_of_elements; i++) { if(A[i] + A[i] >= distance) { cout << "2\n"; return; } } long long steps = distance/A[no_of_elements - 1] + (distance%A[no_of_elements - 1] != 0); cout << steps << "\n"; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Explanations/Cow and Haybales Explanation.txt ================================================ We can simulate the process. One by one, we will carry the i-th element over to A[2] and then transfer it to A[1] ----- void solve() { int no_of_elements, no_of_days; cin >> no_of_elements >> no_of_days; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; for(int i = 2; i <= no_of_elements && no_of_days > 0; i++) { while(A[i] > 0 && no_of_days >= (i - 1)) { A[i]--; A[1]++; no_of_days -= (i - 1); } } cout << A[1] << "\n"; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Explanations/Cow and Message Explanation.txt ================================================ Observation - The number of good strings will be equal to the number of pairs and single letters. Proof - It is clear that every single letter is good. Every good string of length > 1, has 2 letters at the beginning So, there is a bijection in between the starting pair of any good string and the rest of the string. Why cannot the same argument be used to reduce 2 -> 1 ? It is because of the property of arithmetic series. The difference has to form an arithmetic progression so the first pair uniquely determine the rest of the string. Whereas, when we look at pairs, they do not correspond to single digits because a single digit by itself does not have any series and can be added to any digit through the entire array. ----- int main() { string S; cin >> S; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS, 0); map pair_frequency; for(int i = S.size() - 1; i >= 0; i--) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { char second_letter = (char)('a' + alpha); string current_pair; current_pair += S[i]; current_pair += second_letter; pair_frequency[current_pair] += frequency[alpha]; } frequency[S[i] - 'a']++; } long long answer = 0; for(auto it = pair_frequency.begin(); it != pair_frequency.end(); it++) { answer = max(answer, it->second); } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { answer = max(answer, frequency[alpha]); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Explanations/Cows and Treats Explanation.txt ================================================ 1. At most 2 cows can come and at most 1 from each side, one from the left, one from the right. 2. Suppose I know that cows {1, 3, 5} are there in the left set. They can only be placed in 1 combination and cannot be changed. Because once one of the cows come, they will block the other cows. 3. We need to iterate over all possibilities. We can do this by iterating on the grass where the left border ends. This will enable us to do the counting. We will see for each sweetness, the possible endings of cows of that sweetness both on the left and right side ----- We will count the number of cows that can go inside the left border. Let it be L We will count the number of cows that can go inside the right border. Let it be R. Then the number of pairs will be L*R - min(L, R) The reason is that the same cow cannot go both on the left and on the right. So, whichever is minimum among (L, R), those are cows which go on both sides and they can only go in one. ----- int main() { int no_of_grass, no_of_cows; cin >> no_of_grass >> no_of_cows; vector sweetness(no_of_grass + 1); for(int i = 1; i <= no_of_grass; i++) { cin >> sweetness[i]; } vector > cows(no_of_grass + 1); for(int i = 1; i <= no_of_cows; i++) { int sweet, hunger; cin >> sweet >> hunger; cows[sweet].push_back(hunger); } for(int i = 1; i <= no_of_grass; i++) { sort(cows[i].begin(), cows[i].end()); } const int MOD = 1e9 + 7; int happy_cows = 0; long long no_of_ways = 1; for(int cut = 0; cut <= no_of_grass; cut++) { vector left(no_of_grass + 1, 0); vector right(no_of_grass + 1, 0); for(int i = 1; i <= cut; i++) { left[sweetness[i]]++; } for(int i = cut + 1; i <= no_of_grass; i++) { right[sweetness[i]]++; } int left_ending = (cut == 0 ? -1 : sweetness[cut]); int happy_cows_here = 0; long long no_of_ways_here = 1; for(int i = 1; i <= no_of_grass; i++) { if(i == left_ending) { if(binary_search(cows[i].begin(), cows[i].end(), left[i])) { happy_cows_here++; } else { happy_cows_here = 0; break; } int right_choices = 0; for(int j = 0; j < cows[i].size(); j++) { if(cows[i][j] != left[i] && cows[i][j] <= right[i]) { right_choices++; } } if(right_choices >= 1) { happy_cows_here++; no_of_ways_here *= right_choices; } } else { int left_choices = 0, right_choices = 0; for(int j = 0; j < cows[i].size(); j++) { if(cows[i][j] <= left[i]) { left_choices++; } if(cows[i][j] <= right[i]) { right_choices++; } } int no_of_pairs = (left_choices*right_choices) - min(left_choices, right_choices); if(no_of_pairs > 0) { happy_cows_here += 2; no_of_ways_here *= no_of_pairs; } else if(left_choices > 0 || right_choices > 0) { happy_cows_here++; no_of_ways_here *= (left_choices + right_choices); } } no_of_ways_here %= MOD; } if(happy_cows_here > happy_cows) { happy_cows = happy_cows_here; no_of_ways = no_of_ways_here; } else if(happy_cows_here == happy_cows && happy_cows_here > 0) { no_of_ways += no_of_ways_here; no_of_ways %= MOD; } } cout << happy_cows << " " << no_of_ways << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Programs/Cow and Fields.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 5e5 + 5, oo = 1e9 + 9; vector graph[MAX_N]; void bfs(int source, vector &distance) { queue Q; Q.push(source); distance[source] = 0; while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(distance[child] >= oo) { distance[child] = distance[v] + 1; Q.push(child); //cout << "Child = " << child << " Distance = " << distance[child] << "\n"; } } } } int main() { int no_of_vertices, no_of_edges, no_of_special_vertices; cin >> no_of_vertices >> no_of_edges >> no_of_special_vertices; vector special_vertices(no_of_special_vertices); for(int i = 0; i < no_of_special_vertices; i++) { cin >> special_vertices[i]; } for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } vector distance_1(no_of_vertices + 1, oo); bfs(1, distance_1); vector distance_n(no_of_vertices + 1, oo); bfs(no_of_vertices, distance_n); sort(special_vertices.begin(), special_vertices.end(), [&] (int a, int b) { return (distance_1[a] - distance_n[a] < distance_1[b] - distance_n[b]); }); int maximum_distance = 0; int furthest_1 = distance_1[special_vertices[0]]; for(int i = 1; i < no_of_special_vertices; i++) { maximum_distance = max(maximum_distance, furthest_1 + distance_n[special_vertices[i]] + 1); //cout << special_vertices[i] << "\n"; //cout << "Distance n = " << distance_n[special_vertices[i]] << " Furthest 1 = " << furthest_1 << "\n"; //cout << "Maximum Distance = " << maximum_distance << "\n"; furthest_1 = max(furthest_1, distance_1[special_vertices[i]]); } maximum_distance = min(maximum_distance, distance_n[1]); cout << maximum_distance << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Programs/Cow and Haybales.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, no_of_days; cin >> no_of_elements >> no_of_days; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; for(int i = 2; i <= no_of_elements && no_of_days > 0; i++) { while(A[i] > 0 && no_of_days >= (i - 1)) { A[i]--; A[1]++; no_of_days -= (i - 1); } } cout << A[1] << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Programs/Cow and Message.cpp ================================================ #include #include #include using namespace std; int main() { string S; cin >> S; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS, 0); map pair_frequency; for(int i = S.size() - 1; i >= 0; i--) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { char second_letter = (char)('a' + alpha); string current_pair; current_pair += S[i]; current_pair += second_letter; pair_frequency[current_pair] += frequency[alpha]; //cout << "Pair = " << current_pair << " Second Frequency = " << frequency[alpha] << "\n"; } frequency[S[i] - 'a']++; } long long answer = 0; for(auto it = pair_frequency.begin(); it != pair_frequency.end(); it++) { answer = max(answer, it->second); } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { answer = max(answer, frequency[alpha]); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/621 Div 1 + 2/Programs/Cows and Treats.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_grass, no_of_cows; cin >> no_of_grass >> no_of_cows; vector sweetness(no_of_grass + 1); for(int i = 1; i <= no_of_grass; i++) { cin >> sweetness[i]; } vector > cows(no_of_grass + 1); for(int i = 1; i <= no_of_cows; i++) { int sweet, hunger; cin >> sweet >> hunger; cows[sweet].push_back(hunger); } for(int i = 1; i <= no_of_grass; i++) { sort(cows[i].begin(), cows[i].end()); } const int MOD = 1e9 + 7; int happy_cows = 0; long long no_of_ways = 1; for(int cut = 0; cut <= no_of_grass; cut++) { vector left(no_of_grass + 1, 0); vector right(no_of_grass + 1, 0); for(int i = 1; i <= cut; i++) { left[sweetness[i]]++; } for(int i = cut + 1; i <= no_of_grass; i++) { right[sweetness[i]]++; } int left_ending = (cut == 0 ? -1 : sweetness[cut]); int happy_cows_here = 0; long long no_of_ways_here = 1; for(int i = 1; i <= no_of_grass; i++) { if(i == left_ending) { if(binary_search(cows[i].begin(), cows[i].end(), left[i])) { happy_cows_here++; } else { happy_cows_here = 0; break; } int right_choices = 0; for(int j = 0; j < cows[i].size(); j++) { if(cows[i][j] != left[i] && cows[i][j] <= right[i]) { right_choices++; } } if(right_choices >= 1) { //cout << "Left = " << left[i] << "\n"; //cout << "Right Choices = " << right_choices << "\n"; happy_cows_here++; no_of_ways_here *= right_choices; } } else { int left_choices = 0, right_choices = 0; for(int j = 0; j < cows[i].size(); j++) { if(cows[i][j] <= left[i]) { left_choices++; } if(cows[i][j] <= right[i]) { right_choices++; } } //cout << "Sweetness = " << i << " L = " << left_choices << " R = " << right_choices << "\n"; int no_of_pairs = (left_choices*right_choices) - min(left_choices, right_choices); if(no_of_pairs > 0) { happy_cows_here += 2; no_of_ways_here *= no_of_pairs; } else if(left_choices > 0 || right_choices > 0) { happy_cows_here++; no_of_ways_here *= (left_choices + right_choices); //cout << "Reached and No of Ways = " << no_of_ways_here << "\n"; } } no_of_ways_here %= MOD; } if(happy_cows_here > happy_cows) { happy_cows = happy_cows_here; no_of_ways = no_of_ways_here; } else if(happy_cows_here == happy_cows && happy_cows_here > 0) { no_of_ways += no_of_ways_here; no_of_ways %= MOD; } //cout << "Cut = " << cut << " Maximum = " << happy_cows << " No of ways = " << no_of_ways << "\n"; } cout << happy_cows << " " << no_of_ways << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Explanations/Bad Ugly Numbers Explanation.txt ================================================ Let us think of the divisibility rules of each number. A number is divisible by 5 only if the last digit if 5 or 0 So, we can make every digit except the last = 5 What do we put as the last digit ? We will put 4, as a number is divisible by 4 if it's last 2 digits are a multiple of 4 and 54 is not a multiple of 4 ----- Another solution is that we can have a string of (n - 1) 3s and 1 2. Just avoid putting 2 in the last position This way the integer will not be even and the sum of digits = 2 (mod 3) so it will not be a multiple of 3 ----- void solve() { int n; cin >> n; if(n == 1) { cout << "-1\n"; return; } for(int i = 1; i <= n - 1; i++) { cout << "5"; } cout << "4\n"; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Explanations/Maximums Explanation.txt ================================================ We will just simulate the process. We will keep track of the maximum element in B[1, ... , i] A[i] = B[i] + prefix_max[i] ----- #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } vector A(no_of_elements + 1); vector prefix_max(no_of_elements + 5, 0); for(int i = 1; i <= no_of_elements; i++) { A[i] = B[i] + prefix_max[i]; prefix_max[i + 1] = max(prefix_max[i], A[i]); } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Explanations/Permutation Partitions Explanation.txt ================================================ Ultimately, the K greatest integers will be the best sum It is always possible to make segments in such a way the K greatest integers are chosen. Let us re-write the array and put a 1 if A[i] is one of the K greatest integers and a 0 otherwise Suppose we have 1 0 0 0 1 Now, here are the possible divisions 1 | 0 0 0 1 1 0 | 0 0 1 1 0 0 | 0 1 1 0 0 0 | 1 All of these divisions satisfy the condition ----- We will keep track of all the indices of the k greatest integers. Suppose the consecutive indices are I[i] and I[i + 1], then the i-th barrier has I[i] - I[i - 1] ways and the first barrier is at A[1] and the last barrier is at A[n] We will simply multiply the number of ways to place the other (K - 1) barriers ----- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long get_sum(long long n) { return (n*(n + 1))/2; } int main() { int no_of_elements, no_of_parts; cin >> no_of_elements >> no_of_parts; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector indices; for(int i = 1; i <= no_of_elements; i++) { if(A[i] > no_of_elements - no_of_parts) { indices.push_back(i); } } sort(all(indices)); long long best_sum = get_sum(no_of_elements) - get_sum(no_of_elements - no_of_parts); long long no_of_ways = 1; const long long MOD = 998244353; for(int i = 1; i < no_of_parts; i++) { no_of_ways *= (indices[i] - indices[i - 1]); no_of_ways %= MOD; } cout << best_sum << " " << no_of_ways << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Explanations/Prefix Suffix Palindrome (Easy Version) Explanation.txt ================================================ The optimal string consists of 1. Some set of matching prefix and suffix of the string 2. And then some palindrome that is either completely in the prefix or completely in the suffix. ----- First, we will find out the maximum matching part of the prefix and the suffix. Then, we will calculate the longest palindrome in both the prefix and the suffix using a DP ----- pair get_prefix_suffix(string S) { for(int length = 1; length <= S.size(); length++) { for(int left = 0, right = left + length - 1; right < S.size(); left++, right++) { max_palindrome_in[left][right] = 0; if(length == 1) { max_palindrome_in[left][right] = 1; continue; } if(length == 2) { max_palindrome_in[left][right] = (S[left] == S[right] ? 2 : 0); continue; } if(S[left] == S[right] && max_palindrome_in[left + 1][right - 1] != 0) { max_palindrome_in[left][right] = 2 + max_palindrome_in[left + 1][right - 1]; } } } int best_prefix = 0; for(int i = 0; i < S.size(); i++) { best_prefix = max(best_prefix, max_palindrome_in[0][i]); } int best_suffix = 0; for(int i = S.size() - 1; i >= 0; i--) { best_suffix = max(best_suffix, max_palindrome_in[i][S.size() - 1]); } return make_pair(best_prefix, best_suffix); } void solve() { string S; cin >> S; int matching_part = 0, prefix_palindrome = 0, suffix_palindrome = 0; for(int i = 0, j = S.size() - 1; i < j; i++, j--) { if(S[i] == S[j]) { matching_part++; } else { break; } } string remaining_S; for(int i = matching_part; i < S.size() - matching_part; i++) { remaining_S += S[i]; } //cout << "Remaining = " << remaining_S << "\n"; pair prefix_suffix = get_prefix_suffix(remaining_S); prefix_palindrome = prefix_suffix.first; suffix_palindrome = prefix_suffix.second; if(prefix_palindrome > suffix_palindrome) { suffix_palindrome = 0; } else { prefix_palindrome = 0; } string answer; for(int i = 0; i < matching_part; i++) { answer += S[i]; } for(int i = 0; i < prefix_palindrome; i++) { answer += remaining_S[i]; } for(int i = remaining_S.size() - suffix_palindrome; i < remaining_S.size(); i++) { answer += remaining_S[i]; } for(int i = S.size() - matching_part; i < S.size(); i++) { answer += S[i]; } cout << answer << "\n"; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Programs/Bad Ugly Numbers.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; if(n == 1) { cout << "-1\n"; return; } for(int i = 1; i <= n - 1; i++) { cout << "5"; } cout << "4\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Programs/Maximums.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } vector A(no_of_elements + 1); vector prefix_max(no_of_elements + 5, 0); for(int i = 1; i <= no_of_elements; i++) { A[i] = B[i] + prefix_max[i]; prefix_max[i + 1] = max(prefix_max[i], A[i]); } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Programs/Permutation Partitions.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long get_sum(long long n) { return (n*(n + 1))/2; } int main() { int no_of_elements, no_of_parts; cin >> no_of_elements >> no_of_parts; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector indices; for(int i = 1; i <= no_of_elements; i++) { if(A[i] > no_of_elements - no_of_parts) { indices.push_back(i); } } sort(all(indices)); long long best_sum = get_sum(no_of_elements) - get_sum(no_of_elements - no_of_parts); long long no_of_ways = 1; const long long MOD = 998244353; for(int i = 1; i < no_of_parts; i++) { no_of_ways *= (indices[i] - indices[i - 1]); no_of_ways %= MOD; } cout << best_sum << " " << no_of_ways << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/CodeForces Global Round 7/Programs/Prefix Suffix Palindrome (Easy Version).cpp ================================================ #include #include #include using namespace std; const int MAX_N = 5005; int max_palindrome_in[MAX_N][MAX_N]; pair get_prefix_suffix(string S) { for(int length = 1; length <= S.size(); length++) { for(int left = 0, right = left + length - 1; right < S.size(); left++, right++) { max_palindrome_in[left][right] = 0; if(length == 1) { max_palindrome_in[left][right] = 1; continue; } if(length == 2) { max_palindrome_in[left][right] = (S[left] == S[right] ? 2 : 0); continue; } if(S[left] == S[right] && max_palindrome_in[left + 1][right - 1] != 0) { max_palindrome_in[left][right] = 2 + max_palindrome_in[left + 1][right - 1]; } } } int best_prefix = 0; for(int i = 0; i < S.size(); i++) { best_prefix = max(best_prefix, max_palindrome_in[0][i]); } int best_suffix = 0; for(int i = S.size() - 1; i >= 0; i--) { best_suffix = max(best_suffix, max_palindrome_in[i][S.size() - 1]); } return make_pair(best_prefix, best_suffix); } void solve() { string S; cin >> S; int matching_part = 0, prefix_palindrome = 0, suffix_palindrome = 0; for(int i = 0, j = S.size() - 1; i < j; i++, j--) { if(S[i] == S[j]) { matching_part++; } else { break; } } string remaining_S; for(int i = matching_part; i < S.size() - matching_part; i++) { remaining_S += S[i]; } //cout << "Remaining = " << remaining_S << "\n"; pair prefix_suffix = get_prefix_suffix(remaining_S); prefix_palindrome = prefix_suffix.first; suffix_palindrome = prefix_suffix.second; if(prefix_palindrome > suffix_palindrome) { suffix_palindrome = 0; } else { prefix_palindrome = 0; } string answer; for(int i = 0; i < matching_part; i++) { answer += S[i]; } for(int i = 0; i < prefix_palindrome; i++) { answer += remaining_S[i]; } for(int i = remaining_S.size() - suffix_palindrome; i < remaining_S.size(); i++) { answer += remaining_S[i]; } for(int i = S.size() - matching_part; i < S.size(); i++) { answer += S[i]; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Explanations/Kuroni and Impossible Calculation Explanation.txt ================================================ If there are two integers A[i] and A[j] such that (A[i] = A[j] (mod m)) Then (A[i] - A[j] = 0) (mod m) There are only m possible remainders mod m = {0, 1, ... , m - 1} By the Pigeonhole Principle, if there are more than m integers, at least 2 will have the same remainder. This means, the answer will be 0 as 1 term (A[i] - A[j]) = 0 (mod m) ----- If there are less than m terms, then there are less than 1000 terms and we can find the answer in O(n^2) time #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, modulo; cin >> no_of_elements >> modulo; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } if(no_of_elements > modulo) { cout << "0\n"; return 0; } long long product = 1; for(int i = 1; i <= no_of_elements; i++) { for(int j = i + 1; j <= no_of_elements; j++) { product *= abs(A[i] - A[j]); product %= modulo; } } cout << product << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Explanations/Kuroni and Punishment Explanation.txt ================================================ Firstly, we will notice that the answer will never be more than N. We can always use at most one move for each element and make them all even. So, the answer is always <= N ------ If the answer is < N, then at least one element is unchanged. This means that the final gcd will be a divisor of one of the original no_of_elements The number of distinct divisors will not be too many. Unfortunately, we do not have enough time to factorise all the integers. Instead, we will randomly pick around 100 of them and take all the distinct prime factors of (A[i] - 1, A[i], A[i] + 1) ------ 1. Ultimately we will change each element by some amount 2. We can always just make every integer even. This means that the total change is at most N. 3. If the total change <= N, then how many elements change by more than 1 ? At most N/2 element change by more than 1 ! In other words, at least N/2 elements change by at most 1 4. That means there are at least N/2 elements for which the 'best' factor is a divisor is one of the divisors of (A[I] - 1, A[I], A[I] + 1) 5. There are two types of elements - Those that change by at most 1 and those that change by more than 1. There are at least N/2 of the former. The probability of a random element belonging to the first set is at least 1/2 If we sample 100 elements randomly, the probability is 1/2^{100} ------ #include #include #include #include #include using namespace std; void factorise(set &F, long long n) { if(n <= 1) { return; } //cout << "N = " << n << "\n"; for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { F.insert(i); while(n%i == 0) { n /= i; } } } if(n > 1) { F.insert(n); } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_TRIES = 100; random_shuffle(A.begin() + 1, A.end()); set factors; for(int i = 1; i <= MAX_TRIES && i <= no_of_elements; i++) { factorise(factors, A[i]); factorise(factors, A[i] - 1); factorise(factors, A[i] + 1); } long long minimum_moves = no_of_elements; for(auto it = factors.begin(); it != factors.end(); it++) { long long x = *it; //cout << "X = " << x << "\n"; long long moves_here = 0; for(int i = 1; i <= no_of_elements; i++) { long long moves_for_this_elements = (x - A[i]%x); if(A[i] >= x) { moves_for_this_elements = min(moves_for_this_elements, A[i]%x); } moves_here += moves_for_this_elements; //cout << "Moves = " << moves_for_this_elements << "\n"; } minimum_moves = min(minimum_moves, moves_here); } cout << minimum_moves << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Explanations/Kuroni and Simple Strings Explanation.txt ================================================ It is best to be greedy. We will remove '(' from the left. And for each '(', we will look for an ')', as much to the right as possible We will do as many such 'sweeps' as we can While printing it, we will sort the indices in each 'sweep' ----- #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { string S; cin >> S; vector >indices; vector available(S.size() + 1, true); for(int attempts = 1; attempts <= S.size(); attempts++) { vector indices_here; for(int front = 0, back = S.size() - 1; front < back;) { while(true) { if(front >= back) { break; } if(!available[front] || S[front] != '(') { front++; continue; } break; } if(front >= back || S[front] != '(') { break; } while(true) { if(back <= front) { break; } if(!available[back] || S[back] != ')') { back--; continue; } break; } if(back <= front || S[back] != ')') { break; } available[front] = false; available[back] = false; indices_here.push_back(front + 1); indices_here.push_back(back + 1); } if(indices_here.size() > 0) { indices.push_back(indices_here); } } cout << indices.size() << "\n"; for(int i = 0; i < indices.size(); i++) { cout << indices[i].size() << "\n"; sort(all(indices[i])); for(int j = 0; j < indices[i].size(); j++) { cout << indices[i][j] << " "; } cout << "\n"; } return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Explanations/Kuroni and the Celebration Explanation.txt ================================================ Let us keep all the leaves in a vector. We will pick out two leaves u and v and query their LCA If LCA(u, v) = u or v, then u or v is the root of the tree If LCA(u, v) = w and w =/= u and w =/= v, then we will erase all vertices in the path from (u, w) and all vertices in the path from (v, w) In the process of doing this if w becomes a leaf, we will add it to our vector. If at any point, the leaf vector has only 1 element, then it will be the root. In every query, the size of the tree reduces by at least 2. So, the number of queries will not exceed (n/2) ----- vector > tree; set leaves; void erase_till(int v, int child, int destination) { if(leaves.find(v) != leaves.end()) { leaves.erase(v); } for(auto it = tree[v].begin(); it != tree[v].end(); it++) { int parent = *it; if(parent == child) { continue; } if(parent == destination) { tree[destination].erase(v); continue; } if(tree[parent].size() > 0) { erase_till(parent, v, destination); } } tree[v].clear(); } int main() { int no_of_vertices; cin >> no_of_vertices; tree.resize(no_of_vertices + 1); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].insert(v); tree[v].insert(u); } for(int v = 1; v <= no_of_vertices; v++) { if(tree[v].size() == 1) { leaves.insert(v); } } int root = 0; while(leaves.size() > 1) { int u = *(leaves.begin()); leaves.erase(u); int v = *(leaves.begin()); leaves.erase(v); int w; cout << "? " << u << " " << v << "\n" << flush; cin >> w; if(w == u || w == v) { root = w; break; } erase_till(u, 0, w); erase_till(v, 0, w); if(tree[w].size() <= 1) { leaves.insert(w); } } if(root == 0) { root = *(leaves.begin()); } cout << "! " << root << "\n" << flush; return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Explanations/Kuroni and the Gifts Explanation.txt ================================================ The elements of both A and B are distinct. The smallest possible sum is A[1] + B[1] We will sort the elements and (A[i] + B[i]) as each element. As (A[i + 1] > A[i]) and (B[i + 1] > B[i]), this means (A[i + 1] + B[i + 1]) > (A[i] + B[i]) This helps us prove that the entire array is distinct ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } sort(all(B)); for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; for(int i = 1; i <= no_of_elements; i++) { cout << B[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Programs/Kuroni and Impossible Calculation.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, modulo; cin >> no_of_elements >> modulo; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } if(no_of_elements > modulo) { cout << "0\n"; return 0; } long long product = 1; for(int i = 1; i <= no_of_elements; i++) { for(int j = i + 1; j <= no_of_elements; j++) { product *= abs(A[i] - A[j]); product %= modulo; } } cout << product << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Programs/Kuroni and Punishment.cpp ================================================ #include #include #include #include #include using namespace std; void factorise(set &F, long long n) { if(n <= 1) { return; } //cout << "N = " << n << "\n"; for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { F.insert(i); while(n%i == 0) { n /= i; } } } if(n > 1) { F.insert(n); } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_TRIES = 100; random_shuffle(A.begin() + 1, A.end()); set factors; for(int i = 1; i <= MAX_TRIES && i <= no_of_elements; i++) { factorise(factors, A[i]); factorise(factors, A[i] - 1); factorise(factors, A[i] + 1); } long long minimum_moves = no_of_elements; for(auto it = factors.begin(); it != factors.end(); it++) { long long x = *it; //cout << "X = " << x << "\n"; long long moves_here = 0; for(int i = 1; i <= no_of_elements; i++) { long long moves_for_this_elements = (x - A[i]%x); if(A[i] >= x) { moves_for_this_elements = min(moves_for_this_elements, A[i]%x); } moves_here += moves_for_this_elements; //cout << "Moves = " << moves_for_this_elements << "\n"; } minimum_moves = min(minimum_moves, moves_here); } cout << minimum_moves << "\n"; return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Programs/Kuroni and Simple Strings.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { string S; cin >> S; vector >indices; vector available(S.size() + 1, true); for(int attempts = 1; attempts <= S.size(); attempts++) { vector indices_here; for(int front = 0, back = S.size() - 1; front < back;) { while(true) { if(front >= back) { break; } if(!available[front] || S[front] != '(') { front++; continue; } break; } if(front >= back || S[front] != '(') { break; } while(true) { if(back <= front) { break; } if(!available[back] || S[back] != ')') { back--; continue; } break; } if(back <= front || S[back] != ')') { break; } available[front] = false; available[back] = false; indices_here.push_back(front + 1); indices_here.push_back(back + 1); } if(indices_here.size() > 0) { indices.push_back(indices_here); } } cout << indices.size() << "\n"; for(int i = 0; i < indices.size(); i++) { cout << indices[i].size() << "\n"; sort(all(indices[i])); for(int j = 0; j < indices[i].size(); j++) { cout << indices[i][j] << " "; } cout << "\n"; } return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Programs/Kuroni and the Celebration.cpp ================================================ #include #include #include using namespace std; vector > tree; set leaves; void erase_till(int v, int child, int destination) { if(leaves.find(v) != leaves.end()) { leaves.erase(v); } for(auto it = tree[v].begin(); it != tree[v].end(); it++) { int parent = *it; if(parent == child) { continue; } if(parent == destination) { tree[destination].erase(v); continue; } if(tree[parent].size() > 0) { erase_till(parent, v, destination); } } tree[v].clear(); } int main() { int no_of_vertices; cin >> no_of_vertices; tree.resize(no_of_vertices + 1); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].insert(v); tree[v].insert(u); } for(int v = 1; v <= no_of_vertices; v++) { if(tree[v].size() == 1) { leaves.insert(v); } } int root = 0; while(leaves.size() > 1) { int u = *(leaves.begin()); leaves.erase(u); int v = *(leaves.begin()); leaves.erase(v); int w; cout << "? " << u << " " << v << "\n" << flush; cin >> w; if(w == u || w == v) { root = w; break; } erase_till(u, 0, w); erase_till(v, 0, w); if(tree[w].size() <= 1) { leaves.insert(w); } } if(root == 0) { root = *(leaves.begin()); } cout << "! " << root << "\n" << flush; return 0; } ================================================ FILE: 2020/Combined Divisions/Ozone Tech Challenge 2020/Programs/Kuroni and the Gifts.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } sort(all(B)); for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; for(int i = 1; i <= no_of_elements; i++) { cout << B[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while (no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/606 Div 2 Technocup 2020 Elimination Round 4/Explanations/As Simple as One and Two Explanation.txt ================================================ We will make 2 passes through the string. 1. In Pass 1, we will remove all the 'o' which are common to both "one" and "two". 2. In Pass 2, we will remove any one of the letters for either "one" or "two". ----- void solve() { string S; cin >> S; vector answer; for(int i = 4; i < S.size(); i++) { if(S[i] == 'e' and S[i - 1] == 'n' and S[i - 2] == 'o' and S[i - 3] == 'w' and S[i - 4] == 't') { S[i - 2] = 'x'; answer.push_back(i - 2 + 1); } } for(int i = 2; i < S.size(); i++) { if(S[i] == 'o' and S[i - 1] == 'w' && S[i - 2] == 't') { answer.push_back(i - 1 + 1); } if(S[i] == 'e' and S[i - 1] == 'n' && S[i - 2] == 'o') { answer.push_back(i - 1 + 1); } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 2/606 Div 2 Technocup 2020 Elimination Round 4/Explanations/Happy Birthday Polycarp Explanation.txt ================================================ If the number has d digits, then all strings upto length (d - 1) are automatically good. So the answer is initially 9(d - 1). We will try all 9 D digit numbers and check how many of them are < n. ----- int no_of_digits(int n) { int digits = 0; while(n > 0) { n /= 10; digits++; } return digits; } void solve() { int n; cin >> n; int answer = 9*(no_of_digits(n) - 1); for(int i = 1, x = 0; i <= 9; i++) { x = 0; for(int d = 1; d <= no_of_digits(n); d++) { x = x*10 + i; } if(x > n) { break; } answer++; } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/606 Div 2 Technocup 2020 Elimination Round 4/Explanations/Make Them Odd Explanation.txt ================================================ In every step, we will keep dividing the largest element till it becomes odd. Use a set to hit only distinct elements. This also takes care of the situation when x/2 is already there in the array. ------ void solve() { int no_of_elements; cin >> no_of_elements; set S; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; if(x%2 == 0) { S.insert(x); } } int no_of_steps = 0; while(!S.empty()) { int maximum = *(S.rbegin()); while(maximum%2 == 0) { if(S.find(maximum) != S.end()) { S.erase(S.find(maximum)); } maximum /= 2; no_of_steps++; } } cout << no_of_steps << "\n"; } ================================================ FILE: 2020/Div 2/606 Div 2 Technocup 2020 Elimination Round 4/Programs/As Simple as One and Two.cpp ================================================ #include #include using namespace std; void solve() { string S; cin >> S; vector answer; for(int i = 4; i < S.size(); i++) { if(S[i] == 'e' and S[i - 1] == 'n' and S[i - 2] == 'o' and S[i - 3] == 'w' and S[i - 4] == 't') { S[i - 2] = 'x'; answer.push_back(i - 2 + 1); } } for(int i = 2; i < S.size(); i++) { if(S[i] == 'o' and S[i - 1] == 'w' && S[i - 2] == 't') { answer.push_back(i - 1 + 1); } if(S[i] == 'e' and S[i - 1] == 'n' && S[i - 2] == 'o') { answer.push_back(i - 1 + 1); } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/606 Div 2 Technocup 2020 Elimination Round 4/Programs/Happy Birthday Polycarp.cpp ================================================ #include using namespace std; int no_of_digits(int n) { int digits = 0; while(n > 0) { n /= 10; digits++; } return digits; } void solve() { int n; cin >> n; int answer = 9*(no_of_digits(n) - 1); for(int i = 1, x = 0; i <= 9; i++) { x = 0; for(int d = 1; d <= no_of_digits(n); d++) { x = x*10 + i; } if(x > n) { break; } answer++; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/606 Div 2 Technocup 2020 Elimination Round 4/Programs/Make Them Odd.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; set S; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; if(x%2 == 0) { S.insert(x); } } int no_of_steps = 0; while(!S.empty()) { int maximum = *(S.rbegin()); while(maximum%2 == 0) { if(S.find(maximum) != S.end()) { S.erase(S.find(maximum)); } maximum /= 2; no_of_steps++; } } cout << no_of_steps << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Explanations/Domino for Young Explanation.txt ================================================ We can think of it as a chessboard.Each domino covers one square of each colour. The answer is whichever is minimum - black or white squares. ----- #include using namespace std; int main() { int no_of_columns; cin >> no_of_columns; long long black = 0, white = 0; for(int i = 1; i <= no_of_columns; i++) { int no_of_rows; cin >> no_of_rows; black += (no_of_rows/2) + (no_of_rows%2 == 1 && i%2 == 0); white += (no_of_rows/2) + (no_of_rows%2 == 1 && i%2 == 1); } long long dominos = min(black, white); cout << dominos << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Explanations/Equation Explanation.txt ================================================ We can just print 9n and 8n. gcd(8, 9) = 1 and 9n - 8n = 1 ----- #include using namespace std; int main() { int n; cin >> n; cout << 9*n << " " << 8*n << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Explanations/Long Beautiful Integer Explanation.txt ================================================ The first k characters determine the entire string. We will first set B[i] = B[i%k] for every i. If B >= A like this, then we are done. This is the smallest beautiful integer as it matches the longest prefix. Otherwise if B < A, then, we will look at the last digit which is not 9 in the prefix. We will increment it and make all the 9's from there till k = 0 Now, B > A and has the longest matching prefix. ----- #include #include using namespace std; int main() { int no_of_digits, k; string S; cin >> no_of_digits >> k >> S; string answer = S; for(int i = k; i < no_of_digits; i++) { answer[i] = answer[i%k]; } int is_lesser = false; for(int i = 0; i < no_of_digits; i++) { if(answer[i] > S[i]) { break; } if(answer[i] < S[i]) { is_lesser = true; break; } } if(!is_lesser) { cout << no_of_digits << "\n" << answer << "\n"; return 0; } int change_point = -1; for(int i = k - 1; i >= 0; i--) { if(S[i] != '9') { change_point = i; answer[i] = answer[i] + 1; break; } } for(int i = change_point + 1; change_point != -1 && i < k; i++) { answer[i] = '0'; } for(int i = k; i < no_of_digits; i++) { answer[i] = answer[i%k]; } cout << no_of_digits << "\n" << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Explanations/Modulo Equality Explanation.txt ================================================ Let us check all possible candidates that we can add to A to make it equal to B. When A = B, then A[1] is equal to some element in B. We will iterate over all B, and check if x = (B[i] - A[1]) satisfies the condition. We will add x to the entire array A and then check if A = B. This can be done by comparing the sorted arrays A and B. ----- int add_and_check_equality(vector A, vector B, int m, int x) { for(int i = 1; i < A.size(); i++) { A[i] = (A[i] + x)%m; } sort(all(A)); for(int i = 1; i < B.size(); i++) { if(A[i] != B[i]) { return false; } } return true; } int main() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; A[i] %= m; } vector B(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; B[i] %= m; } sort(all(B)); int minimum_moves = m; for(int i = 1; i <= no_of_elements; i++) { int to_add = (B[i] - A[1] + m)%m; if(add_and_check_equality(A, B, m, to_add)) { minimum_moves = min(minimum_moves, to_add); } } cout << minimum_moves << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Programs/Domino for Young.cpp ================================================ #include using namespace std; int main() { int no_of_columns; cin >> no_of_columns; long long black = 0, white = 0; for(int i = 1; i <= no_of_columns; i++) { int no_of_rows; cin >> no_of_rows; black += (no_of_rows/2) + (no_of_rows%2 == 1 && i%2 == 0); white += (no_of_rows/2) + (no_of_rows%2 == 1 && i%2 == 1); } long long dominos = min(black, white); cout << dominos << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Programs/Equation.cpp ================================================ #include using namespace std; int main() { int n; cin >> n; cout << 9*n << " " << 8*n << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Programs/Long Beautiful Integer.cpp ================================================ #include #include using namespace std; int main() { int no_of_digits, k; string S; cin >> no_of_digits >> k >> S; string answer = S; for(int i = k; i < no_of_digits; i++) { answer[i] = answer[i%k]; } int is_lesser = false; for(int i = 0; i < no_of_digits; i++) { if(answer[i] > S[i]) { break; } if(answer[i] < S[i]) { is_lesser = true; break; } } if(!is_lesser) { cout << no_of_digits << "\n" << answer << "\n"; return 0; } int change_point = -1; for(int i = k - 1; i >= 0; i--) { if(S[i] != '9') { change_point = i; answer[i] = answer[i] + 1; break; } } for(int i = change_point + 1; change_point != -1 && i < k; i++) { answer[i] = '0'; } for(int i = k; i < no_of_digits; i++) { answer[i] = answer[i%k]; } cout << no_of_digits << "\n" << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/609 Div 2/Programs/Modulo Equality.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int add_and_check_equality(vector A, vector B, int m, int x) { for(int i = 1; i < A.size(); i++) { A[i] = (A[i] + x)%m; } sort(all(A)); for(int i = 1; i < B.size(); i++) { if(A[i] != B[i]) { return false; } } return true; } int main() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; A[i] %= m; } vector B(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; B[i] %= m; } sort(all(B)); int minimum_moves = m; for(int i = 1; i <= no_of_elements; i++) { int to_add = (B[i] - A[1] + m)%m; if(add_and_check_equality(A, B, m, to_add)) { minimum_moves = min(minimum_moves, to_add); } } cout << minimum_moves << "\n"; return 0; } ================================================ FILE: 2020/Div 2/612 Div 2/Explanations/Angry Students Explanation.txt ================================================ The prefix of P's will not be changed. For every other P, the amount of time taken to change it is equal to the distance of the leftmost A. We can compute this in one linear sweep. ----- void solve() { int length; string S; cin >> length >> S; const int oo = 1e7; vector nearest_a(length + 1, oo); nearest_a[0] = (S[0] == 'A' ? 0 : oo); for(int i = 1; i < length; i++) { nearest_a[i] = (S[i] == 'A' ? 0 : nearest_a[i - 1] + 1); } int answer = 0; for(int i = 0; i < length; i++) { //Skip the prefix if(nearest_a[i] >= oo) { continue; } answer = max(answer, nearest_a[i]); } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/612 Div 2/Explanations/Hyperset Explanation.txt ================================================ Let us notice something. Suppose we fix 2 strings A and B. There can only be 1 string C, such that (A, B, C) is a set. For each of the K positions, if A[i] = B[i], then C[i] also has to be = A[i] If A[i] != B[i], then C[i] must be the third character not equal to both (A[i], B[i]). ----- Let us iterate over every pair of strings. The third string C is only one. For every pair (A[i], A[j]), add the frequency of Complement(A[i], A[j]) to the answer. The only observation is that every triplet (A, B, C) is counted three times. 1. When we fix (A, B) 2. When we fix (B, C) 3. When we fix (C, A) So, we will divide the number of triplets by 3. ---- We need to notice something. What about identical triplets - when all three strings are the same - (A, A, A) ? If we add it in the same way, then we will be counting such triplets 6 times. When we fix (A, A) and add frequency of Complement(A, A) = A to the answer, the answer overcounts by 2. Each such triplet is counted 3x2 = 6 times. That is why, in my solution I count same triplets first, and then different triplets seperately. ---- Note that we do not have to deal with the condition where A = B =/= C because of the definition of the triplet :) ---- char get_third(char a, char b) { switch(a) { case 'S' : return (b == 'E' ? 'T' : 'E'); case 'E' : return (b == 'T' ? 'S' : 'T'); case 'T' : return (b == 'S' ? 'E' : 'S'); } return 0; } long long choose_3(long long n) { long long numerator = n*(n - 1)*(n - 2); long long denominator = 3*2*1; return numerator/denominator; } int main() { int no_of_cards, no_of_features; cin >> no_of_cards >> no_of_features; vector card(no_of_cards + 1); map frequency; for(int i = 1; i <= no_of_cards; i++) { cin >> card[i]; frequency[card[i]]++; } long long same_triplets = 0; for(auto it = frequency.begin(); it != frequency.end(); it++) { same_triplets += choose_3(it->second); } long long different_triplets = 0; for(int i = 1; i <= no_of_cards; i++) { for(int j = i + 1; j <= no_of_cards; j++) { if(card[i] == card[j]) { continue; } string complement; for(int k = 0; k < no_of_features; k++) { if(card[i][k] == card[j][k]) { complement += card[i][k]; } else { complement += get_third(card[i][k], card[j][k]); } } different_triplets += frequency[complement]; } } different_triplets /= 3; long long no_of_triplets = same_triplets + different_triplets; cout << no_of_triplets << "\n"; return 0; } ================================================ FILE: 2020/Div 2/612 Div 2/Explanations/Madhouse (Easy Version) Explanation.txt ================================================ Let us do this. Since we are given random permutations of every substring, we will collect a vector of length 26 denoting the frequency of each of the alphabets instead of the actual string. We will first get all the substrings of length [1, n]. We will then get all the substrings of length [2, n]. We will store all the vectors of length 26 inside a multiset. We will delete all the vectors from [2, n] that are present. This leaves us with n substrings - [1, 1], [1, 2], [1, 3], ... , [1, n]. ---- Notice that [1, 1] is the only letter. To get the second letter, we must search for which letter is there in [1, 2] but not in [1, 1]. Similarly, we will repeat this process. To get the i-th alphabet, we will search for which letter is there in [1, i] but not there in [1, i - 1]. ----- int sort_by_frequency(vector &A, vector &B) { const int NO_OF_ALPHABETS = 26; int a_sum = 0, b_sum = 0; for(int i = 0; i < NO_OF_ALPHABETS; i++) { a_sum += A[i]; b_sum += B[i]; } return (b_sum > a_sum); } int main() { int length; cin >> length; const int NO_OF_ALPHABETS = 26; cout << "? 1 " << length << endl; multiset >subarray; for(int i = 1; i <= length; i++) { for(int j = i; j <= length; j++) { string S; cin >> S; if(length == 1) { cout << "! " << S << endl; return 0; } vector frequency(NO_OF_ALPHABETS, 0); for(int k = 0; k < S.size(); k++) { frequency[S[k] - 'a']++; } subarray.insert(frequency); } } cout << "? 2 " << length << endl; for(int i = 2; i <= length; i++) { for(int j = i; j <= length; j++) { string S; cin >> S; vector frequency(NO_OF_ALPHABETS, 0); for(int k = 0; k < S.size(); k++) { frequency[S[k] - 'a']++; } subarray.erase(subarray.find((frequency))); } } vector >subarrays_from_1; for(auto it = subarray.begin(); it != subarray.end(); it++) { subarrays_from_1.push_back(*it); } sort(all(subarrays_from_1), sort_by_frequency); string answer; vector current_frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < length; i++) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(subarrays_from_1[i][alpha] > current_frequency[alpha]) { answer += (char)('a' + alpha); current_frequency[alpha]++; } } } cout << "! " << answer << endl; return 0; } ================================================ FILE: 2020/Div 2/612 Div 2/Programs/Angry Students.cpp ================================================ #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; const int oo = 1e7; vector nearest_a(length + 1, oo); nearest_a[0] = (S[0] == 'A' ? 0 : oo); for(int i = 1; i < length; i++) { nearest_a[i] = (S[i] == 'A' ? 0 : nearest_a[i - 1] + 1); } int answer = 0; for(int i = 0; i < length; i++) { //Skip the prefix if(nearest_a[i] >= oo) { continue; } answer = max(answer, nearest_a[i]); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/612 Div 2/Programs/Hyperset.cpp ================================================ #include #include #include using namespace std; char get_third(char a, char b) { switch(a) { case 'S' : return (b == 'E' ? 'T' : 'E'); case 'E' : return (b == 'T' ? 'S' : 'T'); case 'T' : return (b == 'S' ? 'E' : 'S'); } return 0; } long long choose_3(long long n) { long long numerator = n*(n - 1)*(n - 2); long long denominator = 3*2*1; return numerator/denominator; } int main() { int no_of_cards, no_of_features; cin >> no_of_cards >> no_of_features; vector card(no_of_cards + 1); map frequency; for(int i = 1; i <= no_of_cards; i++) { cin >> card[i]; frequency[card[i]]++; } long long same_triplets = 0; for(auto it = frequency.begin(); it != frequency.end(); it++) { same_triplets += choose_3(it->second); } long long different_triplets = 0; for(int i = 1; i <= no_of_cards; i++) { for(int j = i + 1; j <= no_of_cards; j++) { if(card[i] == card[j]) { continue; } string complement; for(int k = 0; k < no_of_features; k++) { if(card[i][k] == card[j][k]) { complement += card[i][k]; } else { complement += get_third(card[i][k], card[j][k]); } } different_triplets += frequency[complement]; } } different_triplets /= 3; long long no_of_triplets = same_triplets + different_triplets; cout << no_of_triplets << "\n"; return 0; } ================================================ FILE: 2020/Div 2/612 Div 2/Programs/Madhouse (Easy Version).cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int sort_by_frequency(vector &A, vector &B) { const int NO_OF_ALPHABETS = 26; int a_sum = 0, b_sum = 0; for(int i = 0; i < NO_OF_ALPHABETS; i++) { a_sum += A[i]; b_sum += B[i]; } return (b_sum > a_sum); } int main() { int length; cin >> length; const int NO_OF_ALPHABETS = 26; cout << "? 1 " << length << endl; multiset >subarray; for(int i = 1; i <= length; i++) { for(int j = i; j <= length; j++) { string S; cin >> S; if(length == 1) { cout << "! " << S << endl; return 0; } vector frequency(NO_OF_ALPHABETS, 0); for(int k = 0; k < S.size(); k++) { frequency[S[k] - 'a']++; } subarray.insert(frequency); } } cout << "? 2 " << length << endl; for(int i = 2; i <= length; i++) { for(int j = i; j <= length; j++) { string S; cin >> S; vector frequency(NO_OF_ALPHABETS, 0); for(int k = 0; k < S.size(); k++) { frequency[S[k] - 'a']++; } subarray.erase(subarray.find((frequency))); } } vector >subarrays_from_1; for(auto it = subarray.begin(); it != subarray.end(); it++) { subarrays_from_1.push_back(*it); } sort(all(subarrays_from_1), sort_by_frequency); string answer; vector current_frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < length; i++) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(subarrays_from_1[i][alpha] > current_frequency[alpha]) { answer += (char)('a' + alpha); current_frequency[alpha]++; } } } cout << "! " << answer << endl; return 0; } ================================================ FILE: 2020/Div 2/613 Div 2/Explanations/Dr Evil Underscores Explanation.txt ================================================ If all the integers have a 1 in a bit position or a 0 in a bit position, then the answer will have a 0 there if we put a bit in X. If some integers have a 1 and some integers have a 0, then the answer will have that bit set in answer regardless of what we put in X. ----- Suppose we are dealing with bit b, What we will do is put all the integers with that bit set in A, We will put all the integers with that bit unset in B We will solve the problem for the remaining bits in A and B seperately and add it to 2^b ----- long long solve(int bit, vector &A) { if(bit < 0 || A.size() == 0) { return 0; } vector set, unset; for(int i = 0; i < A.size(); i++) { if(is_bit_set(A[i], bit)) { set.push_back(A[i]); } else { unset.push_back(A[i]); } } if(set.size() == 0) { return solve(bit - 1, unset); } if(unset.size() == 0) { return solve(bit - 1, set); } return ( (1LL << bit) + min(solve(bit - 1, set), solve(bit - 1, unset)) ); } ================================================ FILE: 2020/Div 2/613 Div 2/Explanations/Fadi and LCM Explanation.txt ================================================ Let us notice something. Suppose p is a prime integer. The LCM of (p^a, p^b) is p^{max(a, b)} If X = p1^a1 p2^a2 ... pn^an If we have to split their prime factors among a and b. We must give p1^a1 to at least one of (a, b). Since we want to minimise the maximum, we will give p1^a1 to one of them and 1 to the other. In the given range, the number of distinct prime factors is not too much (Around 11). We will use bitmasks to check how many of the 11 factors we give to a and how many we give to b and choose the best pair. ------ int main() { long long n; cin >> n; vector prime_factors; factorise(n, prime_factors); long long best_x = 1, best_y = n; int number_of_uniques = prime_factors.size(); for(long long mask = 0; mask < (1LL << number_of_uniques); mask++) { long long x = 1, y = 1; for(int bit = 0; bit < number_of_uniques; bit++) { if(is_bit_set(mask, bit)) { x *= prime_factors[bit]; } else { y *= prime_factors[bit]; } } if(max(x, y) < max(best_x, best_y)) { best_x = x; best_y = y; } } cout << best_x << " " << best_y << "\n"; return 0; } ================================================ FILE: 2020/Div 2/613 Div 2/Explanations/Just Eat It Explanation.txt ================================================ We will use Kandane's Algorithm to find out the best segment that can be chosen at each point. The only exception is when we are at the last element. We have to be careful that the segment we are choosing at the last element is not the entire array. We will check that if we are at the last element, the best segment sum is not the entire prefix sum. The only way we are allowed to take a sum = the entire prefix sum at i = n is if there is some point where prefix[i] = 0 Then, prefix[n] - prefix[i] = prefix[n] ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int is_zero = false; vector prefix_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = A[i] + prefix_sum[i - 1]; if(prefix_sum[i] == 0) { is_zero = true; } } long long best_choice = -1e10; vector max_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { max_sum[i] = max(A[i], A[i] + max_sum[i - 1]); if(i == no_of_elements && max_sum[i] == prefix_sum[i] && is_zero == false) { continue; } best_choice = max(best_choice, max_sum[i]); } cout << (prefix_sum[no_of_elements] > best_choice ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/613 Div 2/Explanations/Mezo Playing Zoma Explanation.txt ================================================ If there are L lefts and R rights, then we can end up anywhere between [-L, R] The answer = (L + R + 1) ------ int main() { int length; string S; cin >> length >> S; int lefts = 0, rights = 0; for(int i = 0; i < length; i++) { switch(S[i]) { case 'L' : lefts++; break; case 'R' : rights++; break; } } int answer = (lefts + rights + 1); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/613 Div 2/Programs/Dr Evil Underscores.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0 ); } long long solve(int bit, vector &A) { if(bit < 0 || A.size() == 0) { return 0; } vector set, unset; for(int i = 0; i < A.size(); i++) { if(is_bit_set(A[i], bit)) { set.push_back(A[i]); } else { unset.push_back(A[i]); } } if(set.size() == 0) { return solve(bit - 1, unset); } if(unset.size() == 0) { return solve(bit - 1, set); } return ( (1LL << bit) + min(solve(bit - 1, set), solve(bit - 1, unset)) ); } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } long long answer = solve(31, A); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/613 Div 2/Programs/Fadi and LCM.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( ( n&(1LL << bit) ) != 0); } void factorise(long long x, vector &P) { for(long long i = 2; i*i <= x; i++) { if(x%i == 0) { long long p = 1; while(x%i == 0) { x /= i; p *= i; } P.push_back(p); } } if(x > 1) { P.push_back(x); } } int main() { long long n; cin >> n; vector prime_factors; factorise(n, prime_factors); long long best_x = 1, best_y = n; int number_of_uniques = prime_factors.size(); for(long long mask = 0; mask < (1LL << number_of_uniques); mask++) { long long x = 1, y = 1; for(int bit = 0; bit < number_of_uniques; bit++) { if(is_bit_set(mask, bit)) { x *= prime_factors[bit]; } else { y *= prime_factors[bit]; } } if(max(x, y) < max(best_x, best_y)) { best_x = x; best_y = y; } } cout << best_x << " " << best_y << "\n"; return 0; } ================================================ FILE: 2020/Div 2/613 Div 2/Programs/Just Eat It.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int is_zero = false; vector prefix_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = A[i] + prefix_sum[i - 1]; if(prefix_sum[i] == 0) { is_zero = true; } } long long best_choice = -1e10; vector max_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { max_sum[i] = max(A[i], A[i] + max_sum[i - 1]); if(i == no_of_elements && max_sum[i] == prefix_sum[i] && is_zero == false) { continue; } best_choice = max(best_choice, max_sum[i]); } cout << (prefix_sum[no_of_elements] > best_choice ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/613 Div 2/Programs/Mezo Playing Zoma.cpp ================================================ #include using namespace std; int main() { int length; string S; cin >> length >> S; int lefts = 0, rights = 0; for(int i = 0; i < length; i++) { switch(S[i]) { case 'L' : lefts++; break; case 'R' : rights++; break; } } int answer = (lefts + rights + 1); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/616 Div 2/Explanations/Array Sharpening Explanation.txt ================================================ Let us make an observation here If it is possible to make (A[1] < A[2] < A[3] < ... < A[k]), then it is possible to make them = (0 < 1 < 2 < ... < (k - 1)) We can do this by simply subtracting more. Let prefix[i] = true, if it is possible to make [1, i] = (0, 1, ... , i - 1) Let suffix[i] = true, if it is possible to make [i, n] = (n - i, ... , 2, 1, 0) We will then go through the entire array and see if we can find an i such that prefix[i - 1] = true and suffix[i + 1] = true and A[i] >= max(i - 1, n - i) Then, we have got our array if even there is a single i that satisfies this condition ! ----- #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_possible(no_of_elements + 1, false); for(int i = 1; i <= no_of_elements; i++) { if(A[i] < i - 1) { break; } prefix_possible[i] = true; } vector suffix_possible(no_of_elements + 1, false); for(int i = no_of_elements; i >= 1; i--) { if(A[i] < (no_of_elements - i)) { break; } suffix_possible[i] = true; } int possible = (no_of_elements == 1 ? true : false); for(int i = 1; i <= no_of_elements; i++) { if(i == 1) { if(A[i] >= (no_of_elements - i) && suffix_possible[i + 1]) { possible = true; break; } } if(i == no_of_elements) { if(A[i] >= (i - 1) && prefix_possible[i - 1]) { possible = true; break; } } if(A[i] >= (i - 1) && prefix_possible[i - 1] && A[i] >= (no_of_elements - i) && suffix_possible[i + 1]) { possible = true; break; } } cout << (possible ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/616 Div 2/Explanations/Even But Not Even Explanation.txt ================================================ The sum of 2 odd numbers is even. If there are at least 2 odd numbers, we will print them in order Otherwise, it is not possible. ----- void solve() { int length; string S; cin >> length >> S; int odd_count = 0; for(int i = 0; i < length; i++) { odd_count += (S[i] - '0')%2; } if(odd_count < 2) { cout << "-1\n"; return; } string answer; for(int i = 0; i < length && answer.size() < 2; i++) { if( (S[i] - '0')%2 == 1) { answer += S[i]; } } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/616 Div 2/Explanations/Mind Control Explanation.txt ================================================ 1. Suppose there are (k - 1) people in front of you. Ultimately, we will have p elements taken from the prefix and s elements taken from the suffix where (p + x = k - 1) 2. Suppose we can control C people. Out of these C people, we will make some of them take the prefix and some of them take the suffix. Out of the U people we can't control, u people will take the prefix and (U - u) will take the suffix. 3. Let us say we make c people out of C take the prefix. The U people we can't control will make their choice so as to minimise our sum. 4. We will iterate over all possibilities. We will first fix that we will choose c people to take the prefix and (C - c) to take the suffix. The U people we can't control will make their choice in such a way as to minimise our sum. 5. We will choose the value of (c, u) that gives us our maximum sum. ----- void solve() { int no_of_elements, position, controlled; cin >> no_of_elements >> position >> controlled; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } controlled = min(controlled, position - 1); int uncontrolled = (position - 1) - controlled; int best_answer = 0; for(int c = 0; c <= controlled; c++) { int best_answer_for_c = 1e9 + 5; for(int i = 0; i <= uncontrolled; i++) { int prefix = c + i, suffix = no_of_elements - (controlled - c) - (uncontrolled - i) + 1;//Last element is n, not (n - 1) so add +1 int answer_here = max(A[prefix + 1], A[suffix - 1]); best_answer_for_c = min(answer_here, best_answer_for_c); } best_answer = max(best_answer, best_answer_for_c); } cout << best_answer << "\n"; } ================================================ FILE: 2020/Div 2/616 Div 2/Programs/Array Sharpening.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_possible(no_of_elements + 1, false); for(int i = 1; i <= no_of_elements; i++) { if(A[i] < i - 1) { break; } prefix_possible[i] = true; } vector suffix_possible(no_of_elements + 1, false); for(int i = no_of_elements; i >= 1; i--) { if(A[i] < (no_of_elements - i)) { break; } suffix_possible[i] = true; } int possible = (no_of_elements == 1 ? true : false); for(int i = 1; i <= no_of_elements; i++) { if(i == 1) { if(A[i] >= (no_of_elements - i) && suffix_possible[i + 1]) { possible = true; break; } } if(i == no_of_elements) { if(A[i] >= (i - 1) && prefix_possible[i - 1]) { possible = true; break; } } if(A[i] >= (i - 1) && prefix_possible[i - 1] && A[i] >= (no_of_elements - i) && suffix_possible[i + 1]) { possible = true; break; } } cout << (possible ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/616 Div 2/Programs/Even But Not Even.cpp ================================================ #include using namespace std; void solve() { int length; string S; cin >> length >> S; int odd_count = 0; for(int i = 0; i < length; i++) { odd_count += (S[i] - '0')%2; } if(odd_count < 2) { cout << "-1\n"; return; } string answer; for(int i = 0; i < length && answer.size() < 2; i++) { if( (S[i] - '0')%2 == 1) { answer += S[i]; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/616 Div 2/Programs/Mind Control.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, position, controlled; cin >> no_of_elements >> position >> controlled; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } controlled = min(controlled, position - 1); int uncontrolled = (position - 1) - controlled; int best_answer = 0; for(int c = 0; c <= controlled; c++) { int best_answer_for_c = 1e9 + 5; for(int i = 0; i <= uncontrolled; i++) { int prefix = c + i, suffix = no_of_elements - (controlled - c) - (uncontrolled - i) + 1;//Last element is n, not (n - 1) so add +1 int answer_here = max(A[prefix + 1], A[suffix - 1]); best_answer_for_c = min(answer_here, best_answer_for_c); } best_answer = max(best_answer, best_answer_for_c); } cout << best_answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/618 Div 2/Explanations/Anu has a Function Explanation.txt ================================================ Observation - f(x, y) will only have the bits that are set in x Every bit in y is subtracted so we cannot add any new bits to x, by performing f(x, y) ----- This means that the value of a[1], represents the value of the entire function. For every A[i], we will calculate the value of the function if we place A[i] at A[1]. The answer will have all the bits set that are set only once in A[i] and not in any other array element. If any bit is set in some other element A[j], it will get subtracted when we peform f(x, A[j]) ----- #include #include using namespace std; int is_bit_set(long long n, int bit) { return ((n & (1LL << bit)) != 0); } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int NO_OF_BITS = 31; vector bit_frequency(NO_OF_BITS + 1, 0); for(int i = 1; i <= no_of_elements; i++) { for(int b = 0; b <= NO_OF_BITS; b++) { if(is_bit_set(A[i], b)) { bit_frequency[b]++; } } } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { long long answer_here = 0; for(int b = 0; b <= NO_OF_BITS; b++) { if(is_bit_set(A[i], b) && bit_frequency[b] == 1) { answer_here |= (1LL << b); } } if(answer_here > answer) { swap(A[i], A[1]); answer = answer_here; } } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/618 Div 2/Programs/Anu has a Function.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ((n & (1LL << bit)) != 0); } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int NO_OF_BITS = 31; vector bit_frequency(NO_OF_BITS + 1, 0); for(int i = 1; i <= no_of_elements; i++) { for(int b = 0; b <= NO_OF_BITS; b++) { if(is_bit_set(A[i], b)) { bit_frequency[b]++; } } } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { long long answer_here = 0; for(int b = 0; b <= NO_OF_BITS; b++) { if(is_bit_set(A[i], b) && bit_frequency[b] == 1) { answer_here |= (1LL << b); } } if(answer_here > answer) { swap(A[i], A[1]); answer = answer_here; } } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/619 Div 2/Explanations/Ayoub's Function Explanation.txt ================================================ We need to maximise the number of substrings containing at least 1 one. This is the same as minimizing the number of substrings containing only 0s. Let us see how to do this with an example. If we want to minimize the number of 0s, it is best to make each group of 0s as small as possible. (2 groups of length 1 is smaller than 1 group of length 2) 0, 0 has 2 substrings 00 has 3 substrings Suppose we have 10 0s and 5 1s 00 | 00 | 00 | 00 | 0 | 0 The best way to distribute them is like this If there are d 1s, then we divide the 0s into (D + 1) parts. ---- First, we will divide them equally 0 | 0 | 0 | 0 | 0 | 0 ----- We will have some remainder. In this case 10 (mod 6) = 4 So, we will add the 4 extra 0s to different parts to keep the sum of 0s minimum So 4 segments, will have an extra 0 ----- How to calculate this ? 1. Find out the length of each 0 segment. The number of 0 substrings will be l(l - 1)/2 + l 2. When we add a 0 to a segment of length z, we will be create (z + 1) new 0-substrings Each remainder contributes (z + 1) to the answer, where z is the length of a 0-substring ---- long long count_substrings(long long n) { return (n*(n + 1))/2; } void solve() { long long length, no_of_1s; cin >> length >> no_of_1s; long long no_of_0s = (length - no_of_1s); long long total_substrings = count_substrings(length); long long dividers = (no_of_1s + 1); long long full_zero_islands_size = (no_of_0s/dividers); long long zero_substrings = dividers*count_substrings(full_zero_islands_size); if(no_of_0s%dividers != 0) { long long remaining_zeroes = no_of_0s - dividers*(full_zero_islands_size); zero_substrings += remaining_zeroes*(full_zero_islands_size + 1); } long long one_substrings = total_substrings - zero_substrings; cout << one_substrings << "\n"; } ================================================ FILE: 2020/Div 2/619 Div 2/Explanations/Motarack's Birthday Explanation.txt ================================================ Let us look at the elements which -1 is adjacent to. Let them be {F1, F2, ... , Fm} The maximum value of |k - Fi| for some Fi in this set will be either with the smallest or largest element. So, the best choice for k is (F1 + Fm)/2 as this is the optimal distance between both After we replace all k's with (F1 + Fm)/2, we will calculate the value of max|A[i] - A[i - 1]| ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector fixed; for(int i = 2; i <= no_of_elements; i++) { if(A[i - 1] == -1 && A[i] != -1) { fixed.push_back(A[i]); } } for(int i = 1; i < no_of_elements; i++) { if(A[i + 1] == -1 && A[i] != -1) { fixed.push_back(A[i]); } } sort(all(fixed)); long long mid; if(fixed.size() == 0) { mid = 0; } else { mid = (fixed[0] + fixed.back())/2; } for(int i = 1; i <= no_of_elements; i++) { if(A[i] == -1) { A[i] = mid; } } long long m = 0; for(int i = 2; i <= no_of_elements; i++) { m = max(m, abs(A[i] - A[i - 1])); } cout << m << " " << mid << "\n"; } ================================================ FILE: 2020/Div 2/619 Div 2/Explanations/Three Strings Explanation.txt ================================================ For each position i, We must swap either (A[i], C[i]) or (B[i], C[i]) This means that either (B[i] = C[i]) or (A[i] = C[i]) respectively ----- void solve() { string A, B, C; cin >> A >> B >> C; for(int i = 0; i < A.size(); i++) { if(A[i] == C[i] || B[i] == C[i]) { continue; } cout << "NO\n"; return; } cout << "YES\n"; } ================================================ FILE: 2020/Div 2/619 Div 2/Explanations/Time to Run Explanation.txt ================================================ We will start from (1, 1) In any given row, we will go left till we reach the end of that row. Then, we will go UDR, till we reach the first cell of the row. Then, we will go to the next row and repeat. If we are at the last row, then we will go U till we reach (1, 1). ----- int range(int max_1, int distance, int size, int &steps) { int taken; if(distance*size <= steps) { taken = distance; } else { taken = steps/size; } steps -= taken*size; return taken; } int main() { int rows, columns, steps; cin >> rows >> columns >> steps; if(steps > 4*rows*columns - 2*rows - 2*columns) { cout << "NO\n"; return 0; } cout << "YES\n"; vector < pair > journey; for(int r = 1; r <= rows && steps > 0; r++) { int steps_taken; steps_taken = range(steps, columns - 1, 1, steps); if(steps_taken > 0) { journey.push_back(make_pair(steps_taken, "R")); } if(r < rows) { steps_taken = range(steps, columns - 1, 3, steps); if(steps_taken > 0) { journey.push_back(make_pair(steps_taken, "DUL")); } if(steps_taken < columns - 1 && steps < 3 && steps > 0) { switch(steps) { case 2 : journey.push_back(make_pair(1, "DU")); steps -= 2; break; case 1 : journey.push_back(make_pair(1, "D")); steps--; break; } } if(steps > 0) { journey.push_back(make_pair(1, "D")); steps--; } continue; } if(r == rows) { steps_taken = range(steps, columns - 1, 1, steps); if(steps_taken > 0) { journey.push_back(make_pair(steps_taken, "L")); } if(steps > 0) { steps_taken = range(steps, rows - 1, 1, steps); journey.push_back(make_pair(steps_taken, "U")); } } } cout << journey.size() << "\n"; for(int i = 0; i < journey.size(); i++) { cout << journey[i].first << " " << journey[i].second << "\n"; } return 0; } ================================================ FILE: 2020/Div 2/619 Div 2/Programs/Ayoub's Function.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long count_substrings(long long n) { return (n*(n + 1))/2; } void solve() { long long length, no_of_1s; cin >> length >> no_of_1s; long long no_of_0s = (length - no_of_1s); long long total_substrings = count_substrings(length); long long dividers = (no_of_1s + 1); long long full_zero_islands_size = (no_of_0s/dividers); long long zero_substrings = dividers*count_substrings(full_zero_islands_size); if(no_of_0s%dividers != 0) { long long remaining_zeroes = no_of_0s - dividers*(full_zero_islands_size); zero_substrings += remaining_zeroes*(full_zero_islands_size + 1); } long long one_substrings = total_substrings - zero_substrings; cout << one_substrings << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/619 Div 2/Programs/Motarack's Birthday.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector fixed; for(int i = 2; i <= no_of_elements; i++) { if(A[i - 1] == -1 && A[i] != -1) { fixed.push_back(A[i]); } } for(int i = 1; i < no_of_elements; i++) { if(A[i + 1] == -1 && A[i] != -1) { fixed.push_back(A[i]); } } sort(all(fixed)); long long mid; if(fixed.size() == 0) { mid = 0; } else { mid = (fixed[0] + fixed.back())/2; } for(int i = 1; i <= no_of_elements; i++) { if(A[i] == -1) { A[i] = mid; } } long long m = 0; for(int i = 2; i <= no_of_elements; i++) { m = max(m, abs(A[i] - A[i - 1])); } cout << m << " " << mid << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/619 Div 2/Programs/Three Strings.cpp ================================================ #include #include using namespace std; void solve() { string A, B, C; cin >> A >> B >> C; for(int i = 0; i < A.size(); i++) { if(A[i] == C[i] || B[i] == C[i]) { continue; } cout << "NO\n"; return; } cout << "YES\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/619 Div 2/Programs/Time to Run.cpp ================================================ #include #include using namespace std; int range(int max_1, int distance, int size, int &steps) { int taken; if(distance*size <= steps) { taken = distance; } else { taken = steps/size; } steps -= taken*size; return taken; } int main() { int rows, columns, steps; cin >> rows >> columns >> steps; if(steps > 4*rows*columns - 2*rows - 2*columns) { cout << "NO\n"; return 0; } cout << "YES\n"; vector < pair > journey; for(int r = 1; r <= rows && steps > 0; r++) { int steps_taken; steps_taken = range(steps, columns - 1, 1, steps); if(steps_taken > 0) { journey.push_back(make_pair(steps_taken, "R")); } if(r < rows) { steps_taken = range(steps, columns - 1, 3, steps); if(steps_taken > 0) { journey.push_back(make_pair(steps_taken, "DUL")); } if(steps_taken < columns - 1 && steps < 3 && steps > 0) { switch(steps) { case 2 : journey.push_back(make_pair(1, "DU")); steps -= 2; break; case 1 : journey.push_back(make_pair(1, "D")); steps--; break; } } if(steps > 0) { journey.push_back(make_pair(1, "D")); steps--; } continue; } if(r == rows) { steps_taken = range(steps, columns - 1, 1, steps); if(steps_taken > 0) { journey.push_back(make_pair(steps_taken, "L")); } if(steps > 0) { steps_taken = range(steps, rows - 1, 1, steps); journey.push_back(make_pair(steps_taken, "U")); } } } cout << journey.size() << "\n"; for(int i = 0; i < journey.size(); i++) { cout << journey[i].first << " " << journey[i].second << "\n"; } return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Explanations/1-Trees and Queries Explanation.txt ================================================ There is a crucial insight that we can make here. We can make a 'waiting' move. After we travel from a -> b, we can keep going back and forth on the same edge. b-> c -> b We can keep going back and forth to one of the neighbours of b. This way, we can make an unlimited number of moves ! ---- Suppose we have a path of length L. There is a path of length (L + 2X) for every integer X. ---- Now, there are 3 Simple Paths from (a, b) 1. a -> b 2. a -> x -> y -> b 3. a -> y -> x -> b ---- If any of these path lengths <= k and have the same parity as k, then we can use the required number of waiting moves to go from (a, b) and use exactly k moves. ---- We can use LCA to calculate the distance between 2 vertices. We can do O(N Log N) precompute and answer each query in O(Log N) time. ----- int main() { int no_of_vertices; cin >> no_of_vertices; int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } depth[0] = 0; dfs(1, 0); precompute_parents(no_of_vertices); int no_of_queries; cin >> no_of_queries; for(int i = 1; i <= no_of_queries; i++) { int x, y, a, b, k; cin >> x >> y >> a >> b >> k; int path_1 = distance(a, b); int path_2 = distance(a, x) + distance(b, y) + 1; int path_3 = distance(a, y) + distance(b, x) + 1; if( (path_1 <= k && path_1%2 == k%2) || (path_2 <= k && path_2%2 == k%2) || (path_3 <= k && path_3%2 == k%2) ) { cout << "YES\n"; } else { cout << "NO\n"; } } return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Explanations/Air Conditioner Explanation.txt ================================================ We can interpret this problem geometrically and it would help greatly. Let us visualise the time on the y-axis and the temperature on the x axis. We are given a set of segments and we must determine if it is possible to draw a line that passes through each of them. Instead of keeping track of a line, we will keep track of the possible range of the line. Let the line always lie between [A, B] on the x axis. In the time between two events, the minimum can reduce by at most (T[i] - T[i - 1]) and the maximum can reduce by at most (T[i] - T[i - 1]) However, we have to be careful of one thing. The minimum range of the line cannot be lesser than the Left boundary of any event. The maximum range of the line cannot be greater than the Right boundary of any event. So at every point, we just have to update the minimum and maximum range of the line. We are keeping the range as large as possible at every step. If a line exists, it has to do so within this range. The beauty of this approach is that we don't have to find the actual line. Just knowing it's range is enough. :) ----- struct customer { int time, left, right; customer(){} customer(int T, int L, int R) { time = T; left = L; right = R; } }; int sort_by_time(customer &A, customer &B) { if(A.time == B.time) { return (A.left < B.left); } return (A.time < B.time); } void solve() { int no_of_customers, starting; cin >> no_of_customers >> starting; vector C(no_of_customers, customer(0, 0, 0)); for(int i = 0; i < no_of_customers; i++) { cin >> C[i].time >> C[i].left >> C[i].right; } sort(all(C), sort_by_time); int minimum = starting, maximum = starting; int possible = true; for(int i = 0; i < no_of_customers && possible; i++) { if(i == 0) { minimum = starting - C[i].time; maximum = starting + C[i].time; } else { minimum = minimum - (C[i].time - C[i - 1].time); maximum = maximum + (C[i].time - C[i - 1].time); } if(minimum > C[i].right || maximum < C[i].left) { possible = false; break; } minimum = max(minimum, C[i].left); maximum = min(maximum, C[i].right); } cout << (possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/620 Div 2/Explanations/Longest Palindrome Explanation.txt ================================================ Let R[S] be the reverse of string S The final palindrome looks like this S1 S2 S3 ... Sm (M)R[Sm] ... R[S3]R[S2]R[S1] And M is a palindrome that can be placed in the middle. The constraints are small enough that we can check every pair of strings. For each string S[i], we will check if it's reverse R(S[i]) is also present in the array. We will store all the strings in one vector and all their reverses in another vector. Suppose S[i] is the 3rd string in the list of strings we will print, then R(S[i]) is the 3rd last string that we need to print. Lastly, we can have at most 1 palindromic string in the middle. We will check if any of the strings are palindromes. If they are, we will use one in the middle. ----- int main() { int no_of_strings, length; cin >> no_of_strings >> length; vector S(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) { cin >> S[i]; } vector strings_index; vector reverse_strings_index; for(int i = 1; i <= no_of_strings; i++) { for(int j = i + 1; j <= no_of_strings; j++) { if(is_palindrome(S[i] + S[j])) { strings_index.push_back(i); reverse_strings_index.push_back(j); } } } string middle; for(int i = 1; i <= no_of_strings; i++) { if(is_palindrome(S[i])) { middle = S[i]; } } int final_length = strings_index.size() + (middle.size() != 0) + reverse_strings_index.size(); final_length *= length; cout << final_length << "\n"; for(int i = 0; i < strings_index.size(); i++) { cout << S[strings_index[i]]; } if(middle.size() != 0) { cout << middle; } for(int i = reverse_strings_index.size() - 1; i >= 0; i--) { cout << S[reverse_strings_index[i]]; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Explanations/Shortest and Longest LIS Explanation.txt ================================================ 1. If we want to make the shortest LIS possible, we must make sure 1 comes as late as possible as it matches with every element. Then, 2 must come as much to the right as possible and so on. 2. We will start from the right end and whenever a sequence of <<< is there, we will start filling from 1, 2, 3 3. For making the longest LIS possible, we will fill each digit as much to the left as possible to ensure it has as many digits as possible to match. So, we will start from the left and fill <<< 1,2,3 ----- #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; vector longest_chain_from(length + 1, 1); for(int i = length - 1; i >= 1; i--) { if(S[i - 1] == '<') { longest_chain_from[i] = 1 + longest_chain_from[i + 1]; } } vector shortest_lis(length + 1); for(int i = length, last = 1; i >= 1; last++) { int j = i; for(j = i; j >= 1 && longest_chain_from[j] + 1 == longest_chain_from[j - 1]; j--) { //cout << "J = " << j << "\n"; last++; } shortest_lis[i] = last; //cout << "J = " << j << " i = " << i << "\n"; for(int k = i - 1; k >= j; k--) { shortest_lis[k] = shortest_lis[k + 1] - 1; } i = j - 1; } for(int i = 1; i <= length; i++) { cout << shortest_lis[i] << " "; } cout << "\n"; vector longest_lis(length + 1); for(int i = 1, last = 1; i <= length; i++, last++) { int j = i; for(j = i; (j <= length - 1 && S[j - 1] == '>'); j++) { last++; } //cout << "J = " << j << "\n"; longest_lis[i] = last; for(int k = i + 1; k <= j; k++) { longest_lis[k] = longest_lis[k - 1] - 1; } i = j; } for(int i = 1; i <= length; i++) { cout << longest_lis[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Explanations/Two Rabbits Explanation.txt ================================================ There are two rabbits. The distance between them reduces by (a + b) in 1 second. The total distance to be covered is (x - y). The rabbits will meet if (x - y) is a multiple of (a + b). Otherwise, they will never complement ----- void solve() { long long position_1, position_2, distance_1, distance_2; cin >> position_1 >> position_2 >> distance_1 >> distance_2; long long time = ((position_2 - position_1)%(distance_1 + distance_2) == 0 ? (position_2 - position_1)/(distance_1 + distance_2) : -1); cout << time << "\n"; } ================================================ FILE: 2020/Div 2/620 Div 2/Programs/1-Trees and Queries.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e5 + 5, MAX_L = 25; vector tree[MAX_N]; int parent[MAX_N][MAX_L], depth[MAX_N]; int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0); } void dfs(int v, int parent_v) { parent[v][0] = parent_v; depth[v] = depth[parent_v] + 1; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); } } void precompute_parents(int no_of_vertices) { for(int l = 1; l < MAX_L; l++) { for(int v = 1; v <= no_of_vertices; v++) { int ancestor = parent[v][l - 1]; parent[v][l] = parent[ancestor][l - 1]; } } } int LCA(int u, int v) { if(depth[v] < depth[u]) { swap(u, v); } int difference = depth[v] - depth[u]; for(int i = MAX_L - 1; i >= 0; i--) { if(is_bit_set(difference, i)) { v = parent[v][i]; } } if(u == v) { return v; } for(int i = MAX_L - 1; i >= 0; i--) { if(parent[v][i] != parent[u][i]) { v = parent[v][i]; u = parent[u][i]; } } return parent[v][0]; } int distance(int u, int v) { int l = LCA(u, v); if(l == u) { return (depth[v] - depth[l]); } if(l == v) { return (depth[u] - depth[l]); } return (depth[v] - depth[l]) + (depth[u] - depth[l]); } int main() { int no_of_vertices; cin >> no_of_vertices; int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } depth[0] = 0; dfs(1, 0); precompute_parents(no_of_vertices); int no_of_queries; cin >> no_of_queries; for(int i = 1; i <= no_of_queries; i++) { int x, y, a, b, k; cin >> x >> y >> a >> b >> k; int path_1 = distance(a, b); int path_2 = distance(a, x) + distance(b, y) + 1; int path_3 = distance(a, y) + distance(b, x) + 1; if( (path_1 <= k && path_1%2 == k%2) || (path_2 <= k && path_2%2 == k%2) || (path_3 <= k && path_3%2 == k%2) ) { cout << "YES\n"; } else { cout << "NO\n"; } } return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Programs/Air Conditioner.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct customer { int time, left, right; customer(){} customer(int T, int L, int R) { time = T; left = L; right = R; } }; int sort_by_time(customer &A, customer &B) { if(A.time == B.time) { return (A.left < B.left); } return (A.time < B.time); } void solve() { int no_of_customers, starting; cin >> no_of_customers >> starting; vector C(no_of_customers, customer(0, 0, 0)); for(int i = 0; i < no_of_customers; i++) { cin >> C[i].time >> C[i].left >> C[i].right; } sort(all(C), sort_by_time); int minimum = starting, maximum = starting; int possible = true; for(int i = 0; i < no_of_customers && possible; i++) { if(i == 0) { minimum = starting - C[i].time; maximum = starting + C[i].time; } else { minimum = minimum - (C[i].time - C[i - 1].time); maximum = maximum + (C[i].time - C[i - 1].time); } if(minimum > C[i].right || maximum < C[i].left) { possible = false; break; } minimum = max(minimum, C[i].left); maximum = min(maximum, C[i].right); } cout << (possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Programs/Longest Palindrome.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int is_palindrome(string S) { for(int i = 0; i < S.size(); i++) { if(S[i] != S[S.size() - 1 - i]) { return false; } } return true; } int main() { int no_of_strings, length; cin >> no_of_strings >> length; vector S(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) { cin >> S[i]; } vector strings_index; vector reverse_strings_index; for(int i = 1; i <= no_of_strings; i++) { for(int j = i + 1; j <= no_of_strings; j++) { if(is_palindrome(S[i] + S[j])) { strings_index.push_back(i); reverse_strings_index.push_back(j); } } } string middle; for(int i = 1; i <= no_of_strings; i++) { if(is_palindrome(S[i])) { middle = S[i]; } } int final_length = strings_index.size() + (middle.size() != 0) + reverse_strings_index.size(); final_length *= length; cout << final_length << "\n"; for(int i = 0; i < strings_index.size(); i++) { cout << S[strings_index[i]]; } if(middle.size() != 0) { cout << middle; } for(int i = reverse_strings_index.size() - 1; i >= 0; i--) { cout << S[reverse_strings_index[i]]; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Programs/Shortest and Longest LIS.cpp ================================================ #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; vector longest_chain_from(length + 1, 1); for(int i = length - 1; i >= 1; i--) { if(S[i - 1] == '<') { longest_chain_from[i] = 1 + longest_chain_from[i + 1]; } } vector shortest_lis(length + 1); for(int i = length, last = 1; i >= 1; last++) { int j = i; for(j = i; j >= 1 && longest_chain_from[j] + 1 == longest_chain_from[j - 1]; j--) { //cout << "J = " << j << "\n"; last++; } shortest_lis[i] = last; //cout << "J = " << j << " i = " << i << "\n"; for(int k = i - 1; k >= j; k--) { shortest_lis[k] = shortest_lis[k + 1] - 1; } i = j - 1; } for(int i = 1; i <= length; i++) { cout << shortest_lis[i] << " "; } cout << "\n"; vector longest_lis(length + 1); for(int i = 1, last = 1; i <= length; i++, last++) { int j = i; for(j = i; (j <= length - 1 && S[j - 1] == '>'); j++) { last++; } //cout << "J = " << j << "\n"; longest_lis[i] = last; for(int k = i + 1; k <= j; k++) { longest_lis[k] = longest_lis[k - 1] - 1; } i = j; } for(int i = 1; i <= length; i++) { cout << longest_lis[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/620 Div 2/Programs/Two Rabbits.cpp ================================================ #include using namespace std; void solve() { long long position_1, position_2, distance_1, distance_2; cin >> position_1 >> position_2 >> distance_1 >> distance_2; long long time = ((position_2 - position_1)%(distance_1 + distance_2) == 0 ? (position_2 - position_1)/(distance_1 + distance_2) : -1); cout << time << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/622 Div 2/Explanations/Fast Food Restaurant Explanation.txt ================================================ We will have a bitmask corresponding to each possibility. Here is our strategy 001 010 100 011 101 110 111 ----- So, we will go through all the submasks and find out which masks correspond to possible meals. ----- void solve() { const int NO_OF_FOOD = 3; vector portions(NO_OF_FOOD); for(int i = 0; i < NO_OF_FOOD; i++) { cin >> portions[i]; } sort(all(portions)); reverse(all(portions)); int max_mask = (1 << NO_OF_FOOD); int no_of_meals = 0; for(int m = 1; m < max_mask; m++) { int good_mask = true; for(int i = 0; i < NO_OF_FOOD; i++) { if(is_bit_set(m, i) && portions[i] <= 0) { //cout << "No " << i << "\n"; good_mask = false; } } //cout << "Mask = " << m << "\n"; if(!good_mask) { continue; } //cout << "Good \n"; for(int i = 0; i < NO_OF_FOOD; i++) { if(is_bit_set(m, i)) { portions[i]--; } } no_of_meals++; } cout << no_of_meals << "\n"; } ================================================ FILE: 2020/Div 2/622 Div 2/Explanations/Sky Scrapers (Hard Version) Explanation.txt ================================================ This is the same as the Easy Version For every A[i], we will calculate the total height if this were the peak. Here, is what we will do if A[i] is the peak We will make all A[j] = A[i], where j < i and A[j] >= A[i] till we find a j such that A[j] < A[i] We will do the same in both the left and right directions. ----- For every A[i], we need to find the first j, such that A[j] < A[i] We can do this with a Stack in O(1) time 1. Initially Stack is empty 2. When we reach A[i], we will pop all elements from the stack as long as A[stack.top()] >= A[i] 3. Then, stack.top() will be the nearest element < A[i] And we will put A[i] in the stack after this This is optimal for the future steps as well. ----- int main() { int no_of_plots; cin >> no_of_plots; vector max_height(no_of_plots + 5); for(int i = 1; i <= no_of_plots; i++) { cin >> max_height[i]; } stack greater_than; greater_than.push(0); vector left_contribution(no_of_plots + 1); for(int i = 1; i <= no_of_plots; i++) { while(max_height[greater_than.top()] > max_height[i]) { greater_than.pop(); } left_contribution[i] = max_height[i]*(i - greater_than.top()) + left_contribution[greater_than.top()]; //cout << "Left " << i << " = " << left_contribution[i] << "\n"; greater_than.push(i); } greater_than.pop(); greater_than.push(no_of_plots + 1); vector right_contribution(no_of_plots + 5); for(int i = no_of_plots; i >= 1; i--) { while(max_height[greater_than.top()] > max_height[i]) { greater_than.pop(); } right_contribution[i] = max_height[i]*(greater_than.top() - i) + right_contribution[greater_than.top()]; greater_than.push(i); //cout << "Right " << i << " = " << right_contribution[i] << "\n"; } long long answer = 0; for(int i = 1; i <= no_of_plots; i++) { answer = max(answer, left_contribution[i] + right_contribution[i] - max_height[i]); } //cout << answer << "\n"; int peak = 0; for(int i = 1; i <= no_of_plots; i++) { if(answer == left_contribution[i] + right_contribution[i] - max_height[i]) { peak = i; break; } } vector height(no_of_plots + 1); height[peak] = max_height[peak]; for(int i = peak - 1; i >= 1; i--) { height[i] = min(max_height[i], height[i + 1]); } for(int i = peak + 1;i <= no_of_plots; i++) { height[i] = min(max_height[i], height[i - 1]); } for(int i = 1; i <= no_of_plots; i++) { cout << height[i] << " "; } cout <<"\n"; return 0; } ================================================ FILE: 2020/Div 2/622 Div 2/Explanations/Skyscrapers (Easy Version) Explanation.txt ================================================ The array will be ascending for some time and then descending. We will iterate over all N plots and find the total if the i-th plot is the peak. ----- long long count(int P, vector &limit, vector &A) { A[P] = limit[P]; for(int i = P - 1; i >= 1; i--) { A[i] = min(limit[i], A[i + 1]); } for(int i = P + 1; i < limit.size(); i++) { A[i] = min(limit[i], A[i - 1]); } long long total = 0; for(int i = 1; i < limit.size(); i++) { total += A[i]; } return total; } int main() { int no_of_plots; cin >> no_of_plots; vector max_height(no_of_plots + 1); for(int i = 1; i <= no_of_plots; i++) { cin >> max_height[i]; } long long max_count = 0; vector answer(no_of_plots + 1); vector this_answer(no_of_plots + 1); for(int peak = 1; peak <= no_of_plots; peak++) { if(count(peak, max_height, this_answer) > max_count) { max_count = count(peak, max_height, this_answer); answer = this_answer; } } for(int i = 1; i <= no_of_plots; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/622 Div 2/Programs/Fast Food Restaurants.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int is_bit_set(int n, int bit) { return ( (n&(1 << bit)) != 0) ; } void solve() { const int NO_OF_FOOD = 3; vector portions(NO_OF_FOOD); for(int i = 0; i < NO_OF_FOOD; i++) { cin >> portions[i]; } sort(all(portions)); reverse(all(portions)); int max_mask = (1 << NO_OF_FOOD); int no_of_meals = 0; for(int m = 1; m < max_mask; m++) { int good_mask = true; for(int i = 0; i < NO_OF_FOOD; i++) { if(is_bit_set(m, i) && portions[i] <= 0) { good_mask = false; } } if(!good_mask) { continue; } for(int i = 0; i < NO_OF_FOOD; i++) { if(is_bit_set(m, i)) { portions[i]--; } } no_of_meals++; } cout << no_of_meals << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/622 Div 2/Programs/Skyscrapers (Easy Version).cpp ================================================ #include #include using namespace std; long long count(int P, vector &limit, vector &A) { A[P] = limit[P]; for(int i = P - 1; i >= 1; i--) { A[i] = min(limit[i], A[i + 1]); } for(int i = P + 1; i < limit.size(); i++) { A[i] = min(limit[i], A[i - 1]); } long long total = 0; for(int i = 1; i < limit.size(); i++) { total += A[i]; } return total; } int main() { int no_of_plots; cin >> no_of_plots; vector max_height(no_of_plots + 1); for(int i = 1; i <= no_of_plots; i++) { cin >> max_height[i]; } long long max_count = 0; vector answer(no_of_plots + 1); vector this_answer(no_of_plots + 1); for(int peak = 1; peak <= no_of_plots; peak++) { if(count(peak, max_height, this_answer) > max_count) { max_count = count(peak, max_height, this_answer); answer = this_answer; } } for(int i = 1; i <= no_of_plots; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/622 Div 2/Programs/Skyscrapers (Hard Version).cpp ================================================ #include #include #include using namespace std; int main() { int no_of_plots; cin >> no_of_plots; vector max_height(no_of_plots + 5); for(int i = 1; i <= no_of_plots; i++) { cin >> max_height[i]; } stack greater_than; greater_than.push(0); vector left_contribution(no_of_plots + 1); for(int i = 1; i <= no_of_plots; i++) { while(max_height[greater_than.top()] > max_height[i]) { greater_than.pop(); } left_contribution[i] = max_height[i]*(i - greater_than.top()) + left_contribution[greater_than.top()]; //cout << "Left " << i << " = " << left_contribution[i] << "\n"; greater_than.push(i); } greater_than.pop(); greater_than.push(no_of_plots + 1); vector right_contribution(no_of_plots + 5); for(int i = no_of_plots; i >= 1; i--) { while(max_height[greater_than.top()] > max_height[i]) { greater_than.pop(); } right_contribution[i] = max_height[i]*(greater_than.top() - i) + right_contribution[greater_than.top()]; greater_than.push(i); //cout << "Right " << i << " = " << right_contribution[i] << "\n"; } long long answer = 0; for(int i = 1; i <= no_of_plots; i++) { answer = max(answer, left_contribution[i] + right_contribution[i] - max_height[i]); } //cout << answer << "\n"; int peak = 0; for(int i = 1; i <= no_of_plots; i++) { if(answer == left_contribution[i] + right_contribution[i] - max_height[i]) { peak = i; break; } } vector height(no_of_plots + 1); height[peak] = max_height[peak]; for(int i = peak - 1; i >= 1; i--) { height[i] = min(max_height[i], height[i + 1]); } for(int i = peak + 1;i <= no_of_plots; i++) { height[i] = min(max_height[i], height[i - 1]); } for(int i = 1; i <= no_of_plots; i++) { cout << height[i] << " "; } cout <<"\n"; return 0; } ================================================ FILE: 2020/Div 2/623 Div 2/Explanations/Dead Pixel Explanation.txt ================================================ There are 4 possible areas (x - 1)b (a - x)b a(y - 1) a(b - y) We will choose the maximum of the 4 areas ----- #include using namespace std; void solve() { int a, b, x, y; cin >> a >> b >> x >> y; x++; y++; int area_1, area_2; if(x > a/2) { area_1 = (x - 1)*b; } else { area_1 = (a - x)*b; } if(y > b/2) { area_2 = a*(y - 1); } else { area_2 = a*(b - y); } int answer = max(area_1, area_2); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/623 Div 2/Explanations/Homecoming Explanation.txt ================================================ This is a tricky problem because of the condition that we will not need to go anywhere from the last station. We will scan the array from right to left. Whenever we encounter a change in segments, we will see if the price range is in our budget. If no, then we need to reach the (i + 1)-th spot by foot ----- void solve() { int bus, tram, budget; cin >> bus >> tram >> budget; string city; cin >> city; int index = 0, money_so_far = 0; for(int i = city.size() - 2; i >= 0; i--) { if(i == city.size() - 2 || (city[i] != city[i + 1])) { int money_here = (city[i] == 'A' ? bus : tram); //cout << "Money at " << i + 1 << " = " << money_here << " T = " << money_so_far + money_here << "\n"; if(money_so_far + money_here > budget) { index = (i + 1); break; } money_so_far += money_here; } } cout << index + 1 << "\n"; } ================================================ FILE: 2020/Div 2/623 Div 2/Explanations/Recommendations Explanation.txt ================================================ The only operation that we are allowed is addition. Let us start processing the elements in ascending order. At any point in time A[1] is the smallest integer. If A[1] < A[2], we can remove A[1] from the array and solve the same problem from [2, n] Otherwise, A[1] = A[2] = ... = A[i] In this case, we have to increment (i - 1) elements no matter what. So, we will increment all values except that which has the highest cost. And we will discard the element with the largest cost and now we will have A[1], A[2] + 1, A[3] + 1, ... , A[i] + 1 We have to check if (A[i + 1] == A[i] + 1) If yes, then we will add the cost of (A[i] + 1) to our multiset of costs and once again increment everything except the largest value. Otherwise, we will repeat the same process till the multiset is empty. ----- I have used a variable called current minima which keeps track of the current minimum And a multiset which keeps track of all the costs of the current minimum. At any one step, we will discard the largest cost. And increment all the other equal elements by 1. We will update the total cost incurred so far. And we will add (A[i] + 1) cost into our multiset if current minima = (A[i] + 1) And when the multiset is empty, we will make current minima = A[i] again This is to prevent it from timing out by getting stuck ----- #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_magazines; cin >> no_of_magazines; vector > M(no_of_magazines); for(int i = 0; i < no_of_magazines; i++) { cin >> M[i].first; } for(int i = 0; i < no_of_magazines; i++) { cin >> M[i].second; } sort(all(M)); multiset equal_segment; long long current_minima = 0, i = 0; long long total_cost = 0, equal_segment_sum = 0; while(i < M.size() || equal_segment.size() > 0) { while(i < M.size() && M[i].first == current_minima) { equal_segment.insert(M[i].second); equal_segment_sum += M[i].second; i++; } if(equal_segment.size() > 0) { auto it = equal_segment.rbegin(); long long largest = *it; equal_segment.erase(equal_segment.find(largest)); //Erases only one instance of largest equal_segment_sum -= largest; total_cost += equal_segment_sum; current_minima++; } else { current_minima = M[i].first; } } cout << total_cost << "\n"; return 0; } ================================================ FILE: 2020/Div 2/623 Div 2/Explanations/Restoring Permutation Explanation.txt ================================================ We will be greedy. We will keep a set of all integers not used so far. For each B[i], we will take the smallest integer > B[i] which is available and place it in A[2i] If there is no such element, then we will declare it is not possible. We have to erase the element after we use it ----- void solve() { int no_of_elements; cin >> no_of_elements; vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } set available; for(int i = 1; i <= 2*no_of_elements; i++) { available.insert(i); } for(int i = 1; i <= no_of_elements; i++) { available.erase(B[i]); } int possible = true; vector A(2*no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { auto it = available.lower_bound(B[i]); if(it == available.end()) { possible = false; break; } A[2*i - 1] = B[i]; A[2*i] = *(it); available.erase(it); } if(!possible) { cout << "-1\n"; return; } for(int i = 1; i <= 2*no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 2/623 Div 2/Programs/Dead Pixel.cpp ================================================ #include using namespace std; void solve() { int a, b, x, y; cin >> a >> b >> x >> y; x++; y++; int area_1, area_2; if(x > a/2) { area_1 = (x - 1)*b; } else { area_1 = (a - x)*b; } if(y > b/2) { area_2 = a*(y - 1); } else { area_2 = a*(b - y); } int answer = max(area_1, area_2); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/623 Div 2/Programs/Homecoming.cpp ================================================ #include using namespace std; void solve() { int bus, tram, budget; cin >> bus >> tram >> budget; string city; cin >> city; int index = 0, money_so_far = 0; for(int i = city.size() - 2; i >= 0; i--) { if(i == city.size() - 2 || (city[i] != city[i + 1])) { int money_here = (city[i] == 'A' ? bus : tram); //cout << "Money at " << i + 1 << " = " << money_here << " T = " << money_so_far + money_here << "\n"; if(money_so_far + money_here > budget) { index = (i + 1); break; } money_so_far += money_here; } } cout << index + 1 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/623 Div 2/Programs/Recommendations.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_magazines; cin >> no_of_magazines; vector > M(no_of_magazines); for(int i = 0; i < no_of_magazines; i++) { cin >> M[i].first; } for(int i = 0; i < no_of_magazines; i++) { cin >> M[i].second; } sort(all(M)); multiset equal_segment; long long current_minima = 0, i = 0; long long total_cost = 0, equal_segment_sum = 0; while(i < M.size() || equal_segment.size() > 0) { while(i < M.size() && M[i].first == current_minima) { equal_segment.insert(M[i].second); equal_segment_sum += M[i].second; i++; } if(equal_segment.size() > 0) { auto it = equal_segment.rbegin(); long long largest = *it; equal_segment.erase(equal_segment.find(largest)); //Erases only one instance of largest equal_segment_sum -= largest; total_cost += equal_segment_sum; current_minima++; } else { current_minima = M[i].first; } } cout << total_cost << "\n"; return 0; } ================================================ FILE: 2020/Div 2/623 Div 2/Programs/Restoring Permutations.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } set available; for(int i = 1; i <= 2*no_of_elements; i++) { available.insert(i); } for(int i = 1; i <= no_of_elements; i++) { available.erase(B[i]); } int possible = true; vector A(2*no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { auto it = available.lower_bound(B[i]); if(it == available.end()) { possible = false; break; } A[2*i - 1] = B[i]; A[2*i] = *(it); available.erase(it); } if(!possible) { cout << "-1\n"; return; } for(int i = 1; i <= 2*no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Explanations/Contest for Robots Explanation.txt ================================================ Let us count the number of problems, A, which A solves and B does not And B = The number of problems B solves which A does not If (A = 0), then it is impossible to make A win If (A > B), then we can give each problem 1 point and A wins If (A < B), then we can give each problem A solves (B/A) number of points and each problem B solves 1 point. Then, we will start giving problems 1 extra point till their total is > B The answer = (B/A) + 1 ----- int main() { int no_of_robots; cin >> no_of_robots; vector A(no_of_robots + 1); for(int i = 1; i <= no_of_robots; i++) { cin >> A[i]; } vector B(no_of_robots + 1); for(int i = 1; i <= no_of_robots; i++) { cin >> B[i]; } int a_points = 0, b_points = 0; for(int i = 1; i <= no_of_robots; i++) { if(A[i] != 0 && B[i] == 0) { a_points++; } else if(A[i] == 0 && B[i] != 0) { b_points++; } } int answer = 0; if(a_points == 0) { answer = -1; } else if(a_points > b_points) { answer = 1; } else { answer = (b_points/a_points) + 1; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Explanations/Journey Planning Explanation.txt ================================================ We are told that if we move from i to j, then j - i = A[j] - A[i] A[i] - i = A[j] - j This insight is easier to come upon if we think of the problem geometrically and think of the indices as X-axis and the values as Y-axis The value of (A[i] - i) is invariant for a subsequence. So, we will find out the total sum of all possible (A[i] - i) and then give the maximum ------ int main() { int no_of_elements; cin >> no_of_elements; vector beauty(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> beauty[i]; } map answer_for; for(int i = 1; i <= no_of_elements; i++) { answer_for[i - beauty[i]] += beauty[i]; } long long answer = 0; for(auto it = answer_for.begin(); it != answer_for.end(); it++) { answer = max(answer, it->second); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Explanations/Navigation System Explanation.txt ================================================ Let us find the shortest distance of each vertex from the source. Let it be in D To find D in a directed graph, we have to do BFS on the transpose graph ----- void bfs(int source) { queue Q; Q.push(source); D[source] = 0; while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int i = 0; i < transpose_graph[v].size(); i++) { int child = transpose_graph[v][i]; if(D[child] == -1) { D[child] = D[v] + 1; Q.push(child); } } } } ----- Let us go through the stops in order. Suppose we are at stop i, 1. If D[next] + 1 =/= D[v], Then the path will be forced to rebuild This will increase both the minimum and maximum paths by 1 2. If D[next] + 1 = D[v], We will count the number of options If there is more than 1 valid option from v, then The maximum number of paths will increase by 1 ----- int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); transpose_graph[v].push_back(u); } int no_of_stops; cin >> no_of_stops; vector stops(no_of_stops + 1, 0); for(int i = 1; i <= no_of_stops; i++) { cin >> stops[i]; } int source = stops[no_of_stops]; bfs(source); int minimum_paths = 0, maximum_paths = 0; for(int i = 1; i < no_of_stops; i++) { if(D[stops[i + 1]] + 1 != D[stops[i]]) { minimum_paths++; maximum_paths++; continue; } int no_of_options = 0; for(int j = 0; j < graph[stops[i]].size(); j++) { int next = graph[stops[i]][j]; if(D[next] + 1 == D[stops[i]]) { no_of_options++; } } if(no_of_options > 1) { maximum_paths++; } } cout << minimum_paths << " " << maximum_paths << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Explanations/Remove Adjacent Explanation.txt ================================================ We can be greedy and start removing alphabets one by one from Z to A We need S[i - 1] to remove S[i]. We do not need any other alphabets. So, we will remove alphabets starting from the greatest to the least ----- #include #include using namespace std; int main() { int length; string S; cin >> length >> S; int removed = 0; for(int alpha = 'z'; alpha > 'a'; alpha--) { for(int attempts = 1; attempts <= length; attempts++) { for(int i = 0; i < length; i++) { if( (i + 1) < length && S[i] == alpha && S[i] == S[i + 1] + 1) { S.erase(i, 1); removed++; continue; } if( (i - 1) >= 0 && S[i] == alpha && S[i] == S[i - 1] + 1) { S.erase(i, 1); removed++; } } } } cout << removed << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Programs/Contest for Robotos.cpp ================================================ #include #include using namespace std; int main() { int no_of_robots; cin >> no_of_robots; vector A(no_of_robots + 1); for(int i = 1; i <= no_of_robots; i++) { cin >> A[i]; } vector B(no_of_robots + 1); for(int i = 1; i <= no_of_robots; i++) { cin >> B[i]; } int a_points = 0, b_points = 0; for(int i = 1; i <= no_of_robots; i++) { if(A[i] != 0 && B[i] == 0) { a_points++; } else if(A[i] == 0 && B[i] != 0) { b_points++; } } int answer = 0; if(a_points == 0) { answer = -1; } else if(a_points > b_points) { answer = 1; } else { answer = (b_points/a_points) + 1; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Programs/Journey Planning.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector beauty(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> beauty[i]; } map answer_for; for(int i = 1; i <= no_of_elements; i++) { answer_for[i - beauty[i]] += beauty[i]; } long long answer = 0; for(auto it = answer_for.begin(); it != answer_for.end(); it++) { answer = max(answer, it->second); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Programs/Navigation System.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 2e5 + 5; vector graph[MAX_N]; vector transpose_graph[MAX_N]; vector D(MAX_N, -1); void bfs(int source) { queue Q; Q.push(source); D[source] = 0; while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int i = 0; i < transpose_graph[v].size(); i++) { int child = transpose_graph[v][i]; if(D[child] == -1) { D[child] = D[v] + 1; Q.push(child); } } } } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); transpose_graph[v].push_back(u); } int no_of_stops; cin >> no_of_stops; vector stops(no_of_stops + 1, 0); for(int i = 1; i <= no_of_stops; i++) { cin >> stops[i]; } int source = stops[no_of_stops]; bfs(source); int minimum_paths = 0, maximum_paths = 0; for(int i = 1; i < no_of_stops; i++) { if(D[stops[i + 1]] + 1 != D[stops[i]]) { minimum_paths++; maximum_paths++; continue; } int no_of_options = 0; for(int j = 0; j < graph[stops[i]].size(); j++) { int next = graph[stops[i]][j]; if(D[next] + 1 == D[stops[i]]) { no_of_options++; } } if(no_of_options > 1) { maximum_paths++; } } cout << minimum_paths << " " << maximum_paths << "\n"; return 0; } ================================================ FILE: 2020/Div 2/625 Div 2/Programs/Remove Adjacent.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; int removed = 0; for(int alpha = 'z'; alpha > 'a'; alpha--) { for(int attempts = 1; attempts <= length; attempts++) { for(int i = 0; i < length; i++) { if( (i + 1) < length && S[i] == alpha && S[i] == S[i + 1] + 1) { S.erase(i, 1); removed++; continue; } if( (i - 1) >= 0 && S[i] == alpha && S[i] == S[i - 1] + 1) { S.erase(i, 1); removed++; } } } } cout << removed << "\n"; return 0; } ================================================ FILE: 2020/Div 2/626 Div 2/Explanations/Count Subrectangles Explanation.txt ================================================ 1. If A[i] = 0, then the whole i-th row is 0. If B[j] = 0, the whole column j is 0 ----- 2. Ultimately, the matrix consists of some islands (rectangles) of ones seperated by entire lines of 0s. We will keep track of the length of the consecutive segments of 1's both row-wise and column-wise. int rows, columns, area; cin >> rows >> columns >> area; vector A(rows + 5, 0); for(int i = 1; i <= rows; i++) { cin >> A[i]; } vector B(columns + 5, 0); for(int i = 1; i <= columns; i++) { cin >> B[i]; } vector row_segments; row_segments.push_back(0); int segment = 0; for(int i = 1; i <= rows + 1; i++) { if(A[i] == 0 || i == rows + 1) { row_segments.push_back(segment); segment = 0; continue; } segment++; } sort(all(row_segments)); vector row_sum(row_segments.size(), 0); for(int i = 1; i < row_segments.size(); i++) { row_sum[i] = row_sum[i - 1] + row_segments[i]; } vector column_segments; column_segments.push_back(0); segment = 0; for(int i = 1; i <= columns + 1; i++) { if(B[i] == 0 || i == columns + 1) { column_segments.push_back(segment); segment = 0; continue; } segment++; } sort(all(column_segments)); vector column_sum(column_segments.size(), 0); for(int i = 1; i < column_segments.size(); i++) { column_sum[i] = column_sum[i - 1] + column_segments[i]; } ----- 3. Iterate over all factors (f1, f2) of K. Let us count the number of 'row segments' which are more than K and the number of 'column segments' which are more than K Suppose (f1 = 5, f2 = 3) Let us count the number of ways of selecting a row of 5 continuous ones Suppose the lengths of the row segments are - {1, 3, 5, 7, 9} The number of ways of choosing a row segment of length 5 is = (5 - 5 + 1) + (7 - 5 + 1) + (9 - 5 + 1) = 1 + 3 + 4 = 8 So, we need to know 1. The number of elements >= 5 2. The sum of elements >= 5 Then, the number of ways = (9 + 7 + 5) - 3(5 - 1) long long no_of_subrectangles = 0; for(long long i = 1; i*i <= area; i++) { if(area%i == 0) { long long f1 = i, f2 = area/i; long long row_contribution = 0; if(f1 <= row_segments.back()) { int j = upper_bound(all(row_segments), f1 - 1) - row_segments.begin(); row_contribution = (row_sum.back() - row_sum[j - 1]) - (row_segments.size() - 1 - (j - 1))*(f1 - 1); //cout << "Sum = " << (row_sum.back() - row_sum[j - 1]) << " - " //<< (row_segments.size() - 1 - (j - 1))*(f2 - 1) << "\n"; } long long column_contribution = 0; if(f2 <= column_segments.back()) { int j = upper_bound(all(column_segments), f2 - 1) - column_segments.begin(); column_contribution = (column_sum.back() - column_sum[j - 1]) - (column_segments.size() - 1 - (j - 1))*(f2 - 1); } //cout << "Fr = " << f1 << " Fc = " << f2 << " = "; no_of_subrectangles += row_contribution*column_contribution; //cout << no_of_subrectangles << " = " << row_contribution << "x" << column_contribution << "\n"; if(f1 == f2) { continue; } column_contribution = 0; if(f1 <= column_segments.back()) { int j = upper_bound(all(column_segments), f1 - 1) - column_segments.begin(); column_contribution = (column_sum.back() - column_sum[j - 1]) - (column_segments.size() - 1 - (j - 1))*(f1 - 1); } row_contribution = 0; //cout << "F2 = " << f2 << " Back = " << row_segments.back() << "\n"; if(f2 <= row_segments.back()) { int j = upper_bound(all(row_segments), f2 - 1) - row_segments.begin(); row_contribution = (row_sum.back() - row_sum[j - 1]) - (row_segments.size() - 1 - (j - 1))*(f2 - 1); //cout << "Sum = " << (row_sum.back() - row_sum[j - 1]) << " - " //<< (row_segments.size() - 1 - (j - 1))*(f2 - 1) << "\n"; } //cout << "Fr = " << f2 << " Fc = " << f1 << " = "; no_of_subrectangles += row_contribution*column_contribution; //cout << no_of_subrectangles << " = " << row_contribution << "x" << column_contribution << "\n"; } } cout << no_of_subrectangles << "\n"; return 0; ================================================ FILE: 2020/Div 2/626 Div 2/Explanations/Even Subset Sum Problem Explanation.txt ================================================ We will either print 1 even integer or 2 odd integers If there is only 1 odd integer, it is not possible ----- void solve() { int no_of_elements; cin >> no_of_elements; vector odd; vector even; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; if(x%2 == 1) { odd.push_back(i); } else { even.push_back(i); } } if(odd.size() >= 2) { cout << "2\n"; cout << odd[0] << " " << odd[1] << "\n"; return; } if(even.size() >= 1) { cout << "1\n"; cout << even[0] << "\n"; return; } cout << "-1\n"; } ================================================ FILE: 2020/Div 2/626 Div 2/Explanations/Unusual Competitions Explanation.txt ================================================ Let us replace the '(' by +1 and the ')' by -1 We will keep track of the prefix sum If at some point, the sum goes below 0, then we will start our segment from there We will close the segment as soon as the sum reaches 0 This greedy solution works because we ensure each segment is as small as possible ----- int main() { int length; string S; cin >> length >> S; int sum = 0; int answer = 0; for(int left = -1, right = 0; right < length; right++) { sum += (S[right] == '(' ? 1 : -1); if(sum == -1 && left == -1) { left = right; continue; } if(sum == 0) { if(left != -1) { answer += (right - (left - 1)); left = -1; continue; } } } if(sum != 0) { answer = -1; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/626 Div 2/Programs/Counting Subrectangles.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int rows, columns, area; cin >> rows >> columns >> area; vector A(rows + 5, 0); for(int i = 1; i <= rows; i++) { cin >> A[i]; } vector B(columns + 5, 0); for(int i = 1; i <= columns; i++) { cin >> B[i]; } map row_frequency; vector row_segments; row_segments.push_back(0); int segment = 0; for(int i = 1; i <= rows + 1; i++) { if(A[i] == 0 || i == rows + 1) { row_frequency[segment]++; row_segments.push_back(segment); segment = 0; continue; } segment++; } sort(all(row_segments)); vector row_sum(row_segments.size(), 0); for(int i = 1; i < row_segments.size(); i++) { row_sum[i] = row_sum[i - 1] + row_segments[i]; } map column_frequency; vector column_segments; column_segments.push_back(0); segment = 0; for(int i = 1; i <= columns + 1; i++) { if(B[i] == 0 || i == columns + 1) { column_frequency[segment]++; column_segments.push_back(segment); segment = 0; continue; } segment++; } sort(all(column_segments)); vector column_sum(column_segments.size(), 0); for(int i = 1; i < column_segments.size(); i++) { column_sum[i] = column_sum[i - 1] + column_segments[i]; } long long no_of_subrectangles = 0; for(long long i = 1; i*i <= area; i++) { if(area%i == 0) { long long f1 = i, f2 = area/i; long long row_contribution = 0; if(f1 <= row_segments.back()) { int j = upper_bound(all(row_segments), f1 - 1) - row_segments.begin(); row_contribution = (row_sum.back() - row_sum[j - 1]) - (row_segments.size() - 1 - (j - 1))*(f1 - 1); //cout << "Sum = " << (row_sum.back() - row_sum[j - 1]) << " - " //<< (row_segments.size() - 1 - (j - 1))*(f2 - 1) << "\n"; } long long column_contribution = 0; if(f2 <= column_segments.back()) { int j = upper_bound(all(column_segments), f2 - 1) - column_segments.begin(); column_contribution = (column_sum.back() - column_sum[j - 1]) - (column_segments.size() - 1 - (j - 1))*(f2 - 1); } //cout << "Fr = " << f1 << " Fc = " << f2 << " = "; no_of_subrectangles += row_contribution*column_contribution; //cout << no_of_subrectangles << " = " << row_contribution << "x" << column_contribution << "\n"; if(f1 == f2) { continue; } column_contribution = 0; if(f1 <= column_segments.back()) { int j = upper_bound(all(column_segments), f1 - 1) - column_segments.begin(); column_contribution = (column_sum.back() - column_sum[j - 1]) - (column_segments.size() - 1 - (j - 1))*(f1 - 1); } row_contribution = 0; //cout << "F2 = " << f2 << " Back = " << row_segments.back() << "\n"; if(f2 <= row_segments.back()) { int j = upper_bound(all(row_segments), f2 - 1) - row_segments.begin(); row_contribution = (row_sum.back() - row_sum[j - 1]) - (row_segments.size() - 1 - (j - 1))*(f2 - 1); //cout << "Sum = " << (row_sum.back() - row_sum[j - 1]) << " - " //<< (row_segments.size() - 1 - (j - 1))*(f2 - 1) << "\n"; } //cout << "Fr = " << f2 << " Fc = " << f1 << " = "; no_of_subrectangles += row_contribution*column_contribution; //cout << no_of_subrectangles << " = " << row_contribution << "x" << column_contribution << "\n"; } } cout << no_of_subrectangles << "\n"; return 0; } ================================================ FILE: 2020/Div 2/626 Div 2/Programs/Even Subset Sum Problem.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector odd; vector even; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; if(x%2 == 1) { odd.push_back(i); } else { even.push_back(i); } } if(odd.size() >= 2) { cout << "2\n"; cout << odd[0] << " " << odd[1] << "\n"; return; } if(even.size() >= 1) { cout << "1\n"; cout << even[0] << "\n"; return; } cout << "-1\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/626 Div 2/Programs/Unusual Competitions.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; int sum = 0; int answer = 0; for(int left = -1, right = 0; right < length; right++) { sum += (S[right] == '(' ? 1 : -1); if(sum == -1 && left == -1) { left = right; continue; } if(sum == 0) { if(left != -1) { answer += (right - (left - 1)); left = -1; continue; } } } if(sum != 0) { answer = -1; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/628 Div 2/Explanations/Copy Copy Copy Copy Copy Explanation.txt ================================================ We concatenate the array N times with itself We can pick all the distinct elements of the array and that will be the longest increasing subsequence The length of the Longest increasing subsequence cannot be more than the number of distinct elements As there is no element greater than the maximum element ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } set distinct; for(int i = 1; i <= no_of_elements; i++) { distinct.insert(A[i]); } cout << distinct.size() << "\n"; } ================================================ FILE: 2020/Div 2/628 Div 2/Explanations/Ehab and GCD Explanation.txt ================================================ We can use (1, x - 1) gcd(1, x - 1) = 1 lcm(1, x - 1) = x - 1 gcd(1, x - 1) + lcm(1, x - 1) = x ----- #include using namespace std; void solve() { long long x; cin >> x; cout << "1 " << x - 1 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/628 Div 2/Explanations/Ehab and Path-etic MEX Explanation.txt ================================================ The crucial insight here is that there will always be a path running through any 2 edges. So, there will always be a path that runs through both 0 and 1 and will have MEX = 2 Now, is there a way, we can avoid having 2 on the same path as (0, 1) ? The only way to do this is if some vertex had degree >= 3 and we label it 0, 1, 2 The mex of every path not containing 0 or 1 will be 0 or 1 The mex of every path containing both 0 and 1 will be 2 ------ My strategy was to start with the leaves and maintain a queue of them. After labelling an edge (u, v), we delete the edge and add u to our queue if u is now a leaf If the tree has at least 3 leaves, then it ensures that there is no path passing through (0, 1, 2) since there can be no path that hits 3 leaves. If the tree has only 2 leaves, then it is a bamboo and any labelling we do won't matter ---- ================================================ FILE: 2020/Div 2/628 Div 2/Explanations/Ehab and XORcist Explanation.txt ================================================ Suppose U = 110001 V = 1100001 I will keep track of the frequency of all 64 bits So initially, it will be U = 110001 Now, the sum I have to still make is V - U = 110000 So here is what I will do First 4 bits nothing Then, I'll go to the fifth bit [11:34 PM, 3/14/2020] Saikat: Presently, my answer is 110001 The sum has a 2^5 in the fifth spot I cannot make it 120001 The reason is the XOR in that spot is 1 So instead of adding 2^5, I will add two 2^4's 11 2 001 Then, I will go to the sixth bit I can't add a 1 in there. Here are my options - (2) 12001 1 (3) 2001 11 (6) 001 112 (8) 01 1120 (16) 1 11200 (32) Among all these options, 1 3 2001 is the best ----- 1. Keep track of frequency of each bit 2. Initially, set it to XOR 3. Then, look at the remaining sum 4. After that go bit by bit. If the i-th bit is set in the remaining sum, then we can either Add 2 bits of (i - 1) Add 4 bits of (i - 2) Add 8 bits of (i - 3) Add 16 bits of (i - 4) . . Add 2^m bits of (i - m) All these choices add an even number of summands so XOR does not change Among all these options, we will choose the one which minimises the number of summands ----- It is not possible if (u > v) or if u =!= v (mod 2) The reason is that the bits in the last position must be either even or odd and can't be both If u = v = 0, then the answer is 0 Else if u = v, the answer is 1 ----- There is a simpler solution If the answer is possible and not 0 or 1, then it is always at most 3 (u + v)/2, (u - v)/2, v works ----- int some_non_zero(vector &A) { for(int i = 0; i < A.size(); i++) { if(A[i] > 0) { return true; } } return false; } int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0); } int main() { long long array_xor, array_sum; cin >> array_xor >> array_sum; if(array_xor > array_sum || (array_xor%2 != array_sum%2)) { cout << "-1\n"; return 0; } if(array_xor == array_sum) { if(array_xor == 0) { cout << "0\n"; } else { cout << "1\n"; cout << array_xor << "\n"; } return 0; } const int MAX_BITS = 63; vector frequency(MAX_BITS, 0); for(int bit = 0; bit < MAX_BITS; bit++) { if(is_bit_set(array_xor, bit)) { array_sum -= (1LL << bit); frequency[bit]++; } } for(int bit = 0; bit < MAX_BITS; bit++) { if(is_bit_set(array_sum, bit)) { int best_spot = max(bit - 1, 0); long long best_no_of_terms = frequency[best_spot] + 2; for(int i = bit - 1; i >= 0; i--) { if(frequency[i] + (1LL << (bit - i)) <= best_no_of_terms) { best_no_of_terms = frequency[i] + (1LL << (bit - i)); best_spot = i; } } frequency[best_spot] += (1LL << (bit - best_spot)); array_sum -= (1LL << bit); } } vector A; while(some_non_zero(frequency)) { long long current = 0; for(int bit = 0; bit < MAX_BITS; bit++) { if(frequency[bit] > 0) { current |= (1LL << bit); frequency[bit]--; } } A.push_back(current); } long long xorr = 0, sum = 0; cout << A.size() << "\n"; for(int i = 0; i < A.size(); i++) { cout << A[i] << " "; xorr ^= A[i]; sum += A[i]; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/628 Div 2/Programs/Copy Copy Copy Copy Copy.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } set distinct; for(int i = 1; i <= no_of_elements; i++) { distinct.insert(A[i]); } cout << distinct.size() << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/628 Div 2/Programs/Ehab and GCD.cpp ================================================ #include using namespace std; void solve() { long long x; cin >> x; cout << "1 " << x - 1 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/628 Div 2/Programs/Ehab and Pathetic MEX.cpp ================================================ #include #include #include #include #include using namespace std; const int MAX_N = 1e5 + 5; vector > tree; queue leaves; void remove(int u, int v) { tree[u].erase(v); tree[v].erase(u); if(tree[u].size() == 1) { leaves.push(u); } if(tree[v].size() == 1) { leaves.push(v); } } int main() { int no_of_vertices; cin >> no_of_vertices; int no_of_edges = no_of_vertices - 1; tree.resize(no_of_vertices + 1); map , int> edge_no; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].insert(v); tree[v].insert(u); edge_no[make_pair(u, v)] = i; edge_no[make_pair(v, u)] = i; } for(int i = 1; i <= no_of_vertices; i++) { if(tree[i].size() == 1) { leaves.push(i); } } int last_label = 0; vector label(no_of_edges + 1, 0); while(leaves.size() > 0) { int current_v = leaves.front(); leaves.pop(); auto v_it = tree[current_v].begin(); int current_u = *v_it; remove(current_u, current_v); /* cout << "L = " << current_v << "," << current_u << " Edge No = " << edge_no[make_pair(current_u, current_v)] << " edgeLabel = " << last_label << "\n";*/ label[edge_no[make_pair(current_u, current_v)]] = last_label++; } for(int i = 1; i <= no_of_edges; i++) { cout << label[i] << "\n"; } return 0; } ================================================ FILE: 2020/Div 2/628 Div 2/Programs/Ehab and XORcist.cpp ================================================ #include #include using namespace std; int some_non_zero(vector &A) { for(int i = 0; i < A.size(); i++) { if(A[i] > 0) { return true; } } return false; } int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0); } int main() { long long array_xor, array_sum; cin >> array_xor >> array_sum; if(array_xor > array_sum || (array_xor%2 != array_sum%2)) { cout << "-1\n"; return 0; } if(array_xor == array_sum) { if(array_xor == 0) { cout << "0\n"; } else { cout << "1\n"; cout << array_xor << "\n"; } return 0; } const int MAX_BITS = 63; vector frequency(MAX_BITS, 0); for(int bit = 0; bit < MAX_BITS; bit++) { if(is_bit_set(array_xor, bit)) { array_sum -= (1LL << bit); frequency[bit]++; } } for(int bit = 0; bit < MAX_BITS; bit++) { if(is_bit_set(array_sum, bit)) { int best_spot = max(bit - 1, 0); long long best_no_of_terms = frequency[best_spot] + 2; for(int i = bit - 1; i >= 0; i--) { if(frequency[i] + (1LL << (bit - i)) <= best_no_of_terms) { best_no_of_terms = frequency[i] + (1LL << (bit - i)); best_spot = i; } } frequency[best_spot] += (1LL << (bit - best_spot)); array_sum -= (1LL << bit); } } vector A; while(some_non_zero(frequency)) { long long current = 0; for(int bit = 0; bit < MAX_BITS; bit++) { if(frequency[bit] > 0) { current |= (1LL << bit); frequency[bit]--; } } A.push_back(current); } long long xorr = 0, sum = 0; cout << A.size() << "\n"; for(int i = 0; i < A.size(); i++) { cout << A[i] << " "; xorr ^= A[i]; sum += A[i]; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Explanations/Composite Coloring Explanation.txt ================================================ We need to make 1 observation If a number is smaller than 1000, it must have at least 1 prime factor <= 31 If a number has 2 prime factors > 31, then it's product will be at least 37*37 > 1000 This means that the smallest prime factor of n will be one of {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31} We will colour all integers with the same 'smallest prime factor' the same colour This guarantees that two integers with the same 'smallest prime factor' are not coprime as their gcd = common smallest prime factor ----- void precompute(vector &lowest_prime_factor, int N) { for(long long i = 2; i < N; i++) { if(lowest_prime_factor[i] != 0) { continue; } for(long long multiple = i; multiple < N; multiple += i) { if(lowest_prime_factor[multiple] == 0) { lowest_prime_factor[multiple] = i; } } } } void solve(vector &lowest_prime_factor) { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector position({2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 31}); vector colour(no_of_elements + 1, 0); set distinct; vector distinct_colours; for(int i = 1; i <= no_of_elements; i++) { colour[i] = upper_bound(position.begin(), position.end(), lowest_prime_factor[A[i]]) - position.begin(); if(distinct.find(colour[i]) == distinct.end()) { distinct.insert(colour[i]); distinct_colours.push_back(colour[i]); } } sort(distinct_colours.begin(), distinct_colours.end()); int no_of_colours = 0; for(int i = 1; i <= no_of_elements; i++) { colour[i] = upper_bound(distinct_colours.begin(), distinct_colours.end(), colour[i]) - distinct_colours.begin(); no_of_colours = max(no_of_colours, colour[i]); } cout << no_of_colours << "\n"; for(int i = 1; i <= no_of_elements; i++) { cout << colour[i] << " "; } cout << "\n"; } int main() { const int MAX_N = 1001; vector lowest_prime_factor(MAX_N, 0); precompute(lowest_prime_factor, MAX_N); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) { solve(lowest_prime_factor); } return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Explanations/Exercising Walk Explanation.txt ================================================ The X and Y axes are independent of each other. The optimal solution is to use a 'waiting' move. Keep going [L, R] till there is only one path left and then follow it It has to be within [X1, X2] and [Y1, Y2] We have to check the case where (X1 = X2) or (Y1 = Y2) seperately as it is not possible to make even 1 move ----- void solve() { long long up, down, left, right; cin >> left >> right >> down >> up; long long x, y, x1, y1, x2, y2; cin >> x >> y >> x1 >> y1 >> x2 >> y2; if(x1 == x2) { if(left + right > 0) { cout << "NO\n"; return; } } else { long long end = x - left + right; if(end < x1 || x2 < end) { cout << "NO\n"; return; } } if(y1 == y2) { if(up + down > 0) { cout << "NO\n"; return; } } else { long long end = y - down + up; if(end < y1 || y2 < end) { cout << "NO\n"; return; } } cout << "Yes\n"; } ================================================ FILE: 2020/Div 2/630 Div 2/Explanations/Height All The Same Explanation.txt ================================================ We have to make 2 crucial observations 1. The integer doesn't matter. Only the parity matters. We can make all integers of the same parity equal. 2. It is possible to flip the parities of two cells u and v on the board, no matter where they are ! Suppose there is a path from u to v u t1 t2 t3 ... tk v We will apply the second operation to (u, t1) (t1, t2) . . , (tk, v) u and v increase by 1 whereas all others increase by 2. This means that we can flip the parities of any two cells together. ----- If there are an even number of even cells, we can make them all odd If there are an even number of odd cells, we can make them all even The only situation where we can't make all integers equal is when there are an odd number of even as well odd number of odd cells ----- Now, let us try to count the number of boards. Let G = MN Let the number of ways to fill a cell be R - (L - 1) = N Now, if G is odd, then there must be either an even number of odd cells or an even number of even cells So every board is good. In that case, the answer = N^G ------ What is G is even ? We want the cases where either there are an even number of Even cells or even number of Odd cells Let the number of ways to fill a cell with an even number be E Let the number of ways to fill a cell with an odd number be O We want C(G, 0) E^0 O^G + C(G, 2) E^2 O^{G - 2} + ... + C(G, G) E^G O^0 There is a beautiful combinatoric trick for this This is basically the expansion of (O + E)^G with the odd terms removed Let us look at the expansion of (O + E)^G ! Here, all the odd terms have a negative sign ! So, (O + E)^G + (O + E)^G gives us twice the number we want. So, we have to divide this by 2. We have to be careful that we are dealing it via MOD, so we have to multiply with inverse(2) rather than divide by 2 ----- #include using namespace std; long long power_mod(long long x, long long power, long long MOD) { long long result = 1; while(power) { if(power%2) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } long long inverse(long long x, long long MOD) { return power_mod(x, MOD - 2, MOD); } int main() { long long rows, columns, left, right; cin >> rows >> columns >> left >> right; long long grid = rows*columns; long long answer = 1; const int MOD = 998244353; if(grid%2 == 1) { long long one_cell = right - (left - 1); answer = power_mod(one_cell, grid, MOD); } else { long long even_cells = right/2 - (left - 1)/2; long long odd_cells = (right - (left - 1)) - even_cells; answer = (power_mod(odd_cells + even_cells, grid, MOD) + power_mod(even_cells - odd_cells, grid, MOD))%MOD; answer *= inverse(2, MOD); answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Explanations/K Complete Word Explanation.txt ================================================ Let f(i, alpha) be the frequency of alphabet 'alpha' in positions = i (mod k) We will compute this first. Now, the character at 0 (mod k) must be the same character at K - 1 (mod k) ----- We will go through all positions mod k and find the cost of making it = alpha The number of steps in making all positions = i and j (mod k) = alpha is total_i - frequency(i, alpha) + total_j - frequency(j, alpha) ----- void solve() { const int NO_OF_ALPHABETS = 26; int length, period; cin >> length >> period; vector > frequency(period, vector (NO_OF_ALPHABETS + 1, 0)); string S; cin >> S; for(int i = 0; i < length; i++) { frequency[i%period][S[i] - 'a']++; } int minimum_moves = 0; for(int i = 0, j = period - 1; i <= j; i++, j--) { int moves_here = length; if(i == j) { int total = length/period + (length%period >= i && i > 0); for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { moves_here = min(moves_here, total - frequency[i][alpha]); } } else { int total_i = length/period + (length%period >= i && i > 0); int total_j = length/period + (length%period >= j); for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { moves_here = min(moves_here, total_i - frequency[i][alpha] + total_j - frequency[j][alpha]); } } //cout << "I = " << i << " J = " << j << " Moves = " << moves_here << "\n"; minimum_moves += moves_here; } cout << minimum_moves << "\n"; } ================================================ FILE: 2020/Div 2/630 Div 2/Explanations/Walk on Matrix Explanation.txt ================================================ Here is the basic idea - We will make a matrix such that the DP matrix gives 0 as the answer and the actual answer is k. Here, is what we will do. Suppose, k = 10101 We need 3 integers 1. The 'Full Form' = 111111 2. The MSB = 100000 3. Complement = 101010 Here is the 3x3 matrix we will create - 111111 010101 101010 100000 010101 101010 111111 111111 010101 ----- Here is the DP Matrix 111111 010101 000000 100000 010101 000000 100000 100000 000000 ----- The Answer in the DP Matrix is 0, and the answer in the original matrix is 010101, Which is what is required. ----- k = 0 is a special case where we will print a single integer ----- How do we get this idea ? Look at the example test case given. We must create a matrix where following the DP path will always gives 0. We do this by adding an additional bit and setting it so it has no bit in common with k And then try to create a path in such a way that the DP path will give the answer = 0 The DP Path makes the answer 0 The optimal path gives us the answer k ----- int is_bit_set(int n, int bit) { return ((n&(1LL << bit)) != 0); } int all_ones(int n) { return ( (n&(n + 1)) == 0); } int get_msb(int n) { for(int bit = MAX_BITS; bit >= 0; bit--) { if(is_bit_set(n, bit)) { return bit; } } return 0; } int complete(int n) { int most_significant_bit = get_msb(n); int complete_n = 0; for(int bit = most_significant_bit; bit >= 0; bit--) { complete_n |= (1LL << bit); } return complete_n; } int main() { int n; cin >> n; if(n == 0) { cout << "1 1\n"; cout << "1\n"; return 0; } int full_form = (all_ones(n) ? 4*n + 3: 2*complete(n) + 1); int complement = full_form - n; int msb = (1 << get_msb(full_form)); matrix[1][1] = full_form; matrix[1][2] = n; matrix[1][3] = complement; matrix[2][1] = msb; matrix[2][2] = n; matrix[2][3] = complement; matrix[3][1] = full_form; matrix[3][2] = full_form; matrix[3][3] = n; cout << "3 3\n"; for(int i = 1; i <= 3; i++) { for(int j = 1; j <= 3; j++) { cout << matrix[i][j] << " "; } cout << "\n"; } /*dp[0][1] = matrix[1][1]; for(int i = 1; i <= 3; i++) { for(int j = 1; j <= 3; j++) { dp[i][j] = max(matrix[i][j]&dp[i - 1][j], matrix[i][j]&dp[i][j - 1]); cout << dp[i][j] << " "; } cout << "\n"; }*/ return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Programs/Composite Coloring.cpp ================================================ #include #include #include #include using namespace std; void precompute(vector &lowest_prime_factor, int N) { for(long long i = 2; i < N; i++) { if(lowest_prime_factor[i] != 0) { continue; } for(long long multiple = i; multiple < N; multiple += i) { if(lowest_prime_factor[multiple] == 0) { lowest_prime_factor[multiple] = i; } } } } void solve(vector &lowest_prime_factor) { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector position({2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 31}); vector colour(no_of_elements + 1, 0); set distinct; vector distinct_colours; for(int i = 1; i <= no_of_elements; i++) { colour[i] = upper_bound(position.begin(), position.end(), lowest_prime_factor[A[i]]) - position.begin(); if(distinct.find(colour[i]) == distinct.end()) { distinct.insert(colour[i]); distinct_colours.push_back(colour[i]); } } sort(distinct_colours.begin(), distinct_colours.end()); int no_of_colours = 0; for(int i = 1; i <= no_of_elements; i++) { colour[i] = upper_bound(distinct_colours.begin(), distinct_colours.end(), colour[i]) - distinct_colours.begin(); no_of_colours = max(no_of_colours, colour[i]); } cout << no_of_colours << "\n"; for(int i = 1; i <= no_of_elements; i++) { cout << colour[i] << " "; } cout << "\n"; } int main() { const int MAX_N = 1001; vector lowest_prime_factor(MAX_N, 0); precompute(lowest_prime_factor, MAX_N); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) { solve(lowest_prime_factor); } return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Programs/Exercising Walk.cpp ================================================ #include using namespace std; void solve() { long long up, down, left, right; cin >> left >> right >> down >> up; long long x, y, x1, y1, x2, y2; cin >> x >> y >> x1 >> y1 >> x2 >> y2; if(x1 == x2) { if(left + right > 0) { cout << "NO\n"; return; } } else { long long end = x - left + right; if(end < x1 || x2 < end) { cout << "NO\n"; return; } } if(y1 == y2) { if(up + down > 0) { cout << "NO\n"; return; } } else { long long end = y - down + up; if(end < y1 || y2 < end) { cout << "NO\n"; return; } } cout << "Yes\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Programs/Height All the Same.cpp ================================================ #include using namespace std; long long power_mod(long long x, long long power, long long MOD) { long long result = 1; while(power) { if(power%2) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } long long inverse(long long x, long long MOD) { return power_mod(x, MOD - 2, MOD); } int main() { long long rows, columns, left, right; cin >> rows >> columns >> left >> right; long long grid = rows*columns; long long answer = 1; const int MOD = 998244353; if(grid%2 == 1) { long long one_cell = right - (left - 1); answer = power_mod(one_cell, grid, MOD); } else { long long one_cell = (right - (left - 1)); long long even_cells = right/2 - (left - 1)/2; long long odd_cells = (right - (left - 1)) - even_cells; if(one_cell%2 == 0) { answer = power_mod(one_cell, grid, MOD); } else { answer = power_mod(one_cell, grid, MOD) + 1; } //answer = (power_mod(odd_cells + even_cells, grid, MOD) + power_mod(even_cells - odd_cells, grid, MOD))%MOD; answer *= inverse(2, MOD); answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Programs/K Complete Word.cpp ================================================ #include #include using namespace std; void solve() { const int NO_OF_ALPHABETS = 26; int length, period; cin >> length >> period; vector > frequency(period, vector (NO_OF_ALPHABETS + 1, 0)); string S; cin >> S; for(int i = 0; i < length; i++) { frequency[i%period][S[i] - 'a']++; } int minimum_moves = 0; for(int i = 0, j = period - 1; i <= j; i++, j--) { int moves_here = length; if(i == j) { int total = length/period + (length%period >= i && i > 0); for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { moves_here = min(moves_here, total - frequency[i][alpha]); } } else { int total_i = length/period + (length%period >= i && i > 0); int total_j = length/period + (length%period >= j); for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { moves_here = min(moves_here, total_i - frequency[i][alpha] + total_j - frequency[j][alpha]); } } //cout << "I = " << i << " J = " << j << " Moves = " << moves_here << "\n"; minimum_moves += moves_here; } cout << minimum_moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/630 Div 2/Programs/Walk on Matrix.cpp ================================================ #include using namespace std; const int MAX_N = 3 + 2, MAX_BITS = 25; int matrix[MAX_N][MAX_N], dp[MAX_N][MAX_N]; int is_bit_set(int n, int bit) { return ((n&(1LL << bit)) != 0); } int all_ones(int n) { return ( (n&(n + 1)) == 0); } int get_msb(int n) { for(int bit = MAX_BITS; bit >= 0; bit--) { if(is_bit_set(n, bit)) { return bit; } } return 0; } int complete(int n) { int most_significant_bit = get_msb(n); int complete_n = 0; for(int bit = most_significant_bit; bit >= 0; bit--) { complete_n |= (1LL << bit); } return complete_n; } int main() { int n; cin >> n; if(n == 0) { cout << "1 1\n"; cout << "1\n"; return 0; } int full_form = (all_ones(n) ? 4*n + 3: 2*complete(n) + 1); int complement = full_form - n; int msb = (1 << get_msb(full_form)); matrix[1][1] = full_form; matrix[1][2] = n; matrix[1][3] = complement; matrix[2][1] = msb; matrix[2][2] = n; matrix[2][3] = complement; matrix[3][1] = full_form; matrix[3][2] = full_form; matrix[3][3] = n; cout << "3 3\n"; for(int i = 1; i <= 3; i++) { for(int j = 1; j <= 3; j++) { cout << matrix[i][j] << " "; } cout << "\n"; } /*dp[0][1] = matrix[1][1]; for(int i = 1; i <= 3; i++) { for(int j = 1; j <= 3; j++) { dp[i][j] = max(matrix[i][j]&dp[i - 1][j], matrix[i][j]&dp[i][j - 1]); cout << dp[i][j] << " "; } cout << "\n"; }*/ return 0; } ================================================ FILE: 2020/Div 2/631 Div 2/Explanations/Dreamoon Likes Coloring Explanation.txt ================================================ Firstly, if the sum is less than N, it is not possible Secondly, if any A[i] > (n - i), then it means that it must begin in one of the first (i - 1) squares. This means it would over write one of the (i - 1) colours. ----- Suppose, these two conditions are not there, then it is always possible. When we paint the i-th colour, we want to be able to paint the entire thing. So, the i-th colour cannot start < i, because (i - 1) colours have been used and they each have at least 1 colour each. We also want to paint the whole thing, so A[i] should not start before (N - suffix_sum[i]) otherwise we can't paint the whole thing. i-th colour should start at max(i, N - suffix_sum[i]) ----- Now, if i starts at a position > i, we can be sure all the cells before it are coloured Since the (i - 1)-th colour started at a point where suffix_sum(i - 1) was enough to cover the entire thing ----- int main() { int no_of_cells, no_of_elements; cin >> no_of_cells >> no_of_elements; vector A(no_of_elements + 5); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { if(A[i] + i - 1 > no_of_cells) { cout << "-1\n"; return 0; } } vector suffix_sum(no_of_elements + 5, 0); for(int i = no_of_elements; i >= 1; i--) { suffix_sum[i] = A[i] + suffix_sum[i + 1]; } if(suffix_sum[1] < no_of_cells) { cout << "-1\n"; return 0; } for(long long i = 1; i <= no_of_elements; i++) { cout << max(i, no_of_cells - suffix_sum[i] + 1) << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/631 Div 2/Explanations/Dreamoon Likes Permutations Explanation.txt ================================================ 1. Let p[i] represent the smallest integer which is not present in A[1, i] 2. Let s[i] represent the smallest integer which is not present in A[i, n] 3. We will precompute this in O(N log N) time. 4. (i, n - i) is good if p[i] = (i + 1) and s[i + 1] = (n - i) + 1 5. Count the number of i which satisfy the above condition ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } set S; for(int i = 1; i <= no_of_elements; i++) { S.insert(i); } vector prefix_mex(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { if(S.find(A[i]) != S.end()) { S.erase(A[i]); } prefix_mex[i] = *(S.begin()); } for(int i = 1; i <= no_of_elements; i++) { S.insert(i); } vector suffix_mex(no_of_elements + 1); for(int i = no_of_elements; i >= 1; i--) { if(S.find(A[i]) != S.end()) { S.erase(A[i]); } suffix_mex[i] = *(S.begin()); } vector > answer; for(int i = 1; i < no_of_elements; i++) { if(prefix_mex[i] == i + 1 && suffix_mex[i + 1] == no_of_elements - i + 1) { answer.push_back(make_pair(i, no_of_elements - i)); } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i].first << " " << answer[i].second << "\n"; } } ================================================ FILE: 2020/Div 2/631 Div 2/Explanations/Dreamoon Likes Sequences Explanation.txt ================================================ Fact - Two consecutive integers in the sequence cannot have the same MSB Suppose, we have 2 elements A[i] and A[i + 1] that have the same MSB - b Then, the prefix XOR (i + 1) will not have the b-th bit set. This means that A[i] > B[i + 1], which should not happen. ----- The integers must be in ascending order. Let b(i) be the number of integers with MSB = i Then, the number of sequences of length 3 for example is b(1) b(2) b(3) b(1) b(2) b(4) b(1) b(2) b(5) . . and so on till b(28) b(29) b(30) ----- We can compute the number of sequences of length i with a DP Let f(i, last) be the number of sequences of length i having b(last) in the i-th position This is = sum{b(last)*f(i - 1, second_last)}, For all seecond_last < last ----- The only thing left to do is to calculate B(i) if i = MSB, then b(i) = n - (2^i) + 1 For example, if n = 1001001, Then all integers in [1 000000, 1 001001] should count, which is why B(6) = n - 2^6 + 1 If i < MSB, then b(i) = 2^i, as every combination of the last (i - 1) bits is allowed ---- void solve() { int d, mod; cin >> d >> mod; const int MAX_BITS = 31; vector < vector > no_of_ways(MAX_BITS + 1, vector (MAX_BITS + 1, 0)); vector frequency(MAX_BITS + 1, 0); for(int msb = false, bit = MAX_BITS; bit >= 0; bit--) { if(msb) { frequency[bit] = (1LL << bit); //cout << "Frequency " << bit << " = " << frequency[bit] << "\n"; continue; } if(is_bit_set(d, bit)) { if(!msb) { msb = true; frequency[bit] = d - (1 << bit) + 1; //cout << "Frequency " << bit << " = " << frequency[bit] << "\n"; } continue; } } for(int length = 1; length <= min(d, MAX_BITS); length++) { for(int last = 0; last <= MAX_BITS; last++) { if(length == 1) { no_of_ways[length][last] = frequency[last]; //cout << "F(" << length << "," << last << ") = " << no_of_ways[length][last] << "\n"; continue; } for(int second_last = 0; second_last <= last - 1; second_last++) { no_of_ways[length][last] += (frequency[last]*no_of_ways[length - 1][second_last])%mod; no_of_ways[length][last] %= mod; } //cout << "F(" << length << "," << last << ") = " << no_of_ways[length][last] << "\n"; } } long long answer = 0; for(int length = 1; length <= MAX_BITS; length++) { for(int bit = 0; bit <= MAX_BITS; bit++) { answer += no_of_ways[length][bit]; answer %= mod; } } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/631 Div 2/Explanations/Dreamoon and Ranking Collection Explanation.txt ================================================ The question is basically this Add x elements to the array and give the greatest integer v such that all integers from [1, v] are there in this array of length (n + x) We will maintain a boolean array of which elements are already there in the array. We will go from 1 to as large an integer as we can and fill up the first x 'empty' spots. ------ void solve() { int no_of_elements, x; cin >> no_of_elements >> x; const int MAX = 1e5; vector used(MAX, false); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; used[A[i]] = true; } int answer = 0; for(int i = 1; i < MAX; i++) { if(!used[i]) { if(x == 0) { answer = i - 1; break; } else { x--; used[i] = true; } } } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/631 Div 2/Programs/Dreamoon Likes Coloring.cpp ================================================ #include #include using namespace std; int main() { int no_of_cells, no_of_elements; cin >> no_of_cells >> no_of_elements; vector A(no_of_elements + 5); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { if(A[i] + i - 1 > no_of_cells) { cout << "-1\n"; return 0; } } vector suffix_sum(no_of_elements + 5, 0); for(int i = no_of_elements; i >= 1; i--) { suffix_sum[i] = A[i] + suffix_sum[i + 1]; } if(suffix_sum[1] < no_of_cells) { cout << "-1\n"; return 0; } for(long long i = 1; i <= no_of_elements; i++) { cout << max(i, no_of_cells - suffix_sum[i] + 1) << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/631 Div 2/Programs/Dreamoon Likes Permutations.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } set S; for(int i = 1; i <= no_of_elements; i++) { S.insert(i); } vector prefix_mex(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { if(S.find(A[i]) != S.end()) { S.erase(A[i]); } prefix_mex[i] = *(S.begin()); } for(int i = 1; i <= no_of_elements; i++) { S.insert(i); } vector suffix_mex(no_of_elements + 1); for(int i = no_of_elements; i >= 1; i--) { if(S.find(A[i]) != S.end()) { S.erase(A[i]); } suffix_mex[i] = *(S.begin()); } vector > answer; for(int i = 1; i < no_of_elements; i++) { if(prefix_mex[i] == i + 1 && suffix_mex[i + 1] == no_of_elements - i + 1) { answer.push_back(make_pair(i, no_of_elements - i)); } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i].first << " " << answer[i].second << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/631 Div 2/Programs/Dreamoon Likes Sequences.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0 ); } void solve() { int d, mod; cin >> d >> mod; const int MAX_BITS = 31; vector < vector > no_of_ways(MAX_BITS + 1, vector (MAX_BITS + 1, 0)); vector frequency(MAX_BITS + 1, 0); for(int msb = false, bit = MAX_BITS; bit >= 0; bit--) { if(msb) { frequency[bit] = (1LL << bit); continue; } if(is_bit_set(d, bit)) { if(!msb) { msb = true; frequency[bit] = d - (1 << bit) + 1; } continue; } } for(int length = 1; length <= min(d, MAX_BITS); length++) { for(int last = 0; last <= MAX_BITS; last++) { if(length == 1) { no_of_ways[length][last] = frequency[last]; continue; } for(int second_last = 0; second_last <= last - 1; second_last++) { no_of_ways[length][last] += (frequency[last]*no_of_ways[length - 1][second_last])%mod; no_of_ways[length][last] %= mod; } } } long long answer = 0; for(int length = 1; length <= MAX_BITS; length++) { for(int bit = 0; bit <= MAX_BITS; bit++) { answer += no_of_ways[length][bit]; answer %= mod; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/631 Div 2/Programs/Dreamoon and Ranking Collection.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, x; cin >> no_of_elements >> x; const int MAX = 1e5; vector used(MAX, false); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; used[A[i]] = true; } int answer = 0; for(int i = 1; i < MAX; i++) { if(!used[i]) { if(x == 0) { answer = i - 1; break; } else { x--; used[i] = true; } } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/632 Div 2/Explanations/Eugene and Array Explanation.txt ================================================ We will iterate from i = 1 to N, and count the number of good subarrays ending at each i Let [L1, R1], [L2, R2], ... , [Lk, Rk] be all the subarrays upto i, such that their sum is 0. Let Lk be the greatest of all the Lk's Then, [Lk + 1, i] [Lk + 2, i] [Lk + 3, i] . . . [i, i] are all good subarrays as there is no subarrays inside such that the sum is 0. ----- Now, the only question is how do we find the largest end_point L_k ? Let us make an observation If Sum[L, R] = 0, then Sum[R] - Sum[L - 1] = 0 Sum[R] = Sum[L - 1] We will keep track of the prefix sum and the last occurrence of every Sum[i] Now, when we are at i, we will check if Sum[i] has occurred before by checking it's frequency ! If frequency[Sum[i]] > 0, then it means it has occurred before, we will look at the rightmost position where Sum[i] has occurred ----- Let it be L Then, end point = max(end_point, L + 2) Why L + 2 ? Because Sum[i] = Sum[L] So Sum[L + 1, i] = 0 From [L + 2, i] is the first (possibly) good array) That is why end point = max(end_point, L + 2) ----- For every i, we have updated end_point, so end_point always is the point from which [end_point, i] is a good array. Now, we have to ensure that end_point <= i The number of good arrays ending at i is (i - end_point + 1) ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = prefix_sum[i - 1] + A[i]; } int end_point = 0; map frequency; map last_occurence; frequency[0] = 1; long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { if(frequency[prefix_sum[i]] != 0) { end_point = max(end_point, last_occurence[prefix_sum[i]] + 2); } last_occurence[prefix_sum[i]] = i; frequency[prefix_sum[i]] = i; int distance = (end_point == 0 ? i : i - end_point + 1); answer += (distance > 0 ? distance : 0); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/632 Div 2/Explanations/Kate and Imperfection Explanation.txt ================================================ Here is the optimal approach 1. We will use all the prime numbers first. The imperfection remains 1 2. Once we are done, we must use a composite integer. And the imperfection will increase We will put 4 next, and then we will put in 6 so that the gcd becomes 3 If we put 8, the gcd becomes 4 3. The editorial has a very nice proof. Suppose we have k integers in our set - {A1, A2, ... , Ak}, then for every integer Ai, all it's divisors are also there. Let us suppose for some Ai, there is a divisor of Ai = x that is not in the set We can remove Ai from the set and put in x The gcd will not increase and the answer will remain the same So, we can use the following constructive idea An integer will be added to the set after all it's divisors have been added ----- How do we do this ? We can use a sieve to find out the greatest divisor of all the integers Then, we will sort them by their greatest divisor For the answer for k, we will choose the first k elements The gcd will be equal to the greatest divisor of A[k] since it's divisor is already in the set ----- int main() { int n; cin >> n; vector largest_divisor(n + 1, 1); for(int i = 1; i <= n; i++) { for(int multiple = 2*i; multiple <= n; multiple += i) { largest_divisor[multiple] = i; } } sort(largest_divisor.begin(), largest_divisor.end()); for(int i = 2; i <= n; i++) { cout << largest_divisor[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/632 Div 2/Explanations/Kind Anton Explanation.txt ================================================ The important constraint here is that the condition (j < i) is maintained So, we will start transforming A from the last element to the first While at i, we will check if (A[i] < B[i]), and see if there is a +1 in the prefix_sum And if (A[i] > B[i]), we will check if there is a -1 in the prefix We will go through the array and check if these conditions are maintained ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1), B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } int positive = false, negative = false, possible = true;; for(int i = 1; i <= no_of_elements; i++) { if(A[i] < B[i]) { if(!positive) { possible = false; } } if(A[i] > B[i]) { if(!negative) { possible = false; } } if(A[i] == 1) { positive = true; } if(A[i] == -1) { negative = true; } } cout << (possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/632 Div 2/Explanations/Little Artem Explanation.txt ================================================ Case 1 - Suppose M, N are both odd We will colour the board like a chessboard with the first square being black The number of squares is odd so there is 1 more black cell than white cell. So, B = W + 1 is satisfied ----- Case 2 - One of M, N is even The square at the [M][N] is white and the number of black and white cells are equal. We will just back the last cell [M][N] = 'B' This will reduce the number of good white cells by 1 and keep the number of good black cells constant so B = W + 1 is maintained ----- Case 3 - Both M, N are even Now [M][N] = B anyway so we will make cell [M][1] = B This reduces the number of good white cells by 1 and the number of black cells constant B = W + 1 is maintained This satisfies all the cases ---- void solve() { int rows, columns; cin >> rows >> columns; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { switch((i + j)%2) { case 0 : grid[i][j] = 'B'; break; case 1 : grid[i][j] = 'W'; break; } } } grid[rows][columns] = 'B'; if(rows%2 == 0 && columns%2 == 0) { grid[rows][1] = 'B'; } for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { cout << grid[i][j]; } cout << "\n"; } } ================================================ FILE: 2020/Div 2/632 Div 2/Programs/Eugene and Array.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = prefix_sum[i - 1] + A[i]; } int end_point = 0; map frequency; map last_occurence; frequency[0] = 1; long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { if(frequency[prefix_sum[i]] != 0) { end_point = max(end_point, last_occurence[prefix_sum[i]] + 2); } last_occurence[prefix_sum[i]] = i; frequency[prefix_sum[i]] = i; int distance = (end_point == 0 ? i : i - end_point + 1); answer += (distance > 0 ? distance : 0); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/632 Div 2/Programs/Kate and Imperfection.cpp ================================================ #include #include #include using namespace std; int main() { int n; cin >> n; vector largest_divisor(n + 1, 1); for(int i = 1; i <= n; i++) { for(int multiple = 2*i; multiple <= n; multiple += i) { largest_divisor[multiple] = i; } } sort(largest_divisor.begin(), largest_divisor.end()); for(int i = 2; i <= n; i++) { cout << largest_divisor[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/632 Div 2/Programs/Kind Anton.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1), B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } int positive = false, negative = false, possible = true;; for(int i = 1; i <= no_of_elements; i++) { if(A[i] < B[i]) { if(!positive) { possible = false; } } if(A[i] > B[i]) { if(!negative) { possible = false; } } if(A[i] == 1) { positive = true; } if(A[i] == -1) { negative = true; } } cout << (possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while (no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/632 Div 2/Programs/Little Artem.cpp ================================================ #include using namespace std; const int MAX_N = 105; char grid[MAX_N][MAX_N]; void solve() { int rows, columns; cin >> rows >> columns; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { switch((i + j)%2) { case 0 : grid[i][j] = 'B'; break; case 1 : grid[i][j] = 'W'; break; } } } grid[rows][columns] = 'B'; if(rows%2 == 0 && columns%2 == 0) { grid[rows][1] = 'B'; } for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { cout << grid[i][j]; } cout << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while (no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/633 Div 2/Explanations/Filling Diamonds Explanation.txt ================================================ It is difficult to explain this without drawing a diagram. The main idea is that if we place a diamond vertically, the rest of the positions are forced. In a diagram of (4n - 2) triangles, there are n positions where we can place a vertical diamond The arrangement before and after the vertical triangle are fixed So, the answer is always n ----- void solve() { long long n; cin >> n; cout << n << "\n"; } ================================================ FILE: 2020/Div 2/633 Div 2/Explanations/Powered Addition Explanation.txt ================================================ 1. We will keep track of the Prefix Maximum as we go from i = 1 to N 2. At every i, we will check if A[i] < prefix_max 3. If yes, we will add just enough to make A[i] = prefix_max The time taken = msb(prefix_max - A[i]) ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int time_required = 0; long long max_so_far = A[1]; for(int i = 1; i <= no_of_elements; i++) { if(A[i] >= max_so_far) { max_so_far = A[i]; continue; } long long required = max_so_far - A[i]; time_required = max(time_required, msb(required) + 1); max_so_far = A[i] + required; } cout << time_required << "\n"; } ================================================ FILE: 2020/Div 2/633 Div 2/Explanations/Sorted Adjacent Differences Explanation.txt ================================================ What is the biggest difference ? A[1] - A[n] If we replace, A[1] by any other element, it will get smaller and if we replace A[n] by any other element, it will get smaller This means, the array ends with (A[1], A[n]) Now, what should be the third last element ? It should be the second largest difference. This means that A[1] should be paired with A[n - 1]. If we exchange A[n - 1] with something else, the difference will get smaller ----- After sorting the array, We will make the array like this A[1] A[n] A[n - 1] A[1] A[n] A[2] A[n - 1] A[1] A[n] and so on ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin() + 1, A.end()); vector answer(no_of_elements + 1); for(int i = no_of_elements, front = 1, back = no_of_elements; i >= 1; i--) { if(i%2 == no_of_elements%2) { answer[i] = A[back--]; } else { answer[i] = A[front++]; } } for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 2/633 Div 2/Programs/Filling Diamonds.cpp ================================================ #include #include using namespace std; void solve() { long long n; cin >> n; cout << n << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) { solve(); } return 0; } ================================================ FILE: 2020/Div 2/633 Div 2/Programs/Powered Addition.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0); } int msb(long long n) { const int MAX_BIT = 63; for(int bit = MAX_BIT; bit >= 0; bit--) { if(is_bit_set(n, bit)) { return bit; } } return 0; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int time_required = 0; long long max_so_far = A[1]; for(int i = 1; i <= no_of_elements; i++) { if(A[i] >= max_so_far) { max_so_far = A[i]; continue; } long long required = max_so_far - A[i]; time_required = max(time_required, msb(required) + 1); max_so_far = A[i] + required; } cout << time_required << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/633 Div 2/Programs/Sorted Adjacent Differences.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin() + 1, A.end()); vector answer(no_of_elements + 1); for(int i = no_of_elements, front = 1, back = no_of_elements; i >= 1; i--) { if(i%2 == no_of_elements%2) { answer[i] = A[back--]; } else { answer[i] = A[front++]; } } for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/635 Div 2/Explanations/Ichime and Triangle Explanation.txt ================================================ The triangle inequality says (a + b > c) So, we can just print b c c b + c > c c + c > b ----- void solve() { int a, b, c, d; cin >> a >> b >> c >> d; cout << b << " " << c << " " << c << "\n"; } ================================================ FILE: 2020/Div 2/635 Div 2/Explanations/Kana and Dragon Quest Game Explanation.txt ================================================ The net reduction is H/2 or 10 As long as H/2 > 10, it is always better to do the first operation And then, we can do the second operation to the maximum extent We will check if the value is still > 0 after these operations And give the answer accordingly ----- void solve() { int total, type_1, type_2; cin >> total >> type_1 >> type_2; while(total/2 + total%2 > 10 && type_1 > 0) { total = total/2 + 10; type_1--; } total -= 10*type_2; cout << (total <= 0 ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/635 Div 2/Explanations/Linova and Kingdom Explanation.txt ================================================ Let us try to calculate the contribution of a vertex to the sum if we add it. ----- Firstly, it is always optimal to choose the first 'unpicked' vertex in a given chain. If we choose some other vertex v instead of u and depth[u] < depth[v] and u and v are in the same chain (lca(u, v) = u), then we can choose v instead of u and get a bigger sum. ----- When we choose a leaf vertex, it contributes depth[v] to the sum. What happens when we choose a non-leaf vertex v ? The happiness of the v-th vertex is depth[v], but the happiness of every vertex in the subtree[v] reduces by 1. (Since v is now an industrial town). So, if v is added to our set, it contributes (depth[v] - subtree_size[v]) So the contribution[v] = (depth[v] - subtree_size[v]) ----- We will sort the contribution of all the vertices and choose the greatest K vertices ----- void dfs(int v, int parent_v) { if(depth[v] != 0) { return; } depth[v] = 1 + depth[parent_v]; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); subtree_from[v] += (1 + subtree_from[child_v]); } } int main() { int no_of_vertices, chosen_vertices; cin >> no_of_vertices >> chosen_vertices; int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } depth[0] = -1; dfs(1, 0); vector contribution; for(int v = 1; v <= no_of_vertices; v++) { contribution.push_back(depth[v] - subtree_from[v]); } sort(all(contribution)); reverse(all(contribution)); long long sum = 0; for(int i = 0; i < chosen_vertices; i++) { sum += contribution[i]; } cout << sum << "\n"; return 0; } ================================================ FILE: 2020/Div 2/635 Div 2/Explanations/Xenia and Colourful Gems Explanation.txt ================================================ Let us imagine that X <= Y <= Z We will iterate over the middle element. If we fix Y, then we will look for the closest X <= Y and the closest Z >= Y This is the optimal pairing. The reason is with a y fixed, replacing either the x with a smaller x or the z with a larger z will increase the sum ---- If we fix either the first or the third element, the exchange argument doesn't hold. For example, 3 3 4 6 If we fix the smallest element (3, 3, 6) is the triplet But we can do better by increasing 3 to 4 (3, 3, 4) gives us 14 which is smaller than 18 ----- We will check all 6 possibilities with each of the arrays given a chance to be X, Y and Z ----- void find_best(vector &X, vector &Y, vector &Z, long long &answer) { for(int j = 1; j < Y.size(); j++) { int i = lower_bound(all(X), Y[j]) - X.begin(); int k = lower_bound(all(Z), Y[j]) - Z.begin(); if(i != X.size() && k != Z.size()) { answer = min(answer, square(X[i] - Y[j]) + square(Y[j] - Z[k]) + square(Z[k] - X[i])); } if(i > 1 && k != Z.size()) { i--; answer = min(answer, square(X[i] - Y[j]) + square(Y[j] - Z[k]) + square(Z[k] - X[i])); } } } void solve() { int no_of_red, no_of_green, no_of_blue; cin >> no_of_red >> no_of_green >> no_of_blue; vector R(no_of_red + 1); for(int i = 1; i <= no_of_red; i++) { cin >> R[i]; } sort(all(R)); vector G(no_of_green + 1); for(int i = 1; i <= no_of_green; i++) { cin >> G[i]; } sort(all(G)); vector B(no_of_blue + 1); for(int i = 1; i <= no_of_blue; i++) { cin >> B[i]; } sort(all(B)); long long answer = LLONG_MAX; //cout << answer << "\n"; find_best(R, G, B, answer); find_best(R, B, G, answer); find_best(G, R, B, answer); find_best(G, B, R, answer); find_best(B, G, R, answer); find_best(B, R, G, answer); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/635 Div 2/Programs/Ichihime and Triangle.cpp ================================================ #include using namespace std; void solve() { int a, b, c, d; cin >> a >> b >> c >> d; cout << b << " " << c << " " << c << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/635 Div 2/Programs/Kana and Dragon Quest game.cpp ================================================ #include using namespace std; void solve() { int total, type_1, type_2; cin >> total >> type_1 >> type_2; while(total/2 + total%2 > 10 && type_1 > 0) { total = total/2 + 10; type_1--; } total -= 10*type_2; cout << (total <= 0 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/635 Div 2/Programs/Linova and Kingdom.cpp ================================================ #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() const int MAX_N = 3e5 + 5; vector tree[MAX_N]; vector depth(MAX_N, 0); vector subtree_from(MAX_N, 0); void dfs(int v, int parent_v) { if(depth[v] != 0) { return; } depth[v] = 1 + depth[parent_v]; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); subtree_from[v] += (1 + subtree_from[child_v]); } } int main() { int no_of_vertices, chosen_vertices; cin >> no_of_vertices >> chosen_vertices; int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } depth[0] = -1; dfs(1, 0); vector contribution; for(int v = 1; v <= no_of_vertices; v++) { contribution.push_back(depth[v] - subtree_from[v]); } sort(all(contribution)); reverse(all(contribution)); long long sum = 0; for(int i = 0; i < chosen_vertices; i++) { sum += contribution[i]; } cout << sum << "\n"; return 0; } ================================================ FILE: 2020/Div 2/635 Div 2/Programs/Xenia and Colourful Gems.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long square(long long n) { return n*n; } void find_best(vector &X, vector &Y, vector &Z, long long &answer) { for(int j = 1; j < Y.size(); j++) { int i = lower_bound(all(X), Y[j]) - X.begin(); int k = lower_bound(all(Z), Y[j]) - Z.begin(); if(i != X.size() && k != Z.size()) { answer = min(answer, square(X[i] - Y[j]) + square(Y[j] - Z[k]) + square(Z[k] - X[i])); } if(i > 1 && k != Z.size()) { i--; answer = min(answer, square(X[i] - Y[j]) + square(Y[j] - Z[k]) + square(Z[k] - X[i])); } } } void solve() { int no_of_red, no_of_green, no_of_blue; cin >> no_of_red >> no_of_green >> no_of_blue; vector R(no_of_red + 1); for(int i = 1; i <= no_of_red; i++) { cin >> R[i]; } sort(all(R)); vector G(no_of_green + 1); for(int i = 1; i <= no_of_green; i++) { cin >> G[i]; } sort(all(G)); vector B(no_of_blue + 1); for(int i = 1; i <= no_of_blue; i++) { cin >> B[i]; } sort(all(B)); long long answer = LLONG_MAX; //cout << answer << "\n"; find_best(R, G, B, answer); find_best(R, B, G, answer); find_best(G, R, B, answer); find_best(G, B, R, answer); find_best(B, G, R, answer); find_best(B, R, G, answer); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/637 Div 2/Explanations/Nastya and Door Explanation.txt ================================================ Let us make another array where P[i] = true, if A[i] is a peak and false otherwise We will make a prefix sum of peaks Then, for each query, we will retrun Sum[R - 1] - Sum[L] ----- void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_peak(no_of_elements + 1, false); for(int i = 2; i < no_of_elements; i++) { if(A[i - 1] < A[i] && A[i] > A[i + 1]) { is_peak[i] = true; } } vector peak_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { peak_sum[i] = peak_sum[i - 1] + is_peak[i]; } int max_peaks = 0, left_border = 1; for(int i = k; i <= no_of_elements; i++) { int right = i - 1, left = i - k + 1; int peaks_here = peak_sum[right] - peak_sum[left]; if(peaks_here > max_peaks) { max_peaks = peaks_here; left_border = left; } } int max_parts = max_peaks + 1; cout << max_parts << " " << left_border << "\n"; } ================================================ FILE: 2020/Div 2/637 Div 2/Explanations/Nastya and Rice Explanation.txt ================================================ The minimum weight we can make n(a - b) and the maximum weight we can make n(a + b) We must check if the maximum weight is not < minimum capacity and that the minimum weight is not < maximum capacity ----- void solve() { int no_of_grains, a, b, c, d; cin >> no_of_grains >> a >> b >> c >> d; int minimum_weight = no_of_grains*(a - b); int maximum_weight = no_of_grains*(a + b); int minimum_capacity = (c - d); int maximum_capacity = (c + d); cout << (minimum_weight > maximum_capacity || maximum_weight < minimum_capacity ? "No\n" : "Yes\n"); } ================================================ FILE: 2020/Div 2/637 Div 2/Explanations/Nastya and Scoreboard Explanation.txt ================================================ Here is the best strategy - We will try to make the left most strings as large an integer as possible. Suppose we have 100 operations in total. If we use 2 operations for A[1] to 9, then we have 98 operations for [2, 100]. We have to know if this is possible. Similarly, if we use 3 operations for A[1] to 8, then we have 97 operations for [3, 100] We have to know if this is exactly possible. ----- 1. We will make a DP Let f(i, j) be true if it is possible to make A[i, ... , n] a valid string with exactly j operations and false otherwise To calculate the transition, we will go over all 10 digits and if we need to use 'd' operations to make A[i] = d, f(i, j) = true if f(i + 1, j - d) is true 2. We will check all 10 digits and not stop when we first get a 'true'. The reason is there might be a situation when we set A[i] to 7 instead of 9 in order to make the entire number a valid string. ----- memset(is_possible, false, sizeof(is_possible)); is_possible[no_of_digits][0] = true; for(int i = no_of_digits - 1; i >= 0; i--) { for(int steps = 0; steps <= switched_off_stick; steps++) { for(int d = 0; d < DIGITS; d++) { int remaining_steps = steps - steps_to_convert(state[i], d); if(remaining_steps >= 0 && is_possible[i + 1][remaining_steps]) { //cout << "F(" << i << "," << steps << ") = for " << d << " is possible\n"; //cout << "Remaining Steps = " << remaining_steps << " And to Convert = " << steps_to_convert(state[i], d) << "\n"; is_possible[i][steps] = true; } } } } ----- How to construct the optimal string ? We will go from i = 0 to N - 1 For each position, we will try to be greedy and place as high a digit as possible if(!is_possible[0][switched_off_stick]) { cout << "-1\n"; return 0; } int steps_remaining = switched_off_stick; string final_integer; for(int i = 0 ; i < no_of_digits; i++) { for(int d = 9; d >= 0; d--) { int steps_for_suffix = steps_remaining - steps_to_convert(state[i], d); if(steps_for_suffix >= 0 && is_possible[i + 1][steps_for_suffix]) { final_integer.push_back('0' + d); steps_remaining -= steps_to_convert(state[i], d); break; } } } cout << final_integer << "\n"; ----- How to check how many steps are required to make A[i] = d, for each d from 0 to 9 ? We will have to 'hard-code' the values of 0 to 9 and then check void hardcode() { digits.push_back("1110111"); //0 digits.push_back("0010010"); //1 digits.push_back("1011101"); //2 digits.push_back("1011011"); //3 digits.push_back("0111010"); //4 digits.push_back("1101011"); //5 digits.push_back("1101111"); //6 digits.push_back("1010010"); //7 digits.push_back("1111111"); //8 digits.push_back("1111011"); //9 } int steps_to_convert(string ¤t, int number) { int steps = 0; string ending = digits[number]; for(int i = 0; i < NO_OF_SEGMENTS; i++) { if(current[i] == '1' && ending[i] == '0') { return oo; } if(current[i] == '0' && ending[i] == '1') { steps++; } //Otherwise current[i] = ending[i] } return steps; } ================================================ FILE: 2020/Div 2/637 Div 2/Explanations/Nastya and Strange Generator Explanation.txt ================================================ Let us try to simulate the process - We start with an empty array. _ _ 1 _ _ Now, for the next step, we have to put 2 in the spot next to the 1 _ _ 1 2 _ And now, the digit 3 can only be placed in the last position ----- Claim - The final array can be broken into subarrays consisting of consecutive integers in ascending order For example x (x + 1) (x + 2) | y (y + 1) (y + 2) (y + 3) | z (z + 1) (z + 2) (z + 3) ---- Proof - We can prove this in with induction over the number of 'segments' already placed We have shown the base case that the first segment will cover the entire suffix ----- Let us assume the 'k' segments are already placed and the suffix is already placed Let x be the first unplaced digit We can place x in any of the first empty places in the prefix (x + 1) has to be a neighbour to x (x + 2) has to be a neighbour to (x + 1) and so on till the entire prefix is over. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } int possible = true; for(int i = no_of_elements; i > 1; i--) { if(P[i - 1] < P[i]) { if(P[i - 1] != P[i] - 1) { possible = false; break; } continue; } } cout << (possible ? "Yes\n" : "No\n"); } ================================================ FILE: 2020/Div 2/637 Div 2/Programs/Nastya and Door.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_peak(no_of_elements + 1, false); for(int i = 2; i < no_of_elements; i++) { if(A[i - 1] < A[i] && A[i] > A[i + 1]) { is_peak[i] = true; } } vector peak_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { peak_sum[i] = peak_sum[i - 1] + is_peak[i]; } int max_peaks = 0, left_border = 1; for(int i = k; i <= no_of_elements; i++) { int right = i - 1, left = i - k + 1; int peaks_here = peak_sum[right] - peak_sum[left]; if(peaks_here > max_peaks) { max_peaks = peaks_here; left_border = left; } } int max_parts = max_peaks + 1; cout << max_parts << " " << left_border << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/637 Div 2/Programs/Nastya and Rice.cpp ================================================ #include using namespace std; void solve() { int no_of_grains, a, b, c, d; cin >> no_of_grains >> a >> b >> c >> d; int minimum_weight = no_of_grains*(a - b); int maximum_weight = no_of_grains*(a + b); int minimum_capacity = (c - d); int maximum_capacity = (c + d); cout << (minimum_weight > maximum_capacity || maximum_weight < minimum_capacity ? "No\n" : "Yes\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/637 Div 2/Programs/Nastya and Scoreboard.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 2015, DIGITS = 10, NO_OF_SEGMENTS = 7, oo = 1e9; int is_possible[MAX_N][MAX_N]; vector digits; void hardcode() { digits.push_back("1110111"); //0 digits.push_back("0010010"); //1 digits.push_back("1011101"); //2 digits.push_back("1011011"); //3 digits.push_back("0111010"); //4 digits.push_back("1101011"); //5 digits.push_back("1101111"); //6 digits.push_back("1010010"); //7 digits.push_back("1111111"); //8 digits.push_back("1111011"); //9 } int steps_to_convert(string ¤t, int number) { int steps = 0; string ending = digits[number]; for(int i = 0; i < NO_OF_SEGMENTS; i++) { if(current[i] == '1' && ending[i] == '0') { return oo; } if(current[i] == '0' && ending[i] == '1') { steps++; } //Otherwise current[i] = ending[i] } return steps; } int main() { hardcode(); int no_of_digits, switched_off_stick; cin >> no_of_digits >> switched_off_stick; vector state(no_of_digits); for(int i = 0; i < no_of_digits; i++) { cin >> state[i]; } memset(is_possible, false, sizeof(is_possible)); is_possible[no_of_digits][0] = true; for(int i = no_of_digits - 1; i >= 0; i--) { for(int steps = 0; steps <= switched_off_stick; steps++) { for(int d = 0; d < DIGITS; d++) { int remaining_steps = steps - steps_to_convert(state[i], d); if(remaining_steps >= 0 && is_possible[i + 1][remaining_steps]) { //cout << "F(" << i << "," << steps << ") = for " << d << " is possible\n"; //cout << "Remaining Steps = " << remaining_steps << " And to Convert = " << steps_to_convert(state[i], d) << "\n"; is_possible[i][steps] = true; } } } } if(!is_possible[0][switched_off_stick]) { cout << "-1\n"; return 0; } int steps_remaining = switched_off_stick; string final_integer; for(int i = 0 ; i < no_of_digits; i++) { for(int d = 9; d >= 0; d--) { int steps_for_suffix = steps_remaining - steps_to_convert(state[i], d); if(steps_for_suffix >= 0 && is_possible[i + 1][steps_for_suffix]) { final_integer.push_back('0' + d); steps_remaining -= steps_to_convert(state[i], d); break; } } } cout << final_integer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/637 Div 2/Programs/Nastya and Strange Generator.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } int possible = true; for(int i = no_of_elements; i > 1; i--) { if(P[i - 1] < P[i]) { if(P[i - 1] != P[i] - 1) { possible = false; break; } continue; } } cout << (possible ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/638 Div 2/Explanations/Pheonix and Balance Explanation.txt ================================================ We can use 1 fact about binary integers and powers of 2 2^i = (2^{i - 1} + 2^{i - 2} + ... + 2^1 + 2^0) + 1 So 2^n is greater than all other powers of 2 combined. So, 2^n will be in one pile along with the lightest (n/2 - 1) coins All the other coins will be in the other pile. ----- void solve() { int n; cin >> n; int heavy_pile = (1 << n); for(int i = 1; i < n/2; i++) { heavy_pile += (1 << i); } int light_pile = 0; for(int i = n/2; i < n; i++) { light_pile += (1 << i); } cout << (heavy_pile - light_pile) << "\n"; } ================================================ FILE: 2020/Div 2/638 Div 2/Programs/Pheonix and Balance.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; int heavy_pile = (1 << n); for(int i = 1; i < n/2; i++) { heavy_pile += (1 << i); } int light_pile = 0; for(int i = n/2; i < n; i++) { light_pile += (1 << i); } cout << (heavy_pile - light_pile) << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/638 Div 2/Programs/Phoenix and Balance.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; int heavy_pile = (1 << n); for(int i = 1; i < n/2; i++) { heavy_pile += (1 << i); } int light_pile = 0; for(int i = n/2; i < n; i++) { light_pile += (1 << i); } cout << (heavy_pile - light_pile) << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Card Construction Explanation.txt ================================================ Let us try to build a recurrence between the number of cards required for H levels and (H - 1) levels We will use 2H cards in the base triangles and (H - 1) cards for the base and then f(H - 1) cards above it f(H) = 2H + (H - 1) + f(H - 1) ----- After precomputing this, let us see the number of pyramids we can make with H cards We can use binary search and find out the smallest number <= H Then reduce H by it And continue to do so till no more pyramids can be made with H cards ----- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 1e9; vector cards; void precompute() { cards.push_back(0); while(cards.back() < MAX_N) { int level = cards.size(); long long next = 2*level + level - 1 + cards.back(); cards.push_back(next); } } void solve() { int n; cin >> n; int no_of_pyramids = 0; while(true) { int current_pyramid_size = lower_bound(all(cards), n) - cards.begin(); if(cards[current_pyramid_size] > n) { current_pyramid_size--; } n -= cards[current_pyramid_size]; if(current_pyramid_size == 0) { break; } no_of_pyramids++; } cout << no_of_pyramids << "\n"; } int main() { precompute(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Hilbert Hotel Explanation.txt ================================================ Two integers i and j will intersect if i + A[i] = j + A[j] (mod N) So, we have to ensure that all N moduli - (0 + A[0]), (1 + A[1]), ... , (N - 1 + A[N - 1]) are unique If any two of them are equal, there will be a collision. We have to ensure that each modulus occurs exactly one time. If any modulus between [0, N - 1] does not occur, then by the Pigeonhole Principle, some other modulus will occur at least twice Be careful to handle negative integers properly and ensure all the moduli are positive ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } vector frequency_mod(no_of_elements); for(int i = 0; i < no_of_elements; i++) { A[i] %= no_of_elements; if(A[i] < 0) { A[i] += 2*no_of_elements; A[i] %= no_of_elements; } frequency_mod[ (i + A[i])%no_of_elements ]++; } int all_unique = true; for(int i = 0; i < no_of_elements; i++) { if(frequency_mod[i] != 1) { all_unique = false; } } cout << (all_unique ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Monopole Magnets Explanation.txt ================================================ There can be no row or column with more than 1 black segment The reason is that if there is a row with more than 1 black segment, then we can force a North Pole to reach the white squares between them. North Magnets can visit every black square so they should be able to visit both black segments Which means both black segments have a South Magnet which attracts the North Magnet in the other segment ----- If there is a row with 0 black cells and is all white, the South Magnet has to be placed in a column with 0 black cells. If there is a row with 0 black cells and is all white and we place it in a column which has black cells, it will make the North Magnet visit the white cell which we don't want. So, a South Magnet should be placed at the intersection of a white row and white column ----- If these two conditions are met, then we can see that it is sufficient to have 1 North Magnet per component As there is a South Magnet in every row and every column, it will help us to get the North Magnet into every black cell of the segment ----- 1. Each row and Column has at most 1 black segment 2. If there is an all white row, there has to be an all white column 3. Otherwise, we will count the number of components in the graph ----- #include #include #include #include using namespace std; const int MAX_N = 1005, NO_OF_NEIGHOURS = 4; const char BLACK = '#', WHITE = '.'; char grid[MAX_N][MAX_N]; int visited[MAX_N][MAX_N]; int next_r[NO_OF_NEIGHOURS] = {-1, 0, 0, 1}; int next_c[NO_OF_NEIGHOURS] = {0, 1, -1, 0}; int rows, columns; int inside_grid(int x, int y) { return (1 <= x && x <= rows && 1 <= y && y <= columns); } void dfs(int x, int y) { visited[x][y] = true; for(int n = 0; n < NO_OF_NEIGHOURS; n++) { int next_x = x + next_r[n]; int next_y = y + next_c[n]; if(inside_grid(next_x, next_y) && grid[next_x][next_y] == BLACK && !visited[next_x][next_y]) { dfs(next_x, next_y); } } } int main() { scanf("%d %d", &rows, &columns); for(int i = 1; i <= rows; i++) { scanf("%s", grid[i] + 1); } vector row_frequency(rows + 1); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == BLACK) { row_frequency[i]++; } } } vector column_frequency(columns + 1); for(int j = 1; j <= columns; j++) { for(int i = 1; i <= rows; i++) { if(grid[i][j] == BLACK) { column_frequency[j]++; } } } int possible = true, all_white_row = false, all_white_column = false; for(int i = 1; i <= rows; i++) { int black_cells = 0; for(int j = 1; j <= columns; j++) { if(grid[i][j] == BLACK) { black_cells++; if(j + 1 <= columns && grid[i][j + 1] == WHITE && black_cells != row_frequency[i]) { possible = false; break; } } } if(row_frequency[i] == 0) { all_white_row = true; } } for(int j = 1; j <= columns; j++) { int black_cells = 0; for(int i = 1; i <= rows; i++) { if(grid[i][j] == BLACK) { black_cells++; if(i + 1 <= rows && grid[i + 1][j] == WHITE && black_cells != column_frequency[j]) { possible = false; break; } } } if(column_frequency[j] == 0) { all_white_column = true; } } if( (all_white_row && !all_white_column) || (!all_white_row && all_white_column) ) { possible = false; } if(!possible) { cout << "-1\n"; return 0; } int no_of_components = 0; memset(visited, false, sizeof(visited)); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == BLACK && !visited[i][j]) { dfs(i, j); no_of_components++; } } } cout << no_of_components << "\n"; return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Puzzle Pieces Explanation.txt ================================================ If we have only 1 row or 1 column, we can achieve any length of it Otherwise, we can only achieve 2x2 and no other combination ----- void solve() { int rows, columns; cin >> rows >> columns; if(min(rows, columns) == 1) { cout << "YES\n"; return; } cout << (max(rows, columns) <= 2 ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Quantifier Question Explanation.txt ================================================ Let us draw an edge between every pair of vertices (u, v) if (u < v) This will give us a directed graph. It is important to notice that each connected component can have exactly 1 Universal Identifier. All other vertices in this component must be an Existential Identifier as they are 'forced'. If there are any cycles in this graph, then we cannot have any valid assignment ----- One thing to be careful of in this problem This is a directed graph. So, when we visit an unvisited graph, it is not enough to only do DFS We must also do DFS on the reverse graph. Suppose the graph is like 5 -> 4 -> 1 -> 2 -> 3 If we do DFS from 1, we will only be marking 2 and 3 But, we should mark 4 and 5 too This is why we must maintain two vectors - Visited and Visited Reverse to mark all vertices in the same component. ----- To check if there is a cycle in either the DFS or Reverse DFS, we will maintain another vector to keep track of whether a variable is still on the DFS Stack. If we visit a vertex on the DFS Stack, it means there is a cycle. Otherwise, there is not. ----- #include #include using namespace std; const int MAX_N = 2e5 + 5; vector graph[MAX_N], reverse_graph[MAX_N]; vector visited(MAX_N, false); vector on_stack(MAX_N, false); vector visited_reverse(MAX_N, false), on_stack_reverse(MAX_N, 0); int dfs_cycle_reverse(int v) { visited_reverse[v] = true; on_stack_reverse[v] = true; for(int i = 0; i < reverse_graph[v].size(); i++) { int child_v = reverse_graph[v][i]; if(visited_reverse[child_v] && on_stack_reverse[child_v]) { return true; } if(!visited_reverse[child_v] && dfs_cycle_reverse(child_v)) { return true; } } on_stack_reverse[v] = false; return false; } int dfs_cycle(int v) { visited[v] = true; on_stack[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(visited[child_v] && on_stack[child_v]) { return true; } if(!visited[child_v] && dfs_cycle(child_v)) { return true; } } on_stack[v] = false; return false; } int main() { int no_of_variables, no_of_inequalities; cin >> no_of_variables >> no_of_inequalities; vector indegree(no_of_variables + 1, 0); for(int i = 1; i <= no_of_inequalities; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); reverse_graph[v].push_back(u); indegree[v]++; //cout << "In Degree " << v << " = " << indegree[v] << "\n"; } int no_of_universals = 0; string answer; for(int i = 1; i <= no_of_variables; i++) { if(!visited[i] && !visited_reverse[i]) { no_of_universals++; answer += 'A'; } else { answer += 'E'; } if(dfs_cycle(i) || dfs_cycle_reverse(i)) { cout << "-1\n"; return 0; } } cout << no_of_universals << "\n"; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Resume Review Explanation.txt ================================================ Let us see what happens when we increment some B[i] from (x - 1) to x The function changes by |x.(A[i] - x)^2| - |(x - 1).(A[i] - (x - 1))^2| This is (A[i] - 3x^2 + 3x - 1) It is interesting to note that this function decreases as x >= 1 The more we increase B[i], the more we decrease this function. However, we have to add k B[i]'s anyway. So, we must try to the greatest values of this update as possible ----- We can do this by binary search. We will fix a value of R, and check how many additions we need to process all contributions > R For example, if R = 100, We will check how many addition steps we need to do to B such that all contributions > 100 are counted We will maintain the invariant that it is always possible for R and not possible for L and stop when (R - L = 1) ----- long long left = -3e18, right = 3e18; while(right - left > 1) { long long mid = (left + right)/2; if(no_of_steps(mid) <= total_steps) { right = mid; } else { left = mid; } } ----- Now, let us try to answer a different question Given an integer X, how many steps do we have to perform if, for every B[i] we set it to a value such that all gains are strictly > x ? We can do this with binary search ! --- We know for a given A[i], if we set B[i] = m, what the last gain will be It will be (A[i] - 3m^2 + 3m - 1) This is a decreasing function so we can use binary search. The invariant we maintain is that It is always possible to do L steps and never possible to do R steps. Initially, L = 0, R = A[i] + 1 If (A[i] - 3m^2 + 3m - 1) > x, then set L = m Otherwise, set R = m In the end, L is the answer that we want - The maximum number of addition steps we can do such that B[i] has all contributions > R counted --- long long no_of_steps(long long x) { long long steps = 0; for(int i = 1; i <= no_of_elements; i++) { long long left = 0, right = A[i] + 1; //Left is always possible, right is not while(right - left > 1) { long long mid = (left + right)/2; long long smallest_contribution = A[i] - 3*mid*mid+ 3*mid - 1; if(smallest_contribution > x) { left = mid; } else { right = mid; } } B[i] = left; steps += left; } return steps; } ----- A side note to be made here is that we might not have used exactly K elements If we have used < K elements, then we must increment B[i] such that the gain = x (It will always be possible that there is an integer increasing which will give us a gain = x This is because of the invariant of our binary search. If there is no integer who's contribution is exactly x, then R would have stopped at a lower integer in our binary search.) R stopped at the minimum integer such that it is possible to make contributions > R ---- long long final_steps = no_of_steps(right); for(int i = 1; i <= no_of_elements && final_steps < total_steps; i++) { if(B[i] == A[i]) { continue; } long long new_b = B[i] + 1; if(A[i] - 3*new_b*new_b + 3*new_b - 1 == right) { B[i]++; final_steps++; } } ================================================ FILE: 2020/Div 2/639 Div 2/Explanations/Resume Review.cpp ================================================ #include #include using namespace std; long long no_of_elements, total_steps; vector A, B; long long no_of_steps(long long x) { long long steps = 0; for(int i = 1; i <= no_of_elements; i++) { long long left = 0, right = A[i] + 1; //Left is always possible, right is not while(right - left > 1) { long long mid = (left + right)/2; long long smallest_contribution = A[i] - 3*mid*mid+ 3*mid - 1; if(smallest_contribution > x) { left = mid; } else { right = mid; } } B[i] = left; steps += left; } return steps; } int main() { cin >> no_of_elements >> total_steps; A.resize(no_of_elements + 1); B.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } // > Right is always possible, <= Left is never possible long long left = -3e18, right = 3e18; while(right - left > 1) { long long mid = (left + right)/2; if(no_of_steps(mid) <= total_steps) { right = mid; } else { left = mid; } } long long final_steps = no_of_steps(right); for(int i = 1; i <= no_of_elements && final_steps < total_steps; i++) { if(B[i] == A[i]) { continue; } long long new_b = B[i] + 1; if(A[i] - 3*new_b*new_b + 3*new_b - 1 == right) { B[i]++; final_steps++; } } for(int i = 1; i <= no_of_elements; i++) { cout << B[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Programs/Card Construction.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 1e9; vector cards; void precompute() { cards.push_back(0); while(cards.back() < MAX_N) { int level = cards.size(); long long next = 2*level + level - 1 + cards.back(); cards.push_back(next); } } void solve() { int n; cin >> n; int no_of_pyramids = 0; while(true) { int current_pyramid_size = lower_bound(all(cards), n) - cards.begin(); if(cards[current_pyramid_size] > n) { current_pyramid_size--; } n -= cards[current_pyramid_size]; if(current_pyramid_size == 0) { break; } no_of_pyramids++; } cout << no_of_pyramids << "\n"; } int main() { precompute(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Programs/Hilbert Hotel.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } vector frequency_mod(no_of_elements); for(int i = 0; i < no_of_elements; i++) { A[i] %= no_of_elements; if(A[i] < 0) { A[i] += 2*no_of_elements; A[i] %= no_of_elements; } frequency_mod[ (i + A[i])%no_of_elements ]++; } int all_unique = true; for(int i = 0; i < no_of_elements; i++) { if(frequency_mod[i] != 1) { all_unique = false; } } cout << (all_unique ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Programs/Monopole Magnets.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 1005, NO_OF_NEIGHOURS = 4; const char BLACK = '#', WHITE = '.'; char grid[MAX_N][MAX_N]; int visited[MAX_N][MAX_N]; int next_r[NO_OF_NEIGHOURS] = {-1, 0, 0, 1}; int next_c[NO_OF_NEIGHOURS] = {0, 1, -1, 0}; int rows, columns; int inside_grid(int x, int y) { return (1 <= x && x <= rows && 1 <= y && y <= columns); } void dfs(int x, int y) { visited[x][y] = true; for(int n = 0; n < NO_OF_NEIGHOURS; n++) { int next_x = x + next_r[n]; int next_y = y + next_c[n]; if(inside_grid(next_x, next_y) && grid[next_x][next_y] == BLACK && !visited[next_x][next_y]) { dfs(next_x, next_y); } } } int main() { scanf("%d %d", &rows, &columns); for(int i = 1; i <= rows; i++) { scanf("%s", grid[i] + 1); } vector row_frequency(rows + 1); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == BLACK) { row_frequency[i]++; } } } vector column_frequency(columns + 1); for(int j = 1; j <= columns; j++) { for(int i = 1; i <= rows; i++) { if(grid[i][j] == BLACK) { column_frequency[j]++; } } } int possible = true, all_white_row = false, all_white_column = false; for(int i = 1; i <= rows; i++) { int black_cells = 0; for(int j = 1; j <= columns; j++) { if(grid[i][j] == BLACK) { black_cells++; if(j + 1 <= columns && grid[i][j + 1] == WHITE && black_cells != row_frequency[i]) { possible = false; break; } } } if(row_frequency[i] == 0) { all_white_row = true; } } for(int j = 1; j <= columns; j++) { int black_cells = 0; for(int i = 1; i <= rows; i++) { if(grid[i][j] == BLACK) { black_cells++; if(i + 1 <= rows && grid[i + 1][j] == WHITE && black_cells != column_frequency[j]) { possible = false; break; } } } if(column_frequency[j] == 0) { all_white_column = true; } } if( (all_white_row && !all_white_column) || (!all_white_row && all_white_column) ) { possible = false; } if(!possible) { cout << "-1\n"; return 0; } int no_of_components = 0; memset(visited, false, sizeof(visited)); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == BLACK && !visited[i][j]) { dfs(i, j); no_of_components++; } } } cout << no_of_components << "\n"; return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Programs/Puzzle Pieces.cpp ================================================ #include using namespace std; void solve() { int rows, columns; cin >> rows >> columns; if(min(rows, columns) == 1) { cout << "YES\n"; return; } cout << (max(rows, columns) <= 2 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Programs/Quantifier Question.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 5; vector graph[MAX_N], reverse_graph[MAX_N]; vector visited(MAX_N, false); vector on_stack(MAX_N, false); vector visited_reverse(MAX_N, false), on_stack_reverse(MAX_N, 0); int dfs_cycle_reverse(int v) { visited_reverse[v] = true; on_stack_reverse[v] = true; for(int i = 0; i < reverse_graph[v].size(); i++) { int child_v = reverse_graph[v][i]; if(visited_reverse[child_v] && on_stack_reverse[child_v]) { return true; } if(!visited_reverse[child_v] && dfs_cycle_reverse(child_v)) { return true; } } on_stack_reverse[v] = false; return false; } int dfs_cycle(int v) { visited[v] = true; on_stack[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(visited[child_v] && on_stack[child_v]) { return true; } if(!visited[child_v] && dfs_cycle(child_v)) { return true; } } on_stack[v] = false; return false; } int main() { int no_of_variables, no_of_inequalities; cin >> no_of_variables >> no_of_inequalities; vector indegree(no_of_variables + 1, 0); for(int i = 1; i <= no_of_inequalities; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); reverse_graph[v].push_back(u); indegree[v]++; //cout << "In Degree " << v << " = " << indegree[v] << "\n"; } int no_of_universals = 0; string answer; for(int i = 1; i <= no_of_variables; i++) { if(!visited[i] && !visited_reverse[i]) { no_of_universals++; answer += 'A'; } else { answer += 'E'; } if(dfs_cycle(i) || dfs_cycle_reverse(i)) { cout << "-1\n"; return 0; } } cout << no_of_universals << "\n"; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/639 Div 2/Programs/Resume Review.cpp ================================================ #include #include using namespace std; long long no_of_elements, total_steps; vector A, B; long long no_of_steps(long long x) { long long steps = 0; for(int i = 1; i <= no_of_elements; i++) { long long left = 0, right = A[i] + 1; //Left is always possible, right is not while(right - left > 1) { long long mid = (left + right)/2; long long smallest_contribution = A[i] - 3*mid*mid+ 3*mid - 1; if(smallest_contribution > x) { left = mid; } else { right = mid; } } B[i] = left; steps += left; } return steps; } int main() { cin >> no_of_elements >> total_steps; A.resize(no_of_elements + 1); B.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } // > Right is always possible, <= Left is never possible long long left = -3e18, right = 3e18; while(right - left > 1) { long long mid = (left + right)/2; if(no_of_steps(mid) <= total_steps) { right = mid; } else { left = mid; } } long long final_steps = no_of_steps(right); for(int i = 1; i <= no_of_elements && final_steps < total_steps; i++) { if(B[i] == A[i]) { continue; } long long new_b = B[i] + 1; if(A[i] - 3*new_b*new_b + 3*new_b - 1 == right) { B[i]++; final_steps++; } } for(int i = 1; i <= no_of_elements; i++) { cout << B[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/641 Div 2/Explanations/Orac and Factors Explanation.txt ================================================ Let us notice that f(n) = 2 for all even integers. If n is odd, then (f(n) + n) is even So, we can do n = (f(n) + n) for our first step And for the remaining (k - 1) steps, we will just add 2 to n ! The main idea here is observing that f(n) = 2 for all even ----- void precompute() { for(int i = 2; i < MAX_N; i++) { for(long long multiple = i; multiple < MAX_N; multiple += i) { if(smallest_multiple[multiple] == 0) { smallest_multiple[multiple] = i; } } } } void solve() { long long n, k; cin >> n >> k; n += smallest_multiple[n]; k--; n += k*2; cout << n << "\n"; } ================================================ FILE: 2020/Div 2/641 Div 2/Explanations/Orac and LCM Explanation.txt ================================================ The gcd of this set should divide every element of the set. Let us look at each prime seperately. ----- Case 1 - There are at least 2 integers not divisible by P In this case, their LCM will also not be divisible by P So, the GCD of the set should now have P set in it ----- Case 2 - There is only 0 or 1 integer not divisible by P In this case, the LCM of every pair will have an exponent of P in it The lowest exponent of P will be equal to the the second smallest exponent of P in the array ----- For each prime, we will count the number of multiples it has If the number of multiples >= N - 1, Then, we will multiply P^{Second Smallest Exponent} to our answer ----- void precompute() { vector is_prime(MAX_N, true); for(int i = 2; i < MAX_N; i++) { if(is_prime[i]) { primes.push_back(i); } for(int j = 0; j < primes.size() && i*primes[j] < MAX_N; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) { break; } } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); precompute(); vector > minimum_exponents(primes.size() + 1, make_pair(100, 100)); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } if(no_of_elements == 2) { cout << (A[1]*A[2])/gcd(A[1], A[2]) << "\n"; return 0; } vector frequency(MAX_N, 0); for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } vector no_of_multiples(primes.size() + 1, 0); for(int i = 0; i < primes.size(); i++) { int p = primes[i]; for(int multiple = p; multiple < MAX_N; multiple += p) { no_of_multiples[i] += frequency[multiple]; } } for(int i = 1; i <= no_of_elements; i++) { for(int j = 0; j < primes.size() && A[i] > 1; j++) { int p = primes[j]; int exponent_here = 0; if(no_of_multiples[j] <= no_of_elements - 2) { continue; } while(A[i]%p == 0) { exponent_here++; A[i] /= p; } if(exponent_here <= minimum_exponents[j].first) { minimum_exponents[j].second = minimum_exponents[j].first; minimum_exponents[j].first = exponent_here; } else if(exponent_here < minimum_exponents[j].second) { minimum_exponents[j].second = exponent_here; } } if(A[i] > 1) { int j = lower_bound(primes.begin(), primes.end(), A[i]) - primes.begin(); if(no_of_multiples[j] > no_of_elements - 2) { int exponent_here = 1; if(exponent_here <= minimum_exponents[j].first) { minimum_exponents[j].second = minimum_exponents[j].first; minimum_exponents[j].first = exponent_here; } else if(exponent_here < minimum_exponents[j].second) { minimum_exponents[j].second = exponent_here; } } } } long long answer = 1; for(int p = 0; p < primes.size(); p++) { int exponent = minimum_exponents[p].second; if(no_of_multiples[ p ] <= no_of_elements - 2) continue; for(int j = 1; j <= exponent; j++) { answer *= primes[p]; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/641 Div 2/Explanations/Orac and Models Explanation.txt ================================================ Let us modify a sieve logic to get the answer For every integer i, we can go from i to some multiple of i We will check the transition from i to all of i's multiples and choose the best answer ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector answer_till(no_of_elements + 1, 1); for(int i = 1; i <= no_of_elements; i++) { for(int m = i; m <= no_of_elements; m += i) { if(A[i] < A[m]) { answer_till[m] = max(answer_till[m], answer_till[i] + 1); //cout << "Answer " << m << " = " << answer_till[m] << "\n"; } } } int answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer = max(answer, answer_till[i]); } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/641 Div 2/Programs/Orac and Factors.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e6 + 5; vector smallest_multiple(MAX_N, 0); void precompute() { for(int i = 2; i < MAX_N; i++) { for(long long multiple = i; multiple < MAX_N; multiple += i) { if(smallest_multiple[multiple] == 0) { smallest_multiple[multiple] = i; } } } } void solve() { long long n, k; cin >> n >> k; n += smallest_multiple[n]; k--; n += k*2; cout << n << "\n"; } int main() { precompute(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/641 Div 2/Programs/Orac and LCM.cpp ================================================ void precompute() { vector is_prime(MAX_N, true); for(int i = 2; i < MAX_N; i++) { if(is_prime[i]) { primes.push_back(i); } for(int j = 0; j < primes.size() && i*primes[j] < MAX_N; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) { break; } } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); precompute(); vector > minimum_exponents(primes.size() + 1, make_pair(100, 100)); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } if(no_of_elements == 2) { cout << (A[1]*A[2])/gcd(A[1], A[2]) << "\n"; return 0; } vector frequency(MAX_N, 0); for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } vector no_of_multiples(primes.size() + 1, 0); for(int i = 0; i < primes.size(); i++) { int p = primes[i]; for(int multiple = p; multiple < MAX_N; multiple += p) { no_of_multiples[i] += frequency[multiple]; } } for(int i = 1; i <= no_of_elements; i++) { for(int j = 0; j < primes.size() && A[i] > 1; j++) { int p = primes[j]; int exponent_here = 0; if(no_of_multiples[j] <= no_of_elements - 2) { continue; } while(A[i]%p == 0) { exponent_here++; A[i] /= p; } if(exponent_here <= minimum_exponents[j].first) { minimum_exponents[j].second = minimum_exponents[j].first; minimum_exponents[j].first = exponent_here; } else if(exponent_here < minimum_exponents[j].second) { minimum_exponents[j].second = exponent_here; } } if(A[i] > 1) { int j = lower_bound(primes.begin(), primes.end(), A[i]) - primes.begin(); if(no_of_multiples[j] > no_of_elements - 2) { int exponent_here = 1; if(exponent_here <= minimum_exponents[j].first) { minimum_exponents[j].second = minimum_exponents[j].first; minimum_exponents[j].first = exponent_here; } else if(exponent_here < minimum_exponents[j].second) { minimum_exponents[j].second = exponent_here; } } } } long long answer = 1; for(int p = 0; p < primes.size(); p++) { int exponent = minimum_exponents[p].second; if(no_of_multiples[ p ] <= no_of_elements - 2) continue; for(int j = 1; j <= exponent; j++) { answer *= primes[p]; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/641 Div 2/Programs/Orac and Models.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector answer_till(no_of_elements + 1, 1); for(int i = 1; i <= no_of_elements; i++) { for(int m = i; m <= no_of_elements; m += i) { if(A[i] < A[m]) { answer_till[m] = max(answer_till[m], answer_till[i] + 1); //cout << "Answer " << m << " = " << answer_till[m] << "\n"; } } } int answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer = max(answer, answer_till[i]); } cout << answer << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Explanation/Counting Triangles Explanation.txt.txt ================================================ - We know $x < y \< z$ so we will count the number of triplets where $z < x + y$ - $x + y \in [A + B, A + C]$ - For every possible sum, we will calculate the number of ways of getting it. - If we fix a value of $x$, we can get every value from $x + B \to x + C$ - We can do this with a linear sweep. - For every possible $z$, we will count the number of ways to get any sum $> z$, which can be gotten using a suffix sum over the number of ways array. ----- int main() { int A, B, C, D; cin >> A >> B >> C >> D; vector no_of_starts(B + C + 5, 0), no_of_finishes(B + C + 5, 0); for(int x = A; x <= B; x++) { no_of_starts[x + B]++; no_of_finishes[x + C + 1]++; } vector no_of_ways(B + C + 5, 0); for(int i = B; i <= B + C; i++) { no_of_ways[i] = no_of_ways[i - 1] + no_of_starts[i] - no_of_finishes[i]; } vector suffix_sum(B + C + 5, 0); for(int i = B + C; i >= B; i--) { suffix_sum[i] = suffix_sum[i + 1] + no_of_ways[i]; } long long no_of_triangles = 0; for(int z = C; z <= min(D, B + C); z++) { no_of_triangles += suffix_sum[z + 1]; } cout << no_of_triangles << "\n"; return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Explanation/Game with Array Explanation.txt ================================================ A win is always possible if S > 2n In the array [2, 2, 2, ... 2, S - 2(n - 1)], there is no subarray with sum either 1 or S - 1 If there exists a subarray who's sum is (S - 1), then the remaining array must sum to 1. But, this does not exist. ----- If S <= 2n, we can reach every integer in [0, S] The array consists of 1's and 2's. - Let us look at the prefix sums $\mod S$ - $P_1, P_2, \dots , P_n$ are all distinct since they are all positive. - $P_1 + K, P_2 + K, P_3 + K, \dots , P_n + k$ are also all pairwise distinct. - Now, we have $2n$ integers all in the range $[0, S - 1]$. By the Pigeonhole Principle, there must be two that are equal since $S < 2n$ - $P_i = P_j + K \pmod S$ - If $i > j$, then we have a subarray $[j, i]$ who's sum is $K$ - Otherwise, we have a subarray $[j, i]$ who's sum is $(S - K)$ since some prefix $[1, j - 1]$and suffix $[i, n]$ add up to $K$ ----- #include using namespace std; int main() { int no_of_elements, sum; cin >> no_of_elements >> sum; if(sum >= 2*no_of_elements) { cout << "YES\n"; for(int i = 1; i <= no_of_elements; i++) { cout << (i < no_of_elements ? 2 : sum - 2*(no_of_elements - 1)) << " "; } cout << "\n"; cout << "1\n"; } else { cout << "NO\n"; } return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Explanation/Restorer Distance Explanation.txt ================================================ What is the cost to make each tower = height H ? We can set M = min(M, A + R) because moving a block is the same as adding and removing. For every height H, we will calculate the number of 'extra' and 'missing' blocks. We can do this using prefix sums and binary search. We will first move min(extra, missing). After that, if we still have extra blocks, we will add them. If we still have missing blocks, we will remove them. ----- It is a piecewise linear function. So, we can check the value of the function at all H[i], along with 1 additional value (S/n) - both floor and ceil. As this is the point where we 'transition' from having more missing blocks to more extra blocks. ----- We can also use ternary search like I did. But the proof for unimodality is complicated. ----- long long calculate(long long h) { int l = lower_bound(all(height), h) - height.begin() - 1; int r = upper_bound(all(height), h) - height.begin(); long long missing_blocks = l*h - sum_till[l]; long long extra_blocks = sum_till[no_of_elements] - sum_till[r - 1] - h*(no_of_elements - r + 1); long long cost = relocate*min(missing_blocks, extra_blocks); if(missing_blocks > extra_blocks) { cost += add*(missing_blocks - extra_blocks); } else if(extra_blocks > missing_blocks) { cost += destroy*(extra_blocks - missing_blocks); } //Overflow if(cost < 0) { cost = oo; } return cost; } ----- Now, let us perform ternary search and find out the best value of H int main() { cin >> no_of_elements >> add >> destroy >> relocate; relocate = min(relocate, add + destroy); height.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> height[i]; } sort(all(height)); sum_till.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + height[i]; } const long long RANGE = 2; long long left = height[1], right = height[no_of_elements]; while(right - left > RANGE) { long long mid_1 = left + (right - left)/3, mid_2 = right - (right - left)/3; if(calculate(mid_1) > calculate(mid_2)) { left = mid_1; } else { right = mid_2; } } long long answer = min(calculate(left), calculate(right)); for(long long i = left; i <= right; i++) { answer = min(answer, calculate(i)); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Explanation/Sequence with Digits Explanation.txt ================================================ We will keep performing the operation till the minimum digit is 0. This will always happen. After this, there is no change to n anymore. ----- pair max_min_digit(long long n) { pair max_min = make_pair(0, 10); while(n) { int digit = n%10; max_min.first = max(max_min.first, digit); max_min.second = min(max_min.second, digit); n /= 10; } return max_min; } void solve() { long long n, k; cin >> n >> k; for(int i = 2; i <= k && max_min_digit(n).second != 0; i++) { n += max_min_digit(n).first*max_min_digit(n).second; } cout << n << "\n"; } ================================================ FILE: 2020/Div 2/643 Div 2/Explanation/Young Explorer Explanation.txt ================================================ Let the sorted array be A[1] < A[2] < ... < A[n] Now, if A[L, ... R] is a group, then the number of people should be A[R] How do we check all possibilities ? For every person A[i], let us make A[i] the largest experience in the group. Let f(i) be the largest number of groups for the first i people. There are 2 possibilities 1. i is the last part of a group. In which case, the current group goes from A[i - A[i], i] 2. i is not part of any group. So, f(i) = max(1 + f(i - A[i]), f(i - 1)) ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin(), A.end()); vector max_groups(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { max_groups[i] = max_groups[i - 1]; if(i - A[i] >= 0) { max_groups[i] = max(max_groups[i], 1 + max_groups[i - A[i]]); } } cout << max_groups[no_of_elements] << "\n"; } ================================================ FILE: 2020/Div 2/643 Div 2/Programs/Counting Triangles.cpp ================================================ #include #include using namespace std; int main() { int A, B, C, D; cin >> A >> B >> C >> D; vector no_of_starts(B + C + 5, 0), no_of_finishes(B + C + 5, 0); for(int x = A; x <= B; x++) { no_of_starts[x + B]++; no_of_finishes[x + C + 1]++; } vector no_of_ways(B + C + 5, 0); for(int i = B; i <= B + C; i++) { no_of_ways[i] = no_of_ways[i - 1] + no_of_starts[i] - no_of_finishes[i]; } vector suffix_sum(B + C + 5, 0); for(int i = B + C; i >= B; i--) { suffix_sum[i] = suffix_sum[i + 1] + no_of_ways[i]; } long long no_of_triangles = 0; for(int z = C; z <= min(D, B + C); z++) { no_of_triangles += suffix_sum[z + 1]; } cout << no_of_triangles << "\n"; return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Programs/Game with Array.cpp ================================================ #include using namespace std; int main() { int no_of_elements, sum; cin >> no_of_elements >> sum; if(sum >= 2*no_of_elements) { cout << "YES\n"; for(int i = 1; i <= no_of_elements; i++) { cout << (i < no_of_elements ? 2 : sum - 2*(no_of_elements - 1)) << " "; } cout << "\n"; cout << "1\n"; } else { cout << "NO\n"; } return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Programs/Restorer Distance.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long no_of_elements, relocate, destroy, add; vector height; vector sum_till; const long long oo = 1e18; long long calculate(long long h) { int l = lower_bound(all(height), h) - height.begin() - 1; int r = upper_bound(all(height), h) - height.begin(); long long missing_blocks = l*h - sum_till[l]; long long extra_blocks = sum_till[no_of_elements] - sum_till[r - 1] - h*(no_of_elements - r + 1); long long cost = relocate*min(missing_blocks, extra_blocks); if(missing_blocks > extra_blocks) { cost += add*(missing_blocks - extra_blocks); } else if(extra_blocks > missing_blocks) { cost += destroy*(extra_blocks - missing_blocks); } //Overflow if(cost < 0) { cost = oo; } return cost; } int main() { cin >> no_of_elements >> add >> destroy >> relocate; relocate = min(relocate, add + destroy); height.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> height[i]; } sort(all(height)); sum_till.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + height[i]; } const long long RANGE = 2; long long left = height[1], right = height[no_of_elements]; while(right - left > RANGE) { long long mid_1 = left + (right - left)/3, mid_2 = right - (right - left)/3; if(calculate(mid_1) > calculate(mid_2)) { left = mid_1; } else { right = mid_2; } } long long answer = min(calculate(left), calculate(right)); for(long long i = left; i <= right; i++) { answer = min(answer, calculate(i)); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Programs/Sequence with Digits.cpp ================================================ #include using namespace std; pair max_min_digit(long long n) { pair max_min = make_pair(0, 10); while(n) { int digit = n%10; max_min.first = max(max_min.first, digit); max_min.second = min(max_min.second, digit); n /= 10; } return max_min; } void solve() { long long n, k; cin >> n >> k; for(int i = 2; i <= k && max_min_digit(n).second != 0; i++) { n += max_min_digit(n).first*max_min_digit(n).second; } cout << n << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/643 Div 2/Programs/Young Explorer.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin(), A.end()); vector max_groups(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { max_groups[i] = max_groups[i - 1]; if(i - A[i] >= 0) { max_groups[i] = max(max_groups[i], 1 + max_groups[i - A[i]]); } } cout << max_groups[no_of_elements] << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/647 Div 2/Explanations/Johnny and Ancient Computers Explanation.txt ================================================ We can never remove any 1 from an integer. The only operation we can do is append 0 and remove trailing 0's. So, without loss of generality, let (a < b), If this is not the case, then swap(a, b) We will try to reach a -> b by appending 0's only. If it is possible, we will take as many steps of 3 as possible. Answer = Ceil(Steps/3) ----- void solve() { long long a, b; cin >> a >> b; if(a > b) { swap(a, b); } int steps = 0; while(a < b) { a *= 2; steps++; } int actual_steps = (a == b ? ceil(steps, 3) : -1); cout << actual_steps << "\n"; } ================================================ FILE: 2020/Div 2/647 Div 2/Explanations/Johnny and Another Rating Drop Explanation.txt ================================================ Let us look at each bit seperately ? How much does the last bit contribute to the sum ? The last bit is always 01 01 01 It contributes n to the sum as each of the n pairs (out of n + 1 integers), has a difference Let us look at the second last bit, It toggles 00 11 00 11 0 and so on It contributes ceil(N/2) to the sum Similarly, we will count the number of 'blocks', which is (N/2^i) + 1, For N and the I-th bit The contribution is (Number of Blocks - 1) as each adjacent pair of blocks contributes 1 We have to count the contribution of each of the 63 bits ----- #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n& (1LL << bit)) != 0 ); } long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } void solve() { long long n; cin >> n; long long answer = 0; const int MAX_BITS = 63; int msb = 0; for(int bit = 0; bit < MAX_BITS; bit++) { if(is_bit_set(n, bit)) { msb = bit; } } for(int bit = 0; bit <= msb; bit++) { long long p = (1LL << bit); long long no_of_blocks = n/p + 1; //cout << "B = " << bit << " Contribution Number of BLocks = " << no_of_blocks << "\n"; answer += no_of_blocks - 1; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/647 Div 2/Explanations/Johnny and Contribution Explanation.txt ================================================ We will model this by a graph. A blog is a vertex and two vertices will share an edge if there is a reference from one to the other. We will colour each vertex with it's topic number. The problem is to order the vertices in such an order that if we colour them in that order, making each vertex = MEX(neighbours), Each vertex will have the colour we desire ----- We will start with an uncoloured graph. Clearly, we must colour all vertices with topic = 1 first Then, we must colour all vertices with topic = 2 And so on We will first sort the vertices by their topic numbers Then, we will colour the graph While colouring the graph with our current colour, we will check the MEX (Neighbours) ----- If it is the same as the colour we desire, we will continue. Otherwise, we will say it is not possible. ----- The correct order is either the sorted order or does not exist ----- Now, the question is, how do we find out the MEX of it's neighbours quickly ? One method is that When we are colour vertex V, we will check all it's neighbours and find out the MEX This requires us to keep a set for each vertex and adds an additional log factor. ---- There is a beautiful approach by which we can remove this log factor. Instead of maintaining a set against each vertex, we can maintain an array, MEX[N], which contains the MEX of each vertex Initially, the MEX of each vertex is 0. When we colour a vertex v, we will update the MEX of all it's neighbours. This is a beautiful example in which inverting the order of operations saves time 1. Looking at all the neighbours and calculating MEX takes O(E log E) time for each vertex 2. Colouring a neighbour and then updating all it's neighbours' MEX takes O(E) time This beautiful approach helps us reduce a log factor ---- Suppose U is a neighbour of V, If MEX[u] = Colour[V], Then MEX[u] = Colour[V] + 1 Otherwise, MEX[u] remains as it is ---- ---- #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 5e5 + 5; vector graph[MAX_N]; vector colour(MAX_N, 0); vector mex(MAX_N, 1); vector > desired_colour; void update_mex(int v) { for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(mex[child] == colour[v]) { mex[child]++; } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1 ; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } desired_colour.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> desired_colour[i].first; desired_colour[i].second = i; } sort(desired_colour.begin() + 1, desired_colour.end()); vector best_order(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { if(mex[desired_colour[i].second] != desired_colour[i].first) { cout << "-1\n"; return 0; } best_order[i] = desired_colour[i].second; colour[desired_colour[i].second] = desired_colour[i].first; update_mex(best_order[i]); } for(int i = 1; i <= no_of_vertices; i++) { cout << best_order[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/647 Div 2/Explanations/Johnny and His Hobbies Explanation.txt ================================================ Let us try every k in [1, 1024] We will check if each k is good in O( N ) time and stop at the first good k k can not be greater than 2^{10}, as that bit is not set in any of the integers Store all the integers in a set for convenience ----- There is also another idea XOR(A[i], x) = A[j] XOR(A[i], A[j]) = x, So, x will have to be one of (N - 1) possible values. ----- int possible(int k, set &S) { for(auto it = S.begin(); it != S.end(); it++) { int x = *it; if(S.find(x^k) == S.end()) { return false; } } return true; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); set S; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; S.insert(A[i]); } const int oo = 1e9, MAX_K = 1025; int best_k = oo; for(int k = 1; k <= MAX_K; k++) { if(possible(k, S)) { best_k = min(best_k, k); break; } } if(best_k == oo) { best_k = -1; } cout << best_k << "\n"; } ================================================ FILE: 2020/Div 2/647 Div 2/Programs/Johnny and Ancient Computers.cpp ================================================ #include using namespace std; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } void solve() { long long a, b; cin >> a >> b; if(a > b) { swap(a, b); } int steps = 0; while(a < b) { a *= 2; steps++; } int actual_steps = (a == b ? ceil(steps, 3) : -1); cout << actual_steps << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/647 Div 2/Programs/Johnny and Another Rating Drop.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n& (1LL << bit)) != 0 ); } long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } void solve() { long long n; cin >> n; long long answer = 0; const int MAX_BITS = 63; int msb = 0; for(int bit = 0; bit < MAX_BITS; bit++) { if(is_bit_set(n, bit)) { msb = bit; } } for(int bit = 0; bit <= msb; bit++) { long long p = (1LL << bit); long long no_of_blocks = n/p + 1; answer += no_of_blocks - 1; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/647 Div 2/Programs/Johnny and Contribution.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 5e5 + 5; vector graph[MAX_N]; vector colour(MAX_N, 0); vector mex(MAX_N, 1); vector > desired_colour; void update_mex(int v) { for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(mex[child] == colour[v]) { mex[child]++; } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1 ; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } desired_colour.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> desired_colour[i].first; desired_colour[i].second = i; } sort(desired_colour.begin() + 1, desired_colour.end()); vector best_order(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { if(mex[desired_colour[i].second] != desired_colour[i].first) { cout << "-1\n"; return 0; } best_order[i] = desired_colour[i].second; colour[desired_colour[i].second] = desired_colour[i].first; update_mex(best_order[i]); } for(int i = 1; i <= no_of_vertices; i++) { cout << best_order[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/647 Div 2/Programs/Johnny and His Hobbies.cpp ================================================ #include #include #include using namespace std; int possible(int k, set &S) { for(auto it = S.begin(); it != S.end(); it++) { int x = *it; if(S.find(x^k) == S.end()) { return false; } } return true; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); set S; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; S.insert(A[i]); } const int oo = 1e9, MAX_K = 1025; int best_k = oo; for(int k = 1; k <= MAX_K; k++) { if(possible(k, S)) { best_k = min(best_k, k); break; } } if(best_k == oo) { best_k = -1; } cout << best_k << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Explanations/Maximum Subsequence Value Explanation.txt ================================================ We want a set of integers and want to know the bits that are set in all, but 2 of the integers. It can be shown that the optimal set always consists of 3 integers. And the value = OR(A[i], A[j], A[k]) If We add a new integer Z, to the set {A[i], A[j], A[k]}, then every bit of Z must be set in any 1 of {A[i], A[j], A[k]} If Z has a bit set that is greater in value to the bits that are existing, we can just replace one of the 3 integers by Z and get a higher answer So, it will never be optimal to have more than 3 integers. We just have to check all the triplets ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { for(int j = i; j <= no_of_elements; j++) { for(int k = j; k <= no_of_elements; k++) { answer = max(answer, A[i]|A[j]|A[k]); } } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Explanations/Secure Password Explanation.txt.txt ================================================ # Naive Approach - Let us assign a bitmask of $i$ to each of the $n$ elements. - We will perform $2 \log n$ queries. - Find the OR of all elements with the $b$-th bit set - Find the OR of all elements with the $b$-th bit unset - Suppose we want to find the answer for $10011$ - We will collect the OR of all elements which have the $2, 3$ bit set and the $0, 1, 4$ bit unset. - This ensures that every element is counted at least once. - Counting an element more than once does not change the answer. --- # Assigning bitmasks so no $2$ are submasks - In the naive approach, we were checking all elements which match the complement of $i$. But, why don't we only check elements which have a $1$ where $i$ has a $0$. - This way we only need to collect the bitwise OR of all elements which a bit set in their mask. This takes $\log n$ queries. - The problem occurs when one mask is a submask of another. For example, $110000$ is a submask of $111100$ - If we only query those subsets which have a $1$ where our mask has a $0$, we will never hit $110000$ or any other submask - We will assign masks in such a way that no mask is a submask of another mask. - Bits which have the same number of bits set can never be a submask of each other. The smallest number of bits for which we can get $1000$ bitmasks is $6$ - We will collect bitmasks which have $6$ bits set. Assign a mask to each of the $n$ positions. Collect the subset OR of all $13$ bits - We can get the value of $P[i]$ by OR-ing all those subsets which have $1$ where it has a $0$ ----- int main() { int no_of_elements; cin >> no_of_elements; const int SET_BITS = 6; vector mask(no_of_elements + 1); for(int m = 1, i = 1; i <= no_of_elements; m++) { if(no_of_bits(m) == SET_BITS) { mask[i] = m; i++; } } const int NO_OF_BITS = 13; vector < vector > subset(NO_OF_BITS + 1); for(int i = 1; i <= no_of_elements; i++) { for(int bit = 0; bit < NO_OF_BITS; bit++) { if(is_bit_set(mask[i], bit)) { subset[bit].push_back(i); } } } vector subset_OR(NO_OF_BITS + 1, 0); for(int bit = 0; bit < NO_OF_BITS; bit++) { if(subset[bit].size() == 0) { continue; } cout << "? " << subset[bit].size() << " "; for(int i = 0; i < subset[bit].size(); i++) { cout << subset[bit][i] << " "; } cout << "\n"; cout.flush(); cin >> subset_OR[bit]; } vector answer(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { for(int bit = 0; bit < NO_OF_BITS; bit++) { if(!is_bit_set(mask[i], bit)) { answer[i] |= subset_OR[bit]; } } } cout << "! "; for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Explanations/Swaps Again Explanation.txt ================================================ Let us look at how the array is affected after one operation - $(a_1, a_2, \dots , a_i, \dots , a_{n - i + 1}, a_{n - i + 2}, \dots , a_n)$ - $(a_{n - i + 1}, a_{n - i + 2}, \dots , a_n, \dots , a_1, a_2 \dots a_i)$ There is a very interesting invariant here. The pairs $(a_i, a_{n - i + 1})$ are always together, but can be swapped. So, we will check whether all $n/2$ pairs $(a_i, a_{n - i + 1})$ and see that both arrays have the same pairs. ----- If the invariant is met, we can put each element in place in at most 3 steps Suppose we want to put the correct element in the index $i$. And suppose $a_i$ is in position $p$. - We will perform $[1, p]$ if $p < n$ - Now $a_p$ is the last element. - We will perform operation $[1, i]$ - Now $a_p$ is in the $i$-th index - If $p$ was in the second half of the array, we'd need an extra operation. It requires at most $3$ operations for each pair. ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int j = 1; j <= no_of_elements; j++) { cin >> B[j]; } map < pair , int> frequency_A; for(int i = 1; 2*i <= no_of_elements; i++) { if(A[i] > A[no_of_elements - i + 1]) { swap(A[i], A[no_of_elements - i + 1]); } frequency_A[make_pair(A[i], A[no_of_elements - i + 1])]++; } map < pair , int> frequency_B; for(int i = 1; 2*i <= no_of_elements; i++) { if(B[i] > B[no_of_elements - i + 1]) { swap(B[i], B[no_of_elements - i + 1]); } frequency_B[make_pair(B[i], B[no_of_elements - i + 1])]++; } int possible = true; if(no_of_elements%2 == 1) { if(A[no_of_elements/2 + 1] != B[no_of_elements/2 + 1]) { possible = false; } } for(auto it = frequency_A.begin(); it != frequency_A.end(); it++) { pair current_pair = it->first; if(frequency_A[current_pair] != frequency_B[current_pair]) { possible = false; } } cout << (possible ? "Yes\n" : "No\n"); } ================================================ FILE: 2020/Div 2/648 Div 2/Programs/Matrix Game.cpp ================================================ #include #include using namespace std; void solve() { int rows, columns; cin >> rows >> columns; vector claimed_row(rows + 1, false), claimed_column(columns + 1, false); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int cell; cin >> cell; if(cell != 0) { claimed_row[i] = true; claimed_column[j] = true; } } } int row_moves = 0; for(int i = 1; i <= rows; i++) { row_moves += (!claimed_row[i]); } int column_moves = 0; for(int j = 1; j <= columns; j++) { column_moves += (!claimed_column[j]); } int moves = min(row_moves, column_moves); cout << (moves%2 == 0 ? "Vivek\n" : "Ashish\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Programs/Maximum Subsequence Value.cpp ================================================ #include #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0 ); } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { for(int j = i; j <= no_of_elements; j++) { for(int k = j; k <= no_of_elements; k++) { answer = max(answer, A[i]|A[j]|A[k]); } } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Programs/Rotation Matching.cpp ================================================ #include #include using namespace std; int calculate_left_shifts(int source, int target, int no_of_elements) { if(target < source) { return (source - target); } return (source + (no_of_elements - target)); } int calculate_right_shifts(int source, int target, int no_of_elements) { if(source < target) { return (target - source); } return ((no_of_elements - source) + target); } int get_matches(vector &A, vector &B) { int no_of_elements = A.size() - 1; vector B_index(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { B_index[B[i]] = i; } vector mismatches_after_left_shift(no_of_elements + 1, no_of_elements); vector mismatches_after_right_shift(no_of_elements + 1, no_of_elements); for(int i = 1; i <= no_of_elements; i++) { int j = B_index[A[i]]; int left_shifts = calculate_left_shifts(i, j, no_of_elements); int right_shifts = calculate_right_shifts(i, j, no_of_elements); mismatches_after_left_shift[left_shifts]--; mismatches_after_right_shift[right_shifts]--; } vector matches_after_left_shift(no_of_elements + 1, 0); vector matches_after_right_shift(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { matches_after_left_shift[i] = no_of_elements - mismatches_after_left_shift[i]; matches_after_right_shift[i] = no_of_elements - mismatches_after_right_shift[i]; } int maximum_matches = 0; for(int i = 1; i <= no_of_elements; i++) { maximum_matches = max(maximum_matches, matches_after_left_shift[i]); maximum_matches = max(maximum_matches, matches_after_right_shift[i]); } return maximum_matches; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } int maximum_matches = max(get_matches(A, B), get_matches(B, A)); cout << maximum_matches << "\n"; return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Programs/Secure Password.cpp ================================================ #include #include using namespace std; int no_of_bits(int mask) { int bit = 0; while(mask) { bit += (mask%2); mask /= 2; } return bit; } int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0); } int main() { int no_of_elements; cin >> no_of_elements; const int SET_BITS = 6; vector mask(no_of_elements + 1); for(int m = 1, i = 1; i <= no_of_elements; m++) { if(no_of_bits(m) == SET_BITS) { mask[i] = m; i++; } } const int NO_OF_BITS = 13; vector < vector > subset(NO_OF_BITS + 1); for(int i = 1; i <= no_of_elements; i++) { for(int bit = 0; bit < NO_OF_BITS; bit++) { if(is_bit_set(mask[i], bit)) { subset[bit].push_back(i); } } } vector subset_OR(NO_OF_BITS + 1, 0); for(int bit = 0; bit < NO_OF_BITS; bit++) { if(subset[bit].size() == 0) { continue; } cout << "? " << subset[bit].size() << " "; for(int i = 0; i < subset[bit].size(); i++) { cout << subset[bit][i] << " "; } cout << "\n"; cout.flush(); cin >> subset_OR[bit]; } vector answer(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { for(int bit = 0; bit < NO_OF_BITS; bit++) { if(!is_bit_set(mask[i], bit)) { answer[i] |= subset_OR[bit]; } } } cout << "! "; for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Programs/Swaps Again.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int j = 1; j <= no_of_elements; j++) { cin >> B[j]; } map < pair , int> frequency_A; for(int i = 1; 2*i <= no_of_elements; i++) { if(A[i] > A[no_of_elements - i + 1]) { swap(A[i], A[no_of_elements - i + 1]); } frequency_A[make_pair(A[i], A[no_of_elements - i + 1])]++; } map < pair , int> frequency_B; for(int i = 1; 2*i <= no_of_elements; i++) { if(B[i] > B[no_of_elements - i + 1]) { swap(B[i], B[no_of_elements - i + 1]); } frequency_B[make_pair(B[i], B[no_of_elements - i + 1])]++; } int possible = true; if(no_of_elements%2 == 1) { if(A[no_of_elements/2 + 1] != B[no_of_elements/2 + 1]) { possible = false; } } for(auto it = frequency_A.begin(); it != frequency_A.end(); it++) { pair current_pair = it->first; if(frequency_A[current_pair] != frequency_B[current_pair]) { possible = false; } } cout << (possible ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/648 Div 2/Programs/Trouble Sort.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector present(2, false); vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; present[B[i]] = true; } int sorted = true; for(int i = 1; i < no_of_elements; i++) { if(A[i] > A[i + 1]) { sorted = false; } } cout << (sorted || (present[0] && present[1])? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Explanations/Binary Subsequence Rotation Explanation.txt ================================================ This operation does not allow us to add any new characters so the number of 1s and 0s must be equal. Let us ignore the positions where S[i] = T[i] and delete them from the string In one step, we can choose an alternating subsequence - 010101 or 1010101 Now, the question is to count the number of alternating sequences the string can be partitioned into ----- Let us keep track of the list of available sequences ending with 1 and with 0 When we are at S[i], we will check if there are any available sequences ending with it's complement. If there are, then we will match S[i] with that and update it accordingly. For example, if S[i] = 0, and we have sequence number 3 ending with 1, we will append s[i] to the third sequence ----- We will maintain a set of all available sequences ending with both numbers When we process S[i], we will check if it's complement is empty or if there is some available sequence We will update it accordingly ----- int main() { int length; string S, T; cin >> length >> S >> T; if(no_of_1s(S) != no_of_1s(T)) { cout << "-1\n"; return 0; } string effective_S; for(int i = 0; i < length; i++) { if(S[i] != T[i]) { effective_S += S[i]; } } int no_of_sequences = 0; set last_sequence[2]; for(int i = 0; i < effective_S.size(); i++) { int current = effective_S[i] - '0'; int complement = 1 - current; if(last_sequence[complement].size() == 0) { no_of_sequences++; last_sequence[current].insert(no_of_sequences); } else { auto it = last_sequence[complement].begin(); last_sequence[current].insert(*it); last_sequence[complement].erase(it); } } cout << no_of_sequences << "\n"; return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Explanations/GCD Compression Explanation.txt ================================================ Keep track of the indices of all the odd and even numbers. The sum of any two odd numbers is even. Pair the odd integers with each other and make the sum even at each step. void solve() { int n; cin >> n; vector odd_index, even_index; for(int i = 1; i <= 2*n; i++) { int x; cin >> x; if(x%2 == 0) { even_index.push_back(i); } else { odd_index.push_back(i); } } vector B; if(odd_index.size()%2 == 1 && even_index.size()%2 == 1) { for(int i = 1; i < odd_index.size(); i += 2) { cout << odd_index[i] << " " << odd_index[i + 1] << "\n"; } for(int i = 1; i < even_index.size(); i += 2) { cout << even_index[i] << " " << even_index[i + 1] << "\n"; } } else { if(odd_index.size() >= 2) { for(int i = 2; i < odd_index.size(); i += 2) { cout << odd_index[i] << " " << odd_index[i + 1] << "\n"; } for(int i = 0; i < even_index.size(); i += 2) { cout << even_index[i] << " " << even_index[i + 1] << "\n"; } } else { for(int i = 0; i < odd_index.size(); i += 2) { cout << odd_index[i] << " " << odd_index[i + 1] << "\n"; } for(int i = 2; i < even_index.size(); i += 2) { cout << even_index[i] << " " << even_index[i + 1] << "\n"; } } } } ================================================ FILE: 2020/Div 2/651 Div 2/Explanations/Maximum GCD Explanation.txt ================================================ void solve() { int n; cin >> n; cout << n/2 << "\n"; } ================================================ FILE: 2020/Div 2/651 Div 2/Explanations/Number Game Explanation.txt ================================================ If N is odd, then we can divide it by the entire integer and first player wins (except when N = 1) If N is a power of 2, then we must subtract 1 and give our opponent this situation. (Except when N = 2) If N is even but has odd divisors, then we can divide by an odd divisor and give it to our opponent. Out opponent will lose, provided N is a multiple of 4 or more. If our opponent gets 2, he will win If our number is of the form 2p, then we will lose if p is prime and win otherwise ----- void solve() { int n; cin >> n; if(n%4 == 0) { cout << (!is_power_of_2(n) ? "Ashishgup\n" : "FastestFinger\n"); return; } if(n%2 == 1) { cout << (n > 1 ? "Ashishgup\n" : "FastestFinger\n"); return; } if(n == 2) { cout << "Ashishgup\n"; return; } int no_of_odd_divisors = get_prime_divisor_count(n) - 1; cout << (no_of_odd_divisors > 1 ? "Ashishgup\n" : "FastestFinger\n"); } ================================================ FILE: 2020/Div 2/651 Div 2/Explanations/Odd Even Subsequence Explanation.txt ================================================ Let us binary search the answer. If we want to check if x is possible, we have to search for a sequence of length K such that either 1. All odd indices are < x 2. All even indices are < x We can do this greedily ----- #include #include using namespace std; int possible(vector &A, int x, int parity, int total_subsequence_length) { int subsequence_length = 0; for(int i = 1; i < A.size() && subsequence_length < total_subsequence_length; i++) { if((subsequence_length + 1)%2 != parity) { //cout << "Subsequence = " << subsequence_length << " i = " << i << "\n"; subsequence_length++; } else { if(A[i] <= x) { //cout << "Subsequence = " << subsequence_length << " i = " << i << "\n"; subsequence_length++; } } } return (subsequence_length == total_subsequence_length); } int main() { int no_of_elements, subsequence_length; cin >> no_of_elements >> subsequence_length; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int oo = 1e9 + 9; long long left = 0, right = oo; while(right - left > 1) { long long mid = (left + right)/2; //cout << "L = " << left << " R = " << right << "\n"; if(possible(A, mid, 0, subsequence_length) || possible(A, mid, 1, subsequence_length)) { right = mid; } else { left = mid; } } cout << right << "\n"; return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Programs/Binary Subsequence Rotation.cpp ================================================ #include #include using namespace std; int no_of_1s(string S) { int count = 0; for(int i = 0; i < S.size(); i++) { count += (S[i] == '1'); } return count; } int main() { int length; string S, T; cin >> length >> S >> T; if(no_of_1s(S) != no_of_1s(T)) { cout << "-1\n"; return 0; } string effective_S; for(int i = 0; i < length; i++) { if(S[i] != T[i]) { effective_S += S[i]; } } int no_of_sequences = 0; set last_sequence[2]; for(int i = 0; i < effective_S.size(); i++) { int current = effective_S[i] - '0'; int complement = 1 - current; if(last_sequence[complement].size() == 0) { no_of_sequences++; last_sequence[current].insert(no_of_sequences); } else { auto it = last_sequence[complement].begin(); last_sequence[current].insert(*it); last_sequence[complement].erase(it); } } cout << no_of_sequences << "\n"; return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Programs/GCD Compression.cpp ================================================ #include #include using namespace std; void solve() { int n; cin >> n; vector odd_index, even_index; for(int i = 1; i <= 2*n; i++) { int x; cin >> x; if(x%2 == 0) { even_index.push_back(i); } else { odd_index.push_back(i); } } vector B; if(odd_index.size()%2 == 1 && even_index.size()%2 == 1) { for(int i = 1; i < odd_index.size(); i += 2) { cout << odd_index[i] << " " << odd_index[i + 1] << "\n"; } for(int i = 1; i < even_index.size(); i += 2) { cout << even_index[i] << " " << even_index[i + 1] << "\n"; } } else { if(odd_index.size() >= 2) { for(int i = 2; i < odd_index.size(); i += 2) { cout << odd_index[i] << " " << odd_index[i + 1] << "\n"; } for(int i = 0; i < even_index.size(); i += 2) { cout << even_index[i] << " " << even_index[i + 1] << "\n"; } } else { for(int i = 0; i < odd_index.size(); i += 2) { cout << odd_index[i] << " " << odd_index[i + 1] << "\n"; } for(int i = 2; i < even_index.size(); i += 2) { cout << even_index[i] << " " << even_index[i + 1] << "\n"; } } } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Programs/Maximum GCD.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; cout << n/2 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Programs/Number Game.cpp ================================================ #include using namespace std; int is_power_of_2(int n) { return ( (n == 1) || (n&(n - 1)) == 0 ); } int get_prime_divisor_count(int n) { int count = 0; for(int i = 2; i*i <= n; i++) { while(n%i == 0) { n /= i; count++; } } if(n > 1) { count++; } return count; } void solve() { int n; cin >> n; if(n%4 == 0) { cout << (!is_power_of_2(n) ? "Ashishgup\n" : "FastestFinger\n"); return; } if(n%2 == 1) { cout << (n > 1 ? "Ashishgup\n" : "FastestFinger\n"); return; } if(n == 2) { cout << "Ashishgup\n"; return; } int no_of_odd_divisors = get_prime_divisor_count(n) - 1; cout << (no_of_odd_divisors > 1 ? "Ashishgup\n" : "FastestFinger\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/651 Div 2/Programs/Odd-Even Subsequence.cpp ================================================ #include #include using namespace std; int possible(vector &A, int x, int parity, int total_subsequence_length) { int subsequence_length = 0; for(int i = 1; i < A.size() && subsequence_length < total_subsequence_length; i++) { if((subsequence_length + 1)%2 != parity) { //cout << "Subsequence = " << subsequence_length << " i = " << i << "\n"; subsequence_length++; } else { if(A[i] <= x) { //cout << "Subsequence = " << subsequence_length << " i = " << i << "\n"; subsequence_length++; } } } return (subsequence_length == total_subsequence_length); } int main() { int no_of_elements, subsequence_length; cin >> no_of_elements >> subsequence_length; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int oo = 1e9 + 9; long long left = 0, right = oo; while(right - left > 1) { long long mid = (left + right)/2; //cout << "L = " << left << " R = " << right << "\n"; if(possible(A, mid, 0, subsequence_length) || possible(A, mid, 1, subsequence_length)) { right = mid; } else { left = mid; } } cout << right << "\n"; return 0; } ================================================ FILE: 2020/Div 2/658 Div 2/Explanations/Common Subsequence Explanation.txt ================================================ Sort the arrays. Go through every element in A and check if it exists in B If there exists a common subsequence, there will be a common subsequence of length 1 If there is no common subsequnece of length 1, there will be no common subsequence ----- void solve() { int n, m; cin >> n >> m; vector A(n); for(int i = 0; i < n; i++) { cin >> A[i]; } sort(all(A)); vector B(m); for(int i = 0; i < m; i++) { cin >> B[i]; } sort(all(B)); for(int i = 0; i < A.size(); i++) { if(binary_search(B.begin(), B.end(), A[i])) { cout << "YES\n"; cout << "1 " << A[i] << "\n"; return; } } cout << "NO\n"; } ================================================ FILE: 2020/Div 2/658 Div 2/Explanations/Sequential Nim Explanation.txt ================================================ Case 1 - The first element is not 1 The first player always wins Proof - There are two possibilities (Either the pile of (N - 1) stones is winning for the first player or the second player) ----- Case 1a - If the pile of (N - 1) stones (without the first pile) is winning for the first player, A - Leaves 1 stone in the pile B - Takes that 1 stone And A is now the first player in the pile of (N - 1) stones Case 1b - If the pile of (N - 1) stones (without the first pile) is winning for the second player, A - Takes the entire pile And A is now the Second Player in the pile of (N - 1) stones ------ Case 2 - The first element is 1, The first player has no choice and has to take it In fact, if there is a prefix of 1's If there are an odd number of 1's, the second player has the turn after the 1s are over If there are an even number of 1's, the first player has the turn after the 1s are over If there are piles remaining after the prefix of 1's is over, the player who has the turn will win Otherwise, the last player who took the last stone will win ------ void solve() { int no_of_piles; cin >> no_of_piles; vector A(no_of_piles + 1); for(int i = 1; i <= no_of_piles; i++) { cin >> A[i]; } int prefix_1s = 0; for(int i = 1; i <= no_of_piles && A[i] == 1; i++) { prefix_1s++; } if(prefix_1s == no_of_piles) { cout << (prefix_1s%2 == 0 ? "Second\n" : "First\n"); return; } cout << (prefix_1s%2 == 0 ? "First\n" : "Second\n"); } ================================================ FILE: 2020/Div 2/658 Div 2/Explanations/Unmerge Explanation.txt ================================================ Let us suppose P[1] is in A If P[2] < P[1], then P[2] will also be in A If P[3] < P[1], then P[3] will also be in A And so on, Let P[k] be the first element such that P[k] > P[1], ----- We can divide P into sequences S[1], S[2], S[3], ... , S[k], where S[1] > S[2] S[1] > S[3] and so on till S[1] > S[k] The entire sequence has to be in the same set. The reason is if any of these (k - 1) elements are in the other set, then S[1] will come after it. ----- The 'heads' of these sequences form an increasing sequence Each sequence can be either in A or in B, but a sequence has to be together. ----- For example, if P = {3, 2, 6, 1, 5, 7 , 8, 4} Then the sequences are {3, 2} {6, 1, 5} {7} {8, 4} We can divide these sequences into two sets such that their sum is 4 ----- A = {3, 2, 8, 4} B = {6, 1, 5, 7} Note that there are other valid partitions. We just need to ensure that the whole sequence is together. Within each set, sort the sequences by the chronological order in which they appear in P ----- A = {3, 2} B = {6, 1, 5, 7, 8, 4} A = {3, 2, 6, 1, 5} B = {7, 8, 4} A = {6, 1, 5} B = {3, 2, 7, 8, 4} ----- Let us take the sequence lengths L{1}, L{2}, ... , L{k} We have to check if they can be partitioned to two sets such that the sums are equal We have to check if there exists a subset who's sum is = n This can be done with a DP ----- void solve() { int n; cin >> n; vector P(2*n + 5); for(int i = 1; i <= 2*n; i++) { cin >> P[i]; } vector sequences; int length = 1, beginning = P[1]; for(int i = 2; i <= 2*n; i++) { if(P[i] > beginning) { sequences.push_back(length); beginning = P[i]; length = 1; } else { length++; } } sequences.push_back(length); vector > possible_sums(n + 1, vector (sequences.size() + 1, false)); for(int s = 0; s <= n; s++) { for(int i = 0; i < sequences.size(); i++) { if(s == 0) { possible_sums[s][i] = true; continue; } if(i == 0) { possible_sums[s][i] = (s == sequences[i] ? true : false); continue; } possible_sums[s][i] = possible_sums[s][i - 1]; if(s >= sequences[i]) { possible_sums[s][i] = (possible_sums[s][i - 1] || possible_sums[s - sequences[i]][i - 1]); } } } cout << (possible_sums[n][sequences.size() - 1] ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 2/658 Div 2/Programs/Common Subsequence.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int n, m; cin >> n >> m; vector A(n); for(int i = 0; i < n; i++) { cin >> A[i]; } sort(all(A)); vector B(m); for(int i = 0; i < m; i++) { cin >> B[i]; } sort(all(B)); for(int i = 0; i < A.size(); i++) { if(binary_search(B.begin(), B.end(), A[i])) { cout << "YES\n"; cout << "1 " << A[i] << "\n"; return; } } cout << "NO\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/658 Div 2/Programs/Sequential Nim.cpp ================================================ #include #include using namespace std; void solve() { int no_of_piles; cin >> no_of_piles; vector A(no_of_piles + 1); for(int i = 1; i <= no_of_piles; i++) { cin >> A[i]; } int prefix_1s = 0; for(int i = 1; i <= no_of_piles && A[i] == 1; i++) { prefix_1s++; } if(prefix_1s == no_of_piles) { cout << (prefix_1s%2 == 0 ? "Second\n" : "First\n"); return; } cout << (prefix_1s%2 == 0 ? "First\n" : "Second\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/658 Div 2/Programs/Unmerge.cpp ================================================ #include #include using namespace std; void solve() { int n; cin >> n; vector P(2*n + 5); for(int i = 1; i <= 2*n; i++) { cin >> P[i]; } vector sequences; int length = 1, beginning = P[1]; for(int i = 2; i <= 2*n; i++) { if(P[i] > beginning) { sequences.push_back(length); beginning = P[i]; length = 1; } else { length++; } } sequences.push_back(length); vector > possible_sums(n + 1, vector (sequences.size() + 1, false)); for(int s = 0; s <= n; s++) { for(int i = 0; i < sequences.size(); i++) { if(s == 0) { possible_sums[s][i] = true; continue; } if(i == 0) { possible_sums[s][i] = (s == sequences[i] ? true : false); continue; } possible_sums[s][i] = possible_sums[s][i - 1]; if(s >= sequences[i]) { possible_sums[s][i] = (possible_sums[s][i - 1] || possible_sums[s - sequences[i]][i - 1]); } } } cout << (possible_sums[n][sequences.size() - 1] ? "YES\n" : "NO\n"); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/659 Div 2/Explanations/Common Prefix Explanation.txt ================================================ S[i] should have at least (A[i - 1], A[i]) characters If this value is 0, it should have at least 1 character When we are constructing S[i], we will set the first (A[i - 1]) characters to S[i - 1] We want to avoid a longer prefix matching, so the remaining characters will be = 'a' + i (mod 25) It is a function of i, so it cannot be equal in both S[i] and S[i - 1] or S[i + 1] When we are in the last string, we should only check A[i - 1] If that is 0, we need to put 1 character on ourselves. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int NO_OF_ALPHABETS = 25; vector S(no_of_elements + 5); for(int i = 1; i <= no_of_elements + 1; i++) { //S[i].resize(max ( max(A[i], 10), A[i - 1] ) ); for(int j = 0; j < A[i - 1]; j++) { S[i] += S[i - 1][j]; //cout << S[i][j] << "\n"; } if(i > no_of_elements) { if(S[i].size() == 0) { S[i] += (char)( 'a' + (i)%(NO_OF_ALPHABETS) ); } continue; } for(int j = A[i - 1]; j < max(A[i], 1); j++) {//cout << "Reached j = " << (char)('a' + (i)%(NO_OF_ALPHABETS) ) << endl; S[i] += (char)('a' + (i)%(NO_OF_ALPHABETS) ); } } for(int i = 1; i <= no_of_elements + 1; i++) { cout << S[i] << "\n"; } } ================================================ FILE: 2020/Div 2/659 Div 2/Explanations/Prefix Flip (Easy Version) Explanation.txt ================================================ We can always do it with 3 flips for every unequal position. If (A[i] = B[i]), we do nothing. Otherwise, we will flip and reverse the prefix of length i Then, we will flip the first bit, Then, we will again flip and reverse the prefix of length i This leaves the remaining (i - 1) bits unchanged and flips the i-th bit and now A[i] = B[i] This can also be done in O(n) time and we do not need to simulate all 3 flips ----- void solve() { string A, B; int length; cin >> length >> A >> B; vector moves; for(int i = A.size() - 1; i >= 0; i--) { if(A[i] != B[i]) { moves.push_back(i + 1); moves.push_back(1); moves.push_back(i + 1); } } cout << moves.size() << " "; for(int i = 0; i < moves.size(); i++) { cout << moves[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 2/659 Div 2/Explanations/Prefix Flip (Hard Version) Explanation.txt ================================================ We will convert A to a string of all 0's and B to a string of all 0's If we reverse the order of operations done to B, then we can create B from a string of all 0's. ----- How to convert a string S to all 0's ? Let us append an extra 0 at the end of string S If S[i] and S[i + 1] are different, we will flip the prefix of length i This maintains the invariant that when we are at position (i + 1), the first i elements are the no_of_special_segments When we finish processing the entire string, it will be all-0's since the last alphabet is 0 ----- void solve() { string A, B; int length; cin >> length >> A >> B; A += '0', B += '0'; vector moves_A, moves_B; for(int i = 1; i <= length; i++) { if(A[i] != A[i - 1]) { moves_A.push_back(i); } if(B[i] != B[i - 1]) { moves_B.push_back(i); } } cout << moves_A.size() + moves_B.size() << " "; for(int i = 0; i < moves_A.size(); i++) { cout << moves_A[i] << " "; } for(int i = moves_B.size() - 1; i >= 0; i--) { cout << moves_B[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 2/659 Div 2/Explanations/String Transformation 1 Explanation.txt ================================================ We will follow the above strategy. We will draw an edge between alphabets u and v, if some instance of u should be converted to v Let {t1, t2, ... , tk} be all the target vertices of vertex v and let t1 < t2 < ... < tk We will convert all the instances of v to t1 and use only one move. We will also add {t2, t3, ... , tk} to the target set of vertex t1 ------ We will process the vertices in alphabetical order. Each alphabet will include at most 1 move. So, the total number of moves will not be more than 19. Also, this always works because a target set of an alphabet becomes empty after we finish processing it. When we finish processing all 20 alphabets, all the target sets are empty ----- void solve() { int length; string A, B; cin >> length >> A >> B; for(int i = 0; i < length; i++) { if(A[i] > B[i]) { cout << "-1\n"; return; } } const int NO_OF_ALPHABETS = 26; vector > replacements(NO_OF_ALPHABETS); for(int i = 0; i < length; i++) { if(A[i] != B[i]) { replacements[A[i] - 'a'].insert(B[i] - 'a'); } } int moves = 0; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(replacements[alpha].size() == 0) { continue; } moves++; auto it = replacements[alpha].begin(); int next_alpha = *it; for(it = replacements[alpha].begin(); it != replacements[alpha].end(); it++) { if(*it != next_alpha) { replacements[next_alpha].insert(*it); } } } cout << moves << "\n"; } ================================================ FILE: 2020/Div 2/659 Div 2/Programs/Common Prefixes.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int NO_OF_ALPHABETS = 25; vector S(no_of_elements + 5); for(int i = 1; i <= no_of_elements + 1; i++) { //S[i].resize(max ( max(A[i], 10), A[i - 1] ) ); for(int j = 0; j < A[i - 1]; j++) { S[i] += S[i - 1][j]; //cout << S[i][j] << "\n"; } if(i > no_of_elements) { if(S[i].size() == 0) { S[i] += (char)( 'a' + (i)%(NO_OF_ALPHABETS) ); } continue; } for(int j = A[i - 1]; j < max(A[i], 1); j++) {//cout << "Reached j = " << (char)('a' + (i)%(NO_OF_ALPHABETS) ) << endl; S[i] += (char)('a' + (i)%(NO_OF_ALPHABETS) ); } } for(int i = 1; i <= no_of_elements + 1; i++) { cout << S[i] << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/659 Div 2/Programs/Prefix Flip (Easy Version).cpp ================================================ #include #include using namespace std; void solve() { string A, B; int length; cin >> length >> A >> B; vector moves; for(int i = A.size() - 1; i >= 0; i--) { if(A[i] != B[i]) { moves.push_back(i + 1); moves.push_back(1); moves.push_back(i + 1); } } cout << moves.size() << " "; for(int i = 0; i < moves.size(); i++) { cout << moves[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/659 Div 2/Programs/Prefix Flip (Hard Version).cpp ================================================ #include #include using namespace std; void solve() { string A, B; int length; cin >> length >> A >> B; A += '0', B += '0'; vector moves_A, moves_B; for(int i = 1; i <= length; i++) { if(A[i] != A[i - 1]) { moves_A.push_back(i); } if(B[i] != B[i - 1]) { moves_B.push_back(i); } } cout << moves_A.size() + moves_B.size() << " "; for(int i = 0; i < moves_A.size(); i++) { cout << moves_A[i] << " "; } for(int i = moves_B.size() - 1; i >= 0; i--) { cout << moves_B[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/659 Div 2/Programs/String Transformation 1.cpp ================================================ #include #include #include using namespace std; void solve() { int length; string A, B; cin >> length >> A >> B; for(int i = 0; i < length; i++) { if(A[i] > B[i]) { cout << "-1\n"; return; } } const int NO_OF_ALPHABETS = 26; vector > replacements(NO_OF_ALPHABETS); for(int i = 0; i < length; i++) { if(A[i] != B[i]) { replacements[A[i] - 'a'].insert(B[i] - 'a'); } } int moves = 0; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(replacements[alpha].size() == 0) { continue; } moves++; auto it = replacements[alpha].begin(); int next_alpha = *it; for(it = replacements[alpha].begin(); it != replacements[alpha].end(); it++) { if(*it != next_alpha) { replacements[next_alpha].insert(*it); } } } cout << moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/660 Div 2/Explanations/Captain Flint and Crew Recruitment Explanation.txt ================================================ The smallest nearly prime integers are 6, 10, 14 So, we can give (6, 10, 14, n - 30) if n > 30 The only condition we have to be careful about is if n - 30 = 6, 10, 14 When n = 36, 40, 44 In these cases, we will need a different solution. We can use (6, 10, 15, n - 31) ----- void solve() { int n; cin >> n; if(n <= 30) { cout << "NO\n"; return; } cout << "YES\n"; switch(n) { case 36 : case 40 : case 44 : cout << "6 10 15 " << n - 31 << "\n"; return; default : cout << "6 10 14 " << n - 30 << "\n"; } } ================================================ FILE: 2020/Div 2/660 Div 2/Explanations/Captain Flint and a Long Voyage Explanation.txt ================================================ First of all, we want the length of the binary number to be maximum possible. So, we will use a 4 digit number. If the digit is deleted, then we cannot distinguish between 8 and 9. As they have asked for the smallest such answer if there are multiple, we will print 8 After all the deletions are over, we will print all 9's to make the integer as large as possible ----- void solve() { int n; cin >> n; int eights = n/4 + (n%4 != 0); int nines = n - eights; for(int i = 1; i <= nines; i++) { cout << "9"; } for(int i = 1; i <= eights; i++) { cout << "8"; } cout << "\n"; } ================================================ FILE: 2020/Div 2/660 Div 2/Programs/Captain Flint and Crew Recruitment.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; if(n <= 30) { cout << "NO\n"; return; } cout << "YES\n"; switch(n) { case 36 : case 40 : case 44 : cout << "6 10 15 " << n - 31 << "\n"; return; default : cout << "6 10 14 " << n - 30 << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/660 Div 2/Programs/Captain Flint and a Long Voyage.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; int eights = n/4 + (n%4 != 0); int nines = n - eights; for(int i = 1; i <= nines; i++) { cout << "9"; } for(int i = 1; i <= eights; i++) { cout << "8"; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/662 Div 2/Programs/Rainbow Dash, Fluttershy and Chess Coloring.cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; int no_of_moves = n/2 + 1; cout << no_of_moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Explanations/Bandit in a City Explanation.txt ================================================ The answer for a given node is maximum of the value of any leaf in it's subtree or ceil(sum[v], leaves[v]) ----- - If we are at a leaf, then the answer is equal to the value of the leaf. - Suppose we are at a vertex, all of who’s children are leaves 🍁 - If the subtree sum is $S[v]$, and the number of leaves is $l[v]$, at least one leaf has to have $S[v]/l[v]$ by the PigeonHole Principle. - However, if some leaf already has a greater amount, then we cannot change it. - When we reach $v$, if every leaf has a smaller amount than $S[V]/l[v]$, then we can achieve $S[v]/l[v]$ by distributing in the required way. - $M[v] = \max(M[c], S[v]/l[v])$ is the answer. - We can apply this logic recursively. For every vertex $v$ that we visit, we already know the values of $M, S, l$ for all it's children. If every single leaf in it's subtree has weight $< S[v]/l[v]$, we can achieve it. Otherwise, we leave the maximum undisturbed and distribute into the other leaves. - Please note that it is always possible to distribute into the other leafs and ensure that the maximum does not exceed $M[v]$ if $M[v] > S[v]/L[v]$. The reason is that if $M[v]$ is greater than this, at least one leaf has to be smaller than this value. ----- long long ceil(long long n, long long d) { return (n/d) + (n%d != 0 ? 1 : 0); } void dfs(int v) { sum[v] = A[v]; if(tree[v].size() == 0) { leaves[v] = 1; maximum[v] = sum[v]; return; } for(int child_v : tree[v]) { dfs(child_v); leaves[v] += leaves[child_v]; sum[v] += sum[child_v]; maximum[v] = max(maximum[v], maximum[child_v]); } maximum[v] = max(maximum[v], ceil(sum[v], leaves[v])); } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 2; i <= no_of_vertices; i++) { int source; cin >> source; tree[source].push_back(i); } for(int i = 1; i <= no_of_vertices; i++) { cin >> A[i]; leaves[i] = 0; maximum[i] = 0; } dfs(1); cout << maximum[1] << "\n"; return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Explanations/Binary Search Explanation.txt ================================================ We will simulate binary search and count the number of indices which need to have a larger and smaller element. There are (N - X) larger elements and they can be placed in P(N - X, L) ways. There are (X - 1) smaller elementss and they can be placed in P(X - 1, S) ways. The remaining R elements can be placed anywhere. ----- #include using namespace std; const int MOD = 1e9 +7; long long power_mod(long long x, long long power) { if(power < 0) { return 0; } long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } long long inverse(long long n) { return power_mod(n, MOD - 2); } long long factorial(long long n) { long long answer = 1; for(int i = 2; i <= n; i++) { answer = (answer*i)%MOD; } return answer; } long long choose(long long n, long long r) { if(r > n) { return 0; } long long denominator = factorial(n - r); return (factorial(n)*inverse(denominator))%MOD; } int main() { int no_of_elements, x, position; cin >> no_of_elements >> x >> position; int larger = 0, smaller = 0; int left = 0, right = no_of_elements; while(left < right) { int mid = (left + right)/2; if(mid <= position) { left = mid + 1; smaller++; } else { right = mid; larger++; } } long long result = (choose(no_of_elements - x, larger)*choose(x - 1, smaller - 1))%MOD; int remaining = no_of_elements - (larger + smaller); result = (result*factorial(remaining))%MOD; cout << result << "\n"; return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Explanations/Complicated Computations Explanation.txt ================================================ We are looking for the smallest integer which is not a MEX in any subarray Given an integer X, how do we check which subarrays it is a MEX in ? It turns out that if there is any subarray in which x is a MEX, a subarray between consecutive occurrences of x will also satisfy this property. Suppose MEX[L, R] = X Then, MEX[L - 1, R] or MEX[L, R + 1] will also be X as long as A[L - 1] =/= X and A[R + 1] =/= X X can only be a MEX in some subarray that does not contain it. ----- For each X, we will check the following segments - 1. The subarray between consecutive occurrences of X 2. The prefix subarray before the first occurrence of X 3. The suffix subarray after the last occurrence of X We don't need to handle the last case seperately since last[x] = 0, for all x in the beginning. We will also need to find out the MEX of the entire array. ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map last; vector is_mex(no_of_elements + 10, false); for(int i = 1; i <= no_of_elements; i++) { if(last[A[i]] + 1 != i) { int mex_here = get_first_smaller(1, 1, MAX_N, last[A[i]] + 1); //cout << "Mex[" << last[A[i]] + 1 << "," << i - 1 << "] = " << mex_here << "\n"; is_mex[mex_here] = true; } last[A[i]] = i; update(1, 1, MAX_N, A[i], i); } for(int i = 1; i <= no_of_elements; i++) { if(last[A[i]] != no_of_elements) { int suffix_mex = get_first_smaller(1, 1, MAX_N, last[A[i]] + 1); //cout << "Suffix Mex[" << last[A[i]] + 1 << "," << no_of_elements << "] = " << suffix_mex << "\n"; is_mex[suffix_mex] = true; } } int array_mex = get_first_smaller(1, 1, MAX_N, 1); is_mex[array_mex] = true; //cout << "Array Mex = " << array_mex << "\n"; int final_mex = 0; for(int i = 1; i < is_mex.size(); i++) { if(!is_mex[i]) { final_mex = i; break; } } cout << final_mex << "\n"; return 0; } ----- How do we find out the MEX of a segment [L, R] ? 1. Let us maintain an array last, which contains the last occurrence of x 2. Let us suppose we have processed all elements from [1, R] and know their last occurrence 3. We are looking for the first index i, such that last[i] < L This means that i does not occur in the segment [L, R] and is the smallest integer which satisfies this property and is therefore the MEX. We can get the first element in last which is < L in O(log n) time using a minimum segment tree like this ----- int get_first_smaller(int n, int left, int right, int x) { if(min_tree[n] > x) { return -1; } if(left == right) { return left; } int mid = (left + right)/2; if(min_tree[LEFT(n)] < x) { return get_first_smaller(LEFT(n), left, mid, x); } return get_first_smaller(RIGHT(n), mid + 1, right, x); } ----- ================================================ FILE: 2020/Div 2/678 Div 2/Explanations/Prime Square Explanation.txt ================================================ 1 + 4 = 5 is a prime number. So, I put exactly one 1 and one 4 in every row and column and padded the remaining with 0s The editorial solution was even more slick. It used 1 + 1 = 2 and just padded with 1s ----- void solve() { int n; cin >> n; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(i == j) { cout << "1 "; } else if(j == (i + 1) || (i == n && j == 1)) { cout << "4 "; } else { cout << "0 "; } } cout << "\n"; } } ================================================ FILE: 2020/Div 2/678 Div 2/Explanations/Reorder Explanation.txt ================================================ A[i]/i is counted i times, so we are actually counting i(A[i]/i) = A[i] The question is asking if the sum of the array is equal to m ! It's quite beautiful ----- void solve() { int no_of_elements, target_sum; cin >> no_of_elements >> target_sum; int sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; sum += A[i]; } cout << (sum == target_sum ? "YES" : "NO") << "\n"; } ================================================ FILE: 2020/Div 2/678 Div 2/Explanations/Sum Over Subsets Explanation.txt ================================================ Thank you for the success, safety, peace and love. ================================================ FILE: 2020/Div 2/678 Div 2/Programs/Bandit in a City.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 5; long long leaves[MAX_N], maximum[MAX_N], sum[MAX_N], A[MAX_N]; vector tree[MAX_N]; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0 ? 1 : 0); } void dfs(int v) { sum[v] = A[v]; if(tree[v].size() == 0) { leaves[v] = 1; maximum[v] = sum[v]; return; } for(int child_v : tree[v]) { dfs(child_v); leaves[v] += leaves[child_v]; sum[v] += sum[child_v]; maximum[v] = max(maximum[v], maximum[child_v]); } maximum[v] = max(maximum[v], ceil(sum[v], leaves[v])); } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 2; i <= no_of_vertices; i++) { int source; cin >> source; tree[source].push_back(i); } for(int i = 1; i <= no_of_vertices; i++) { cin >> A[i]; leaves[i] = 0; maximum[i] = 0; } dfs(1); cout << maximum[1] << "\n"; return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Programs/Binary Search.cpp ================================================ #include using namespace std; const int MOD = 1e9 +7; long long power_mod(long long x, long long power) { if(power < 0) { return 0; } long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } long long inverse(long long n) { return power_mod(n, MOD - 2); } long long factorial(long long n) { long long answer = 1; for(int i = 2; i <= n; i++) { answer = (answer*i)%MOD; } return answer; } long long choose(long long n, long long r) { if(r > n) { return 0; } long long denominator = factorial(n - r); return (factorial(n)*inverse(denominator))%MOD; } int main() { int no_of_elements, x, position; cin >> no_of_elements >> x >> position; int larger = 0, smaller = 0; int left = 0, right = no_of_elements; while(left < right) { int mid = (left + right)/2; if(mid <= position) { left = mid + 1; smaller++; } else { right = mid; larger++; } } long long result = (choose(no_of_elements - x, larger)*choose(x - 1, smaller - 1))%MOD; int remaining = no_of_elements - (larger + smaller); result = (result*factorial(remaining))%MOD; cout << result << "\n"; return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Programs/Complicated Computations.cpp ================================================ #include #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; const int MAX_N = 1e5 + 5; vector min_tree(3*MAX_N + 5, 0); void update(int n, int left, int right, int position, int value) { if(right < position || position < left) { return; } if(left == right) { min_tree[n] = value; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); min_tree[n] = min(min_tree[LEFT(n)], min_tree[RIGHT(n)]); } int get_first_smaller(int n, int left, int right, int x) { if(min_tree[n] > x) { return -1; } if(left == right) { return left; } int mid = (left + right)/2; if(min_tree[LEFT(n)] < x) { return get_first_smaller(LEFT(n), left, mid, x); } return get_first_smaller(RIGHT(n), mid + 1, right, x); } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map last; vector is_mex(no_of_elements + 10, false); for(int i = 1; i <= no_of_elements; i++) { if(last[A[i]] + 1 != i) { int mex_here = get_first_smaller(1, 1, MAX_N, last[A[i]] + 1); //cout << "Mex[" << last[A[i]] + 1 << "," << i - 1 << "] = " << mex_here << "\n"; is_mex[mex_here] = true; } last[A[i]] = i; update(1, 1, MAX_N, A[i], i); } for(int i = 1; i <= no_of_elements; i++) { if(last[A[i]] != no_of_elements) { int suffix_mex = get_first_smaller(1, 1, MAX_N, last[A[i]] + 1); //cout << "Suffix Mex[" << last[A[i]] + 1 << "," << no_of_elements << "] = " << suffix_mex << "\n"; is_mex[suffix_mex] = true; } } int array_mex = get_first_smaller(1, 1, MAX_N, 1); is_mex[array_mex] = true; //cout << "Array Mex = " << array_mex << "\n"; int final_mex = 0; for(int i = 1; i < is_mex.size(); i++) { if(!is_mex[i]) { final_mex = i; break; } } cout << final_mex << "\n"; return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Programs/Prime Square.cpp ================================================ #include #include using namespace std; void solve() { int n; cin >> n; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(i == j) { cout << "1 "; } else if(j == (i + 1) || (i == n && j == 1)) { cout << "4 "; } else { cout << "0 "; } } cout << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Programs/Reorder.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, target_sum; cin >> no_of_elements >> target_sum; int sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; sum += A[i]; } cout << (sum == target_sum ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/678 Div 2/Programs/Sum Over Subsets.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e5 + 5, MOD = 998244353; vector mu(MAX_N, 1); vector A(MAX_N); map frequency; long long square(long long n) { return (n*n)%MOD; } long long power_mod(long long x, long long power) { long long result = 1; while(power > 0) { if(power%2) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } void precompute() { vector is_prime(MAX_N + 1, true); is_prime[1] = is_prime[0] = false; mu[1] = 1; for(int i = 2; i < MAX_N; i++) { if(!is_prime[i]) { continue; } for(int multiple = i; multiple < MAX_N; multiple += i) { mu[multiple] *= -1; is_prime[multiple] = false; } for(long long square = i*1LL*i; square < MAX_N; square += i*1LL*i) { mu[square] = 0; } } } long long count_with_gcd(int x) { long long square_sum = 0, pairwise_sum = 0, sum = 0, total = 0; for(int i = x; i < MAX_N; i += x) { square_sum += ( square(i)*frequency[i] )%MOD; square_sum %= MOD; sum += (i*frequency[i])%MOD; sum %= MOD; total += frequency[i]; } pairwise_sum = (sum*sum - square_sum + MOD)%MOD; long long answer = 0; if(total >= 2) { //cout << " Squares = " << square_sum << " Pairs = " << pairwise_sum << "\n"; long long t_minus_1 = (total + MOD - 1)%MOD, t_minus_2 = (total + MOD - 2)%MOD; long long same_term = ((t_minus_1)*power_mod(2, total - 2))%MOD; same_term = (same_term*square_sum)%MOD; long long different_term = power_mod(2, total - 2); if(total >= 3) { different_term += (power_mod(2, total - 3)*t_minus_2)%MOD; different_term %= MOD; } //cout << "Multiplier = " << different_term << "\n"; different_term = (different_term*pairwise_sum)%MOD; //cout << "Answer for x = " << x << " = " << same_term << " + " << different_term; answer = (same_term + different_term)%MOD; //cout << " = " << answer << "\n"; } return answer; } int main() { int no_of_elements; cin >> no_of_elements; precompute(); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; cin >> frequency[A[i]]; } long long answer = 0; for(int i = 1; i < MAX_N; i++) { answer += mu[i]*count_with_gcd(i); answer = (answer + MOD)%MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/684 Div 2/Explanations/Binary Table Explanation.txt ================================================ If there are an odd number of rows or odd number of columns, we will handle the last odd row and last odd column seperately. We will do this greedily. If two consecutive elements of a row or column are 1, we will flip a L that involves both of them. Otherwise, we will flip an L that involves only one of them. I have written various helper functions to do this. Note - When both rows and columns are odd While making a flip operation on the last column, avoid performing an operation that would flip an element of the last row. The reason is we have already flipped the last row first and the last row should contain all 0s. ----- Now, we have a NxM matrix where both N and M are even. Divide the matrix in 2x2 squares and solve each 2x2 square seperately. There are basically $4$ cases - The square can have $\{1, 2, 3, 4\}$ ones. Each case should be handled differently I came up with an elegant implementation. Instead of writing separate code for each of the $4$ cases, I reduced each case to another case. 1. If it has 4 ones, flip and make it have 1 one. 2. If it has 1 one, flip and make it have 2 ones. 3. If it has 2 ones, flip and make it have 3 ones. 4. If it has 3 ones, flip and make it have 0 ones. Every 2x2 square takes at most 4 operations. ----- void get(vector > &M, vector > &op, vector > &S) { int one_count = 0; for(int i = 0; i < S.size(); i++) { one_count += (M[S[i].first][S[i].second] == 1); } switch(one_count) { case 4 : solve_4(M, op, S); case 1 : solve_1(M, op, S); case 2 : solve_2(M, op, S); case 3 : solve_3(M, op, S); } } ----- How do we convert a matrix with 4 ones to 1 one ? Flip any arbitrary L void solve_4(vector > &M, vector > &op, vector > &S) { for(int i = 0; i < 3; i++) { perform(M, op, S[i]); } } ------ How do we convert a matrix with 1 one to 2 ones ? Flip any L containing the 1 void solve_1(vector > &M, vector > &op, vector > &S) { int r_1, c_1; for(int i = 0; i < S.size(); i++) { if(M[S[i].first][S[i].second] == 1) { r_1 = S[i].first; c_1 = S[i].second; } } for(int i = 0; i < S.size(); i++) { if(S[i].first == r_1 || S[i].second == c_1) { perform(M, op, S[i]); } } } ----- How do we convert a matrix with 2 ones to 3 ones ? Flip a L that contains one of the 1's void solve_2(vector > &M, vector > &op, vector > &S) { int frequency_1 = 0; for(int i = 0; i < S.size(); i++) { if(M[S[i].first][S[i].second] == 1) { if(frequency_1 == 0) { perform(M, op, S[i]); } frequency_1++; } else { perform(M, op, S[i]); } } } ------ How do we convert a matrix with 3 1's to a matrix with 0 1's ? Flip the 3 1's void solve_3(vector > &M, vector > &op, vector > &S) { for(int i = 0; i < S.size(); i++) { if(M[S[i].first][S[i].second] == 1) { perform(M, op, S[i]); } } } ------ ================================================ FILE: 2020/Div 2/684 Div 2/Explanations/Buy the String Explanation.txt ================================================ If (h + cost[0] < cost[1]), we will convert all the 1's to 0's If (h + cost[1] < cost[0]), we will convert all the 0's to 1's Otherwise, we will not do a single change. Please note that it is not possible for both of these conditions to be true at the same time It would imply 2h < 0 ----- void solve() { int length, cost[2], change; string S; cin >> length >> cost[0] >> cost[1] >> change >> S; int answer = 0; for(int i = 0; i < S.size(); i++) { if(change + cost[0] < cost[1]) { if(S[i] == '1') { answer += change; } answer += cost[0]; } else if(change + cost[1] < cost[0]) { if(S[i] == '0') { answer += change; } answer += cost[1]; } else if(change >= max(cost[0] - cost[1], cost[1] - cost[0])) { answer += cost[S[i] - '0']; } } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/684 Div 2/Explanations/Graph Subset Problem Explanation.txt ================================================ Let us process the vertices in ascending order of their degree. Let d(v) be the degree of the smallest vertex. If d(v) < k - 1, then v is not part of any clique or good subset. So, we can delete v from the graph along with all it's edges. If d(v) = k - 1, then it is possible that v and all it's edges are part of a clique. We will check this set of k vertices to check if every pair of vertices is connected. This takes O(k^2) time. If d(v) >= k, then all the remaining vertices have at least k neighbours. This means that the remaining vertices form a good subset so we can just print the subset. ----- In order to support deletion of vertices quickly, we will store the graph in an Adjacency set. vector > did not clear the time limit. So, use vector < unordered_set > ----- Let us notice that a clique has k(k - 1)/2 edges. And a good subset has at least k^2 edges. This means that 2m >= root(k) approximately. So, if m = 2 x 10^5, k can be around 600. Since the value of k in which the answer exists is small, we can afford to do brute force. Every time we check a clique candidate, we eliminate (k - 1) edges. So, we can check at most (M/K - 1) candidates. So, the time complexity of this is O(M/K)O(K^2) = O(M K) ----- void solve() { int no_of_vertices, no_of_edges, k; cin >> no_of_vertices >> no_of_edges >> k; vector > graph(no_of_vertices + 1); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].insert(v); graph[v].insert(u); } vector is_active(no_of_vertices + 1, true); set > degree; for(int i = 1; i <= no_of_vertices; i++) { degree.insert(make_pair(graph[i].size(), i)); } int subset_found = false, clique = false; for(set > :: iterator it = degree.begin(); degree.size() > 0; ) { it = degree.begin(); if( (*it).first >= k ) { subset_found = true; break; } if( (*it).first == k - 1 && 2LL*no_of_edges >= k*1LL*(k - 1)) { clique = (*it).second; vector current_candidates; current_candidates.push_back(clique); for(unordered_set :: iterator it_1 = graph[clique].begin(); clique && it_1 != graph[clique].end(); it_1++) { current_candidates.push_back(*it_1); } for(int i = 0; i < current_candidates.size() && clique != false; i++) { for(int j = i + 1; j < current_candidates.size(); j++) { if(graph[current_candidates[i]].count(current_candidates[j]) == 0) { clique = false; break; } } } if(clique) { break; } } int v = (*it).second; for(unordered_set :: iterator it = graph[v].begin(); it != graph[v].end(); it++) { int u = *it; degree.erase(make_pair(graph[u].size(), u)); graph[u].erase(v); degree.insert(make_pair(graph[u].size(), u)); } no_of_edges -= (*it).first; degree.erase(it); } if(subset_found) { cout << "1 " << degree.size() << "\n"; for(set > :: iterator it = degree.begin(); it != degree.end(); it++) { cout << (*it).second << " "; } cout << "\n"; return; } if(clique) { cout << "2\n"; cout << clique << " "; for(unordered_set :: iterator it = graph[clique].begin(); it != graph[clique].end(); it++) { cout << (*it) << " "; } cout << "\n"; return; } cout << "-1\n"; } ================================================ FILE: 2020/Div 2/684 Div 2/Explanations/Greedy Shopping Explanation.txt ================================================ The array is sorted in non-increasing order. This is important because it allows us to use a Minimum Segment Tree built over A. Let us see how we can simulate the process. We will start at 1 and then traverse the tree. If the current node's range is completely outside the range we are looking at, discard it. If the current node's minimum is > M, then we cannot buy a single element here, so discard it. If these two conditions are not satisfied, then it means there is at least 1 element here which we can buy. If the current node is completely within the range and the sum < M, buy everything in the range. Otherwise, go to the left child and then the right child. This ensures we are visiting the array elements in left-to-right order. The sorting helps us use the Minimum Segment Tree ----- { propagate(n, left, right); if(right < query_left || query_right < left) { //cout << "Outside range\n"; return; } //cout << "In "<< n << " [" << left << "," << right << "]\n"; if(tree[n].minimum > M) { //cout << "Minimum = " << tree[n].minimum << " > " << M << "\n"; return; } if(query_left <= left && right <= query_right && tree[n].sum <= M) { M -= tree[n].sum; //cout << "Sum = " << tree[n].sum << "\n"; C += (right - left + 1); //cout << "Completely within Range and now " << M << "\n"; return; } int mid = (left + right)/2; //cout << "Breaking into Left with " << M << "\n"; go_right(LEFT(n), left, mid, query_left, query_right, M, C); //cout << "Breaking into right with " << M << "\n"; go_right(RIGHT(n), mid + 1, right, query_left, query_right, M, C); } ----- Be careful while doing lazy propagation. I had 2 mistakes - 1. I was propagating even when lazy[n] = 0 2. I was adding lazy[n] to it's children, when I should be assigning. Adding affects the sum and the minimum. Do not propagate if you are at a leaf node. I avoided this mistake, but it is a common one. ----- struct node { long long sum, minimum, maximum, lazy; node() { sum = 0; lazy = 0; } node(long long S, long long Min, long long Max) { sum = S; minimum = Min; maximum = Max; lazy = 0; } }; node merge(node &L, node &R) { return node(L.sum + R.sum, min(L.minimum, R.minimum), max(L.maximum, R.maximum)); } const int MAX_N = 2e5 + 5, oo = 1e9; node tree[3*MAX_N]; void propagate(int n, int left, int right) { if(tree[n].lazy == 0) { return; } tree[n].maximum = tree[n].lazy; tree[n].minimum = tree[n].lazy; tree[n].sum = (right - left + 1)*tree[n].lazy; if(left != right) { tree[LEFT(n)].lazy = tree[n].lazy; tree[RIGHT(n)].lazy = tree[n].lazy; } tree[n].lazy = 0; } ----- For the update operation, we have to update some suffix of the prefix since A is sorted. So, we will look for the first integer < y and then update everything in [i, x] int find_first(int n, int left, int right, int x) { propagate(n, left, right); if(tree[n].minimum >= x) { return oo; } if(left == right) { return right; } int mid = (left + right)/2; if(tree[LEFT(n)].minimum < x) { return find_first(LEFT(n), left, mid, x); } return find_first(RIGHT(n), mid + 1, right, x); } ----- ================================================ FILE: 2020/Div 2/684 Div 2/Explanations/Sum of Medians Explanation.txt ================================================ We will be greedy and try to put the largest possible elements in the medians. Let us sort the array in descending order. Suppose the array length is n. Then the suffix length is (n/2). The first (n/2) elements cannot be a median of any array. The largest median possible is A[n/2 + 1]. Similarly, the largest value of the second median is A[n/2 + 1 + n/2 + 1]. And so on. We will choose all elements that are a multiple of (n/2 + 1). We can prove this by an exchange argument. Let us suppose we have k medians. We can take the largest median and replace it with A[n/2 + 1]. We cannot replace it with any larger integer since it requires (n/2) greater elements. The sum either remains the same or increases. After this, we can do the same with the second largest median after deleting the largest median and the first (n/2) and last (n/2) elements. Ultimately, we will be left with the medians that we have constructed. ------ void solve() { int no_of_elements, no_of_arrays; cin >> no_of_elements >> no_of_arrays; vector A(no_of_elements*no_of_arrays + 1); for(int i = 1; i <= no_of_elements*no_of_arrays; i++) { cin >> A[i]; } int median_position = (no_of_elements/2) + (no_of_elements%2); int suffix = no_of_elements - median_position; sort(all(A)); reverse(all(A)); long long answer = 0; for(int i = suffix + 1, medians = 0; medians < no_of_arrays; i += (suffix + 1)) { answer += A[i]; medians++; } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/684 Div 2/Programs/Binary Table.cpp ================================================ #include #include #include using namespace std; int flip(int x) { return (1 - x); } void perform(vector > &M, vector > &op, int i, int j) { op.push_back(make_pair(i, j)); M[i][j] = flip(M[i][j]); } void perform(vector > &M, vector > &op, pair P) { perform(M, op, P.first, P.second); } /*x x x*/ void flip_corner_L(vector > &M, vector > &op, int i, int j) { perform(M, op, i, j); perform(M, op, i - 1, j); perform(M, op, i - 1, j - 1); } /*x x x*/ void flip_down_corner_L(vector > &M, vector > &op, int i, int j) { perform(M, op, i, j); perform(M, op, i + 1, j); perform(M, op, i, j - 1); } /* x x x */ void flip_down_L(vector > &M, vector > &op, int i, int j) { perform(M, op, i, j); perform(M, op, i, j + 1); perform(M, op, i - 1, j); } /* x x x */ void flip_down_back_L(vector > &M, vector > &op, int i, int j) { perform(M, op, i, j); perform(M, op, i, j - 1); perform(M, op, i - 1, j - 1); } /*x x x */ void flip_up_L(vector > &M, vector > &op, int i, int j) { perform(M, op, i, j); perform(M, op, i - 1, j); perform(M, op, i - 1, j + 1); } /*x x x */ void flip_down_up_L(vector > &M, vector > &op, int i, int j) { perform(M, op, i, j); perform(M, op, i, j - 1); if(i == 1) { perform(M, op, i + 1, j - 1); } else { perform(M, op, i - 1, j - 1); } } void solve_3(vector > &M, vector > &op, vector > &S) { for(int i = 0; i < S.size(); i++) { if(M[S[i].first][S[i].second] == 1) { perform(M, op, S[i]); } } } void solve_2(vector > &M, vector > &op, vector > &S) { int frequency_1 = 0; for(int i = 0; i < S.size(); i++) { if(M[S[i].first][S[i].second] == 1) { if(frequency_1 == 0) { perform(M, op, S[i]); } frequency_1++; } else { perform(M, op, S[i]); } } } void solve_1(vector > &M, vector > &op, vector > &S) { int r_1, c_1; for(int i = 0; i < S.size(); i++) { if(M[S[i].first][S[i].second] == 1) { r_1 = S[i].first; c_1 = S[i].second; } } for(int i = 0; i < S.size(); i++) { if(S[i].first == r_1 || S[i].second == c_1) { perform(M, op, S[i]); } } } void solve_4(vector > &M, vector > &op, vector > &S) { for(int i = 0; i < 3; i++) { perform(M, op, S[i]); } } void get(vector > &M, vector > &op, vector > &S) { int one_count = 0; for(int i = 0; i < S.size(); i++) { one_count += (M[S[i].first][S[i].second] == 1); } switch(one_count) { case 4 : solve_4(M, op, S); case 1 : solve_1(M, op, S); case 2 : solve_2(M, op, S); case 3 : solve_3(M, op, S); } } void solve() { int rows, columns; scanf("%d %d", &rows, &columns); vector > M(rows + 1, vector (columns + 1)); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { scanf("%1d", &M[i][j]); //printf("%d\n", M[i][j]); } } vector > operations; if(rows%2 == 1) { for(int j = 1; j <= columns; j++) { if(M[rows][j] == 1) { if(j == columns) { flip_corner_L(M, operations, rows, j); } else if(M[rows][j + 1] == 1) { flip_down_L(M, operations, rows, j); } else { flip_up_L(M, operations, rows, j); } } } } if(columns%2 == 1) { for(int i = 1; i <= rows; i++) { if(M[i][columns] == 1) { if(i == rows) { flip_down_back_L(M, operations, i, columns); } else if(M[i + 1][columns] == 1) { flip_down_corner_L(M, operations, i, columns); } else { flip_down_up_L(M, operations, i, columns); } } } } for(int i = 1; i + 1 <= rows; i += 2) { for(int j = 1; j + 1 <= columns; j += 2) { vector > squares; int next_r = i + 1, next_c = j + 1; squares.push_back(make_pair(i, j)); squares.push_back(make_pair(i + 1, j)); squares.push_back(make_pair(i, j + 1)); squares.push_back(make_pair(i + 1, j + 1)); get(M, operations, squares); } } printf("%d\n", operations.size()/3); for(int i = 0; i < operations.size(); i++) { printf("%d %d ", operations[i].first, operations[i].second); if((i + 1)%3 == 0) { printf("\n"); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/684 Div 2/Programs/Buy the String.cpp ================================================ #include using namespace std; void solve() { int length, cost[2], change; string S; cin >> length >> cost[0] >> cost[1] >> change >> S; int answer = 0; for(int i = 0; i < S.size(); i++) { if(change + cost[0] < cost[1]) { if(S[i] == '1') { answer += change; } answer += cost[0]; } else if(change + cost[1] < cost[0]) { if(S[i] == '0') { answer += change; } answer += cost[1]; } else if(change >= max(cost[0] - cost[1], cost[1] - cost[0])) { answer += cost[S[i] - '0']; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/684 Div 2/Programs/Graph Subset Problem.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_vertices, no_of_edges, k; cin >> no_of_vertices >> no_of_edges >> k; vector > graph(no_of_vertices + 1); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].insert(v); graph[v].insert(u); } vector is_active(no_of_vertices + 1, true); set > degree; for(int i = 1; i <= no_of_vertices; i++) { degree.insert(make_pair(graph[i].size(), i)); } int subset_found = false, clique = false; for(set > :: iterator it = degree.begin(); degree.size() > 0; ) { it = degree.begin(); if( (*it).first >= k ) { subset_found = true; break; } if( (*it).first == k - 1 && 2LL*no_of_edges >= k*1LL*(k - 1)) { clique = (*it).second; vector current_candidates; current_candidates.push_back(clique); for(unordered_set :: iterator it_1 = graph[clique].begin(); clique && it_1 != graph[clique].end(); it_1++) { current_candidates.push_back(*it_1); } for(int i = 0; i < current_candidates.size() && clique != false; i++) { for(int j = i + 1; j < current_candidates.size(); j++) { if(graph[current_candidates[i]].count(current_candidates[j]) == 0) { clique = false; break; } } } if(clique) { break; } } int v = (*it).second; for(unordered_set :: iterator it = graph[v].begin(); it != graph[v].end(); it++) { int u = *it; degree.erase(make_pair(graph[u].size(), u)); graph[u].erase(v); degree.insert(make_pair(graph[u].size(), u)); } no_of_edges -= (*it).first; degree.erase(it); } if(subset_found) { cout << "1 " << degree.size() << "\n"; for(set > :: iterator it = degree.begin(); it != degree.end(); it++) { cout << (*it).second << " "; } cout << "\n"; return; } if(clique) { cout << "2\n"; cout << clique << " "; for(unordered_set :: iterator it = graph[clique].begin(); it != graph[clique].end(); it++) { cout << (*it) << " "; } cout << "\n"; return; } cout << "-1\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/684 Div 2/Programs/Greedy Shopping.cpp ================================================ #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; struct node { long long sum, minimum, maximum, lazy; node() { sum = 0; lazy = 0; } node(long long S, long long Min, long long Max) { sum = S; minimum = Min; maximum = Max; lazy = 0; } }; node merge(node &L, node &R) { return node(L.sum + R.sum, min(L.minimum, R.minimum), max(L.maximum, R.maximum)); } const int MAX_N = 2e5 + 5, oo = 1e9; node tree[3*MAX_N]; void propagate(int n, int left, int right) { if(tree[n].lazy == 0) { return; } tree[n].maximum = tree[n].lazy; tree[n].minimum = tree[n].lazy; tree[n].sum = (right - left + 1)*tree[n].lazy; if(left != right) { tree[LEFT(n)].lazy = tree[n].lazy; tree[RIGHT(n)].lazy = tree[n].lazy; } tree[n].lazy = 0; } void update(int n, int left, int right, int query_left, int query_right, long long x) { propagate(n, left, right); if(right < left || query_right < query_left || query_right < left || right < query_left) { return; } if(query_left <= left && right <= query_right) { //cout << " Updating [" << left << "," << right << "] = " << x; tree[n].lazy = x; propagate(n, left, right); //cout << " Sum = " << tree[n].sum << "\n"; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, query_left, query_right, x); update(RIGHT(n), mid + 1, right, query_left, query_right, x); tree[n] = merge(tree[LEFT(n)], tree[RIGHT(n)]); } int find_first(int n, int left, int right, int x) { propagate(n, left, right); if(tree[n].minimum >= x) { return oo; } if(left == right) { return right; } int mid = (left + right)/2; if(tree[LEFT(n)].minimum < x) { return find_first(LEFT(n), left, mid, x); } return find_first(RIGHT(n), mid + 1, right, x); } void go_right(int n, int left, int right, int query_left, int query_right, int &M, int &C) { propagate(n, left, right); if(right < query_left || query_right < left) { //cout << "Outside range\n"; return; } //cout << "In "<< n << " [" << left << "," << right << "]\n"; if(tree[n].minimum > M) { //cout << "Minimum = " << tree[n].minimum << " > " << M << "\n"; return; } if(query_left <= left && right <= query_right && tree[n].sum <= M) { M -= tree[n].sum; //cout << "Sum = " << tree[n].sum << "\n"; C += (right - left + 1); //cout << "Completely within Range and now " << M << "\n"; return; } int mid = (left + right)/2; //cout << "Breaking into Left with " << M << "\n"; go_right(LEFT(n), left, mid, query_left, query_right, M, C); //cout << "Breaking into right with " << M << "\n"; go_right(RIGHT(n), mid + 1, right, query_left, query_right, M, C); } int main() { int no_of_elements, no_of_queries; cin >> no_of_elements >> no_of_queries; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; update(1, 1, no_of_elements, i, i, x); } for(int i = 1; i <= no_of_queries; i++) { int type, x, y; cin >> type >> x >> y; const int UPDATE = 1, QUERY = 2; switch(type) { case UPDATE : { int prefix = x, value = y; int i = find_first(1, 1, no_of_elements, value); //cout << "First < " << value << " is " << i << "\n"; update(1, 1, no_of_elements, i, prefix, value); break; } case QUERY : { int money = y, start = x; int visit_count = 0; go_right(1, 1, no_of_elements, start, no_of_elements, money, visit_count); cout << visit_count << "\n"; } } } return 0; } ================================================ FILE: 2020/Div 2/684 Div 2/Programs/Sum of Medians.cpp ================================================ #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; void solve() { int no_of_elements, no_of_arrays; cin >> no_of_elements >> no_of_arrays; vector A(no_of_elements*no_of_arrays + 1); for(int i = 1; i <= no_of_elements*no_of_arrays; i++) { cin >> A[i]; } int median_position = (no_of_elements/2) + (no_of_elements%2); int suffix = no_of_elements - median_position; sort(all(A)); reverse(all(A)); long long answer = 0; for(int i = suffix + 1, medians = 0; medians < no_of_arrays; i += (suffix + 1)) { answer += A[i]; medians++; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Explanations/Bitwise Queries Explanation.txt ================================================ Here is the main idea of the problem - 1. We will find 1 element. 2. We will use that element to determine the rest of the array. ----- How do we find out 1 element ? And how do we use it to find the remaining ? Firstly, we will keep XOR[i] = XOR(A[1], A[i]), for all i If we know A[1], then A[i] = XOR(A[1], XOR[i]) XOR is the best operation for recovering the original elements because OR and AND lose bits. In general, the symmetry offered by XOR is always the best for such problems. We will use the following identity - a + b = XOR(a, b) + 2AND(a, b) The reason is - 1. When both a, b have a 0 at a bit, XOR is also 0 and addition is also 0 2. When one has a 1, XOR and addition both give 1 3. When both have a 1, XOR contributes 0 and addition contributes 2x2^i So, in order to complete addition, we need to add double of all the bits that are set in both a and b This is AND(a, b) ! ------ We will find out the sums of A[1] + A[2] = S[12] A[2] + A[3] = S[23] A[3] + A[1] = S[31] This requires 6 queries and the remaining (n - 3) can be guessed with 1 query each. But, we can use the following idea to bring it down to 5 - XOR(A[2], A[3]) = XOR( XOR(A[1], A[2]), XOR(A[1], A[3]) ) This is enough for the Easy Version ------ Let us use the fact that all integer are in [0, n - 1] and that n is a power of 2. This means that either there is some integer that repeats twice or all integers in [0, n - 1] are present. If some integer is present twice, then XOR[i] = XOR[j]. We can use AND(i, j) to find out A[i] and use A[i] to find out A[1] A[1] can be used to find out the remaining array. This requires 1 + (n - 1) = n operations If every integer is present, it means every integer's binary complement occurs. This means that for every integer, there will be an integer such that their sum is (n - 1). This means that the XOR is (N - 1) and AND is 0. This save us a query. If XOR[i] = N - 1, then we will find out (A[1], A[i], A[j]) using the system of equations method we used. But we only need 4 queries instead of 5 since AND(A[1], A[i]) is known. ------ void ask(int i, int j, string operation, int &result) { cout << operation << " " << i << " " << j << "\n"; cout.flush(); cin >> result; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, -1); vector xor_1(no_of_elements + 1, 0); for(int i = 2; i <= no_of_elements; i++) { ask(1, i, "XOR", xor_1[i]); } int and_12 = -1, and_23 = -1, and_13 = -1; int xor_12 = -1 , xor_13 = -1, xor_23 = -1; int second = 0, third = 0; map last_xor_occurence; for(int i = 1; i <= no_of_elements; i++) { //All Elements Different, At least one pair XOR = n - 1, n = 2^p if(xor_1[i] == no_of_elements - 1) { second = i; third = (i == 2 ? 3 : 2); xor_12 = xor_1[second]; xor_13 = xor_1[third]; xor_23 = xor_1[second]^xor_1[third]; and_12 = 0; ask(second, third, "AND", and_23); ask(1, third, "AND", and_13); break; } //Two Equal Elements if(last_xor_occurence[xor_1[i]] != 0) { ask(last_xor_occurence[xor_1[i]], i, "AND", A[i]); A[1] = A[i]^xor_1[i]; break; } last_xor_occurence[xor_1[i]] = i; } if(second != 0 && third != 0) { int sum_12 = xor_12 + 2*and_12; int sum_23 = xor_23 + 2*and_23; int sum_13 = xor_13 + 2*and_13; A[1] = (sum_12 - sum_23 + sum_13)/2; } for(int i = 2; i <= no_of_elements; i++) { A[i] = A[1]^xor_1[i]; } cout << "! "; for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; cout.flush(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Explanations/Circle Game Explanation.txt ================================================ Let us look at the line x = y. Suppose the furthest points in the line x = y inside the circle is (kz, kz) Let (k(z + 1), kz) be outside the circle of radius d. Then, the second person will always win. No matter what the first player does, the second player can always ensure that the coin remains on the line (x = y). It will be the first player who moves out of the circle. ----- If (k(z + 1), kz)) is inside the circle, then after the first player makes a move, the first player is in the same position the second player was in the previous situation. The first player can always ensure the difference in the multiplier of x and y differs by 1 after each of his move so (k(z + 1, kz)) can only be reached after the first player's turn. ----- We will do binary search to find the furthest z, such that (kz, kz) is inside d-circle ------ long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } long long square(long long n) { return n*n; } void solve() { long long d, k; cin >> d >> k; long long left = 0, right = ceil(d, k); while(right - left > 1) { long long mid = (left + right)/2; if(2*square(k*mid) <= square(d)) { left = mid; } else { right = mid; } } long long z = left; cout << (square(k*z) + square(k*(z + 1)) <= square(d) ? "Ashish" : "Utkarsh") << "\n"; } ================================================ FILE: 2020/Div 2/685 Div 2/Explanations/Non Substring Subsequence Explanation.txt ================================================ We will search for A[L] in S[1, L - 1] We will search for A[R] in S[R + 1, N] If either of these conditions are met, the subsequence is met. But, we must show that it is also necessary. Let us suppose that there is such a sequence in S. If the sequence begins before A[L], then the first character is before A[L]. (If the first occurence of A[L] is A[L], then it is not possible.) If the sequence begins After A[L], then the last character must occur again after A[R]. (If the last occurence of A[R] is R, then it is not possible.) ----- void solve() { int length, queries; cin >> length >> queries; string S; cin >> S; for(int i = 1; i <= queries; i++) { int left, right; cin >> left >> right; int answer_found = false; for(int i = right + 1; i <= length; i++) { if(S[right - 1] == S[i - 1]) { cout << "YES\n"; answer_found = true; break; } } if(answer_found) { continue; } for(int i = 1; i < left; i++) { if(S[i - 1] == S[left - 1]) { cout << "YES\n"; answer_found = true; break; } } if(answer_found) { continue; } cout << "NO\n"; } } ================================================ FILE: 2020/Div 2/685 Div 2/Explanations/Nullify the Matrix Explanation.txt ================================================ 1. Because of the constraint (r1 <= r2) and (c1 <= c2), any path we choose will contain only one square on the diagonal (r1 + c1). 2. Let us notice something. If any diagonal has XOR 0, we can choose a path that makes the XOR of every diagonal = 0 If every diagonal has XOR 0, then any path we choose will make the XOR non zero Since the final matrix has the XOR of every diagonal 0, this helps us in determining the winner. 3. Let us choose the smallest and largest diagonals having (r + c) values which are non-zero XOR In the first diagonal, we will choose a square which has the same bit set as X(r + c). There has to be at least one such square or the XOR will not have that bit set. We will perform subtraction to ensure the XOR becomes 0. Suppose the XOR was X and the square has S, We will make the square = XOR(S, X) Every other diagonal, there are additions allowed so we can make all the XOR's 0 4. If the XOR is 0, then our subtraction in the first square makes it non zero. 5. Each diagonal corresponds to a pile of stones. We can subtract from 1 set of piles but can add on the other piles. We can come up with this observation by noticing that the question says only the first square has a restriction of addition and the other squares are free. What is a property of the first square that no other square in the path has ? The diagonal ! This is the way to think of this ----- void solve() { int rows, columns; cin >> rows >> columns; vector diagonal (rows + columns + 1); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int x; cin >> x; diagonal[i + j] ^= x; } } int nim_sum = 0; for(int i = 2; i <= rows + columns; i++) { nim_sum += diagonal[i]; } cout << (nim_sum != 0 ? "Ashish\n" : "Jeel\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Explanations/String Equality Explanation.txt ================================================ Fact 1 - If A and B are anagrams, we can always make A = B Let us perform the swaps to make the last alphabet of A = last alphabet of B Then, we can delete the last character and repeat the same with strings of length (n - 1). ------ Fact 2 - The frequency of every alphabet (mod K) never changes We can change exactly K alphabets at a time. So the number of removals or additions to any alphabet can only be K at a time. So frequency[alphabet] (mod K) is invariant. If (frequency_A[alpha] %k != frequency_B[alpha]%k), then A and B can never have the same frequency of that alphabet. If they have the same remainder mod K for every alphabet, we will do a simulation. ----- void solve() { int length, k; string A, B; cin >> length >> k >> A >> B; const int NO_OF_ALPHABETS = 26; vector frequency_A(NO_OF_ALPHABETS + 1, 0), frequency_B(NO_OF_ALPHABETS + 1, 0); for(int i = 0; i < length; i++) { frequency_A[A[i] - 'a']++; frequency_B[B[i] - 'a']++; } int possible = true; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(frequency_A[alpha]%k != frequency_B[alpha]%k) { possible = false; } } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(frequency_B[alpha] > frequency_A[alpha]) { possible = false; break; } int extra = frequency_A[alpha] - frequency_B[alpha]; frequency_A[alpha + 1] += extra; } cout << (possible ? "Yes\n" : "No\n"); } ================================================ FILE: 2020/Div 2/685 Div 2/Explanations/Subtract or Divide Explanation.txt ================================================ 1. If n is 1, we do not need to do anything. 2. If n is 2, we can subtract 1 and do it in each step. 3. If n is even, we can go to 2 in 1 step and 1 in another. It is 2. 4. If n is 3, we can go to 2 in one step. And reach 1 in 2. 5. If n is odd, we can go an even integer in 1 step. And reach 1 in 3. ------ void solve() { int n; cin >> n; int moves = 0; if(n == 2) { moves++; } else if(n%2 == 0) { moves = 2; } else if(n > 1) { moves = (n == 3 ? 2 : 3); } cout << moves << "\n"; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/Bitwise Queries (Hard Version).cpp ================================================ #include #include #include using namespace std; void ask(int i, int j, string operation, int &result) { cout << operation << " " << i << " " << j << "\n"; cout.flush(); cin >> result; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, -1); vector xor_1(no_of_elements + 1, 0); for(int i = 2; i <= no_of_elements; i++) { ask(1, i, "XOR", xor_1[i]); } int and_12 = -1, and_23 = -1, and_13 = -1; int xor_12 = -1 , xor_13 = -1, xor_23 = -1; int second = 0, third = 0; map last_xor_occurence; for(int i = 1; i <= no_of_elements; i++) { //All Elements Different, At least one pair XOR = n - 1, n = 2^p if(xor_1[i] == no_of_elements - 1) { second = i; third = (i == 2 ? 3 : 2); xor_12 = xor_1[second]; xor_13 = xor_1[third]; xor_23 = xor_1[second]^xor_1[third]; and_12 = 0; ask(second, third, "AND", and_23); ask(1, third, "AND", and_13); break; } //Two Equal Elements if(last_xor_occurence[xor_1[i]] != 0) { ask(last_xor_occurence[xor_1[i]], i, "AND", A[i]); A[1] = A[i]^xor_1[i]; break; } last_xor_occurence[xor_1[i]] = i; } if(second != 0 && third != 0) { int sum_12 = xor_12 + 2*and_12; int sum_23 = xor_23 + 2*and_23; int sum_13 = xor_13 + 2*and_13; A[1] = (sum_12 - sum_23 + sum_13)/2; } for(int i = 2; i <= no_of_elements; i++) { A[i] = A[1]^xor_1[i]; } cout << "! "; for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; cout.flush(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/Bitwise Queries.cpp ================================================ #include #include using namespace std; void ask(int i, int j, string operation, int &result) { cout << operation << " " << i << " " << j << "\n"; cout.flush(); cin >> result; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); vector xor_1(no_of_elements + 1); int and_12, and_23, and_13; ask(1, 2, "XOR", xor_1[2]); ask(1, 2, "AND", and_12); ask(1, 3, "XOR", xor_1[3]); ask(1, 3, "AND", and_13); ask(2, 3, "AND", and_23); int xor_23 = xor_1[2]^xor_1[3]; //(1^2)^(1^3) = 2^3 int sum_12 = xor_1[2] + 2*and_12; int sum_23 = xor_23 + 2*and_23; int sum_13 = xor_1[3] + 2*and_13; A[1] = (sum_12 - sum_23 + sum_13)/2; A[2] = A[1]^xor_1[2]; A[3] = A[1]^xor_1[3]; for(int i = 4; i <= no_of_elements; i++) { ask(1, i, "XOR", xor_1[i]); A[i] = A[1]^xor_1[i]; } cout << "! "; for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; cout.flush(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/Circle Game.cpp ================================================ #include using namespace std; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } long long square(long long n) { return n*n; } void solve() { long long d, k; cin >> d >> k; long long left = 0, right = ceil(d, k); while(right - left > 1) { long long mid = (left + right)/2; if(2*square(k*mid) <= square(d)) { left = mid; } else { right = mid; } } long long z = left; cout << (square(k*z) + square(k*(z + 1)) <= square(d) ? "Ashish" : "Utkarsh") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/Non-Substring Subsequence .cpp ================================================ #include using namespace std; void solve() { int length, queries; cin >> length >> queries; string S; cin >> S; for(int i = 1; i <= queries; i++) { int left, right; cin >> left >> right; int answer_found = false; for(int i = right + 1; i <= length; i++) { if(S[right - 1] == S[i - 1]) { cout << "YES\n"; answer_found = true; break; } } if(answer_found) { continue; } for(int i = 1; i < left; i++) { if(S[i - 1] == S[left - 1]) { cout << "YES\n"; answer_found = true; break; } } if(answer_found) { continue; } cout << "NO\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/Nullify the Matrix.cpp ================================================ #include #include using namespace std; void solve() { int rows, columns; cin >> rows >> columns; vector diagonal (rows + columns + 1); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int x; cin >> x; diagonal[i + j] ^= x; } } int nim_sum = 0; for(int i = 2; i <= rows + columns; i++) { nim_sum += diagonal[i]; } cout << (nim_sum != 0 ? "Ashish\n" : "Jeel\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/String Equality.cpp ================================================ #include #include using namespace std; void solve() { int length, k; string A, B; cin >> length >> k >> A >> B; const int NO_OF_ALPHABETS = 26; vector frequency_A(NO_OF_ALPHABETS + 1, 0), frequency_B(NO_OF_ALPHABETS + 1, 0); for(int i = 0; i < length; i++) { frequency_A[A[i] - 'a']++; frequency_B[B[i] - 'a']++; } int possible = true; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(frequency_A[alpha]%k != frequency_B[alpha]%k) { possible = false; } } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(frequency_B[alpha] > frequency_A[alpha]) { possible = false; break; } int extra = frequency_A[alpha] - frequency_B[alpha]; frequency_A[alpha + 1] += extra; } cout << (possible ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/685 Div 2/Programs/Subtract or Divide .cpp ================================================ #include using namespace std; void solve() { int n; cin >> n; int moves = 0; if(n == 2) { moves++; } else if(n%2 == 0) { moves = 2; } else if(n > 1) { moves = (n == 3 ? 2 : 3); } cout << moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Explanations/Bouncing Ball Explanation.txt ================================================ Let us start at the i-th position. Then the cost is (A[i] + A[i + k] + A[i + 2k] + ... ) We will iterate through all possible candidates for the starting, i >= p and calculate the total cost ----- void solve() { int no_of_elements, p, k; cin >> no_of_elements >> p >> k; string S; cin >> S; int add_cost, removal_cost; cin >> add_cost >> removal_cost; vector sum(S.size() + k + 1, 0); for(int i = S.size() - 1; i >= 0; i--) { sum[i] = add_cost*(S[i] == '0') + sum[i + k]; //cout << "Sum " << i << " = " << sum[i] << "\n"; } const long long oo = 1e18; long long answer = oo; for(int i = p - 1, j = S.size(), r = 0; j >= p && i < S.size(); i++, j--, r++) { answer = min(answer, (r)*removal_cost + sum[i]); } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Explanations/New Game Plus Explanation.txt ================================================ Suppose we use (A[1], A[2], ... , A[x]) before using a reset. What is the total cost ? Remember that we can only add the boss point to our total before killing the boss. Total = (x - 1)A[1] + (x - 2)A[2] + ... + 0A[x] Seeing this, it is clearly optimal to visit elements in non-increasing order in 1 play through. ----- However, we also have negative increments. In this situation, it is better to use our play throughs. We need to imagine we have (k + 1) piles or stacks. It is always better for the larger element to be at a higher level in a stack. Suppose we have to elements a and b with a >= b at levels i and j respectively with i < j The current contribution to the total from both of these is ai + bj But, if we swap a and b, we will make the contribution (aj + bi), which is greater. ----- So, we will keep the lowest elements in the lowest level of all stacks. Then, the next lowest in the second, and so on. This is what we will start with - Distribute the integers as evenly as possible. After that, we will see if the answer can be improved by moving some of the greatest integers into one stack. ----- When i = 0 (mod k), we cannot put any more piles on the same stack since we have reached the limit. Suppose there are the 4 stacks and we are trying to build a tower of maximum length. We can put the box on the second stack on the first tower, box of the third stack on the first tower, box of the fourth stack on the first tower But we increase the height further as the box of the first pile is already in the first pile. ----- int main() { int no_of_elements, no_of_resets; cin >> no_of_elements >> no_of_resets; int no_of_stacks = no_of_resets + 1; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector suffix_sum(no_of_elements + 5, 0); for(int i = no_of_elements - 1; i >= 0; i--) { suffix_sum[i] = suffix_sum[i + 1] + A[i]; } long long total = 0; //Distribute Negative Integers Evenly for(int i = 0; i < no_of_elements; i++) { total += A[i]*(i/no_of_stacks); } for(int i = no_of_elements - 1; i >= 0; i--) { if(i%no_of_stacks == 0) //This element stays on same level { continue; } //cout << "i = " << i << " Total = " << total << " and suffix = " << suffix_sum[i] << "\n"; total = max(total, total + suffix_sum[i]); //cout << "total = " << total << "\n"; } cout << total << "\n"; return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Explanations/Prison Break Explanation.txt ================================================ The X and Y axes are independent. The X answer is max(i - 1, n - i) The Y answer is max(j - 1, m - j) Add the answers ----- void solve() { int rows, columns, i, j; cin >> rows >> columns >> i >> j; int row_answer = max(rows - i, i - 1); int column_answer = max(columns - j, j - 1); int answer = row_answer + column_answer; cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Explanations/Repainting Street Explanation.txt ================================================ There are only 100 colours so check the cost to make the array equal to each colour. The check can be done greedily. ----- int calculate(vector &A, int k, int chosen) { int n = A.size() - 1, no_of_days = 0; for(int i = 1; i <= n; i++) { if(A[i] != chosen) { no_of_days++; i += (k - 1); } } return no_of_days; } void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_COLOURS = 100; int answer = ceil(no_of_elements, k); for(int c = 1; c <= MAX_COLOURS; c++) { answer = min(answer, calculate(A, k, c)); } cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Explanations/XOR Gun Explanation.txt ================================================ Suppose there are 3 integers which have the same MSB. A[i], A[i + 1], A[i + 2] XOR(A[i + 1], A[i + 2]) will have a 0 in that bit position and be < A[i] So, it is always possible with 1 step. If every MSB occurs at most twice, we will have around 60 elements. Then, we will check it with brute force. For every pair (i, i + 1), XOR A[i] with some prefix and A[i + 1] with some suffix and check if it is possible to make A[i] > A[i + 1] ----- #include #include using namespace std; int is_bit_set(int n, int bit) { return ( (n&(1LL << bit)) != 0 ); } int msb(int n) { const int NO_OF_BITS = 31; for(int i = NO_OF_BITS; i >= 0; i--) { if(is_bit_set(n, i)) { return i; } } return 0; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int possible = false; const int NO_OF_BITS = 31; vector msb_frequency(NO_OF_BITS + 1, 0); for(int i = 1; i <= no_of_elements; i++) { msb_frequency[msb(A[i])]++; } int answer = no_of_elements + 1; for(int bit = 0; bit < NO_OF_BITS; bit++) { if(msb_frequency[bit] >= 3) { possible = true; answer = 1; break; } } vector prefix_xor(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { prefix_xor[i] = prefix_xor[i - 1]^A[i]; } for(int i = 1; i < no_of_elements && answer > 1; i++) { for(int j = i - 1; j >= 0; j--) { int prefix = prefix_xor[i]^prefix_xor[j]; int prefix_operations = (i - 1) - j; for(int k = i + 1; k <= no_of_elements; k++) { int suffix = prefix_xor[k]^prefix_xor[i]; int suffix_operations = k - (i + 1); if(prefix > suffix) { possible = true; answer = min(answer, prefix_operations + suffix_operations); } } } } cout << (possible ? answer : -1) << "\n"; return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Programs/Bouncing Ball.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, p, k; cin >> no_of_elements >> p >> k; string S; cin >> S; int add_cost, removal_cost; cin >> add_cost >> removal_cost; vector sum(S.size() + k + 1, 0); for(int i = S.size() - 1; i >= 0; i--) { sum[i] = add_cost*(S[i] == '0') + sum[i + k]; //cout << "Sum " << i << " = " << sum[i] << "\n"; } const long long oo = 1e18; long long answer = oo; for(int i = p - 1, j = S.size(), r = 0; j >= p && i < S.size(); i++, j--, r++) { answer = min(answer, (r)*removal_cost + sum[i]); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Programs/New Game Plus.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_resets; cin >> no_of_elements >> no_of_resets; int no_of_stacks = no_of_resets + 1; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector suffix_sum(no_of_elements + 5, 0); for(int i = no_of_elements - 1; i >= 0; i--) { suffix_sum[i] = suffix_sum[i + 1] + A[i]; } long long total = 0; //Distribute Negative Integers Evenly for(int i = 0; i < no_of_elements; i++) { total += A[i]*(i/no_of_stacks); } for(int i = no_of_elements - 1; i >= 0; i--) { if(i%no_of_stacks == 0) //This element stays on same level { continue; } //cout << "i = " << i << " Total = " << total << " and suffix = " << suffix_sum[i] << "\n"; total = max(total, total + suffix_sum[i]); //cout << "total = " << total << "\n"; } cout << total << "\n"; return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Programs/Prison Break.cpp ================================================ #include #include #include using namespace std; void solve() { int rows, columns, i, j; cin >> rows >> columns >> i >> j; int row_answer = max(rows - i, i - 1); int column_answer = max(columns - j, j - 1); int answer = row_answer + column_answer; cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Programs/Repainting Street.cpp ================================================ #include #include #include using namespace std; int ceil(int n, int d) { return (n/d) + (n%d != 0); } int calculate(vector &A, int k, int chosen) { int n = A.size() - 1, no_of_days = 0; for(int i = 1; i <= n; i++) { if(A[i] != chosen) { no_of_days++; i += (k - 1); } } return no_of_days; } void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_COLOURS = 100; int answer = ceil(no_of_elements, k); for(int c = 1; c <= MAX_COLOURS; c++) { answer = min(answer, calculate(A, k, c)); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/687 Div 2 Technocup 2021 Elimination Round 2/Programs/XOR Gun.cpp ================================================ #include #include using namespace std; int is_bit_set(int n, int bit) { return ( (n&(1LL << bit)) != 0 ); } int msb(int n) { const int NO_OF_BITS = 31; for(int i = NO_OF_BITS; i >= 0; i--) { if(is_bit_set(n, i)) { return i; } } return 0; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int possible = false; const int NO_OF_BITS = 31; vector msb_frequency(NO_OF_BITS + 1, 0); for(int i = 1; i <= no_of_elements; i++) { msb_frequency[msb(A[i])]++; } int answer = no_of_elements + 1; for(int bit = 0; bit < NO_OF_BITS; bit++) { if(msb_frequency[bit] >= 3) { possible = true; answer = 1; break; } } vector prefix_xor(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { prefix_xor[i] = prefix_xor[i - 1]^A[i]; } for(int i = 1; i < no_of_elements && answer > 1; i++) { for(int j = i - 1; j >= 0; j--) { int prefix = prefix_xor[i]^prefix_xor[j]; int prefix_operations = (i - 1) - j; for(int k = i + 1; k <= no_of_elements; k++) { int suffix = prefix_xor[k]^prefix_xor[i]; int suffix_operations = k - (i + 1); if(prefix > suffix) { possible = true; answer = min(answer, prefix_operations + suffix_operations); } } } } cout << (possible ? answer : -1) << "\n"; return 0; } ================================================ FILE: 2020/Div 2/688 Div 2/Explanation/Suffix Operations Explanation.txt ================================================ Let us observe that if we apply the operations on [i, n], A[i + 1] - A[i], A[i + 2] - A[i - 1], ... A[n] - A[n - 1] do not change. The differences of adjacent elements in the suffix remain the same. ----- In order to make it equal, the only way is to apply the operation to [i, N] We have to apply it |A[i] - A[i - 1]| times. Which element can we change ? If we change A[i], it is optimal to set it to either A[i - 1] or A[i + 1]. |A[i - 1] - x| + |A[i + 1] - x| is minimum when x = A[i - 1] or A[i + 1]. We will examine the maximum change we can do at every level and choose the best. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long change = max(abs(A[no_of_elements] - A[no_of_elements - 1]), abs(A[1] - A[2])); for(int i = 2; i < no_of_elements; i++) { long long new_operations = abs(A[i + 1] - A[i - 1]); long long old_operations = abs(A[i] - A[i - 1]) + abs(A[i + 1] - A[i]); change = max(change, old_operations - new_operations); } long long answer = 0; for(int i = 2; i <= no_of_elements; i++) { answer += abs(A[i] - A[i - 1]); } answer -= change; cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/688 Div 2/Programs/Suffix Operations.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long change = max(abs(A[no_of_elements] - A[no_of_elements - 1]), abs(A[1] - A[2])); for(int i = 2; i < no_of_elements; i++) { long long new_operations = abs(A[i + 1] - A[i - 1]); long long old_operations = abs(A[i] - A[i - 1]) + abs(A[i + 1] - A[i]); change = max(change, old_operations - new_operations); } long long answer = 0; for(int i = 2; i <= no_of_elements; i++) { answer += abs(A[i] - A[i - 1]); } answer -= change; cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Explanations/Divide and Summarize Explanation.txt ================================================ Let us precompute all possible sums we can get and store it in a set. This allows us to answer each query in O(log N) time. While we are precomputing the sums, we keep dividing the array into 2 and the height of this tree is at most Log N. So, the total time taken to precompute is O(N Log N) The number of sums stored is N + N/2 + N/4 + N/8 + N/16 + ... = O(N log N) ----- void check(map &S, int left, int right) { S[get_sum(left, right)] = true; if(A[left] == A[right]) { return; } int middle_element = (A[left] + A[right])/2; //Points to last occurrence of middle_element int mid = upper_bound(A.begin() + left, A.begin() + right, middle_element) - A.begin() - 1; check(S, left, mid); check(S, mid + 1, right); } ================================================ FILE: 2020/Div 2/689 Div 2/Explanations/Find a Spruce Explanation.txt ================================================ Let L[i][j] denote the maximum size of the left spruce starting at (i, j) and only going left. L[i][j] has a left spruce of size x, if L[i][j] >= x and L[i][j - 1] >= x - 1 So, L[i][j] = min(Height[i][j], L[i][j - 1] + 1) Let R[i][j] denote the maximum size of the right spruce starting at (i, j) R[i][j] = min(Height[i][j], R[i][j + 1] + 1) The length of the spruce at (i, j) is min(L[i][j], R[i][j]) ----- void solve() { int rows, columns; cin >> rows >> columns; vector grid(rows); for(int i = 0; i < rows; i++) { cin >> grid[i]; } vector > height(rows, vector (columns, 0)); for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(grid[i][j] == '*') { height[i][j] = (i == 0 ? 1 : height[i - 1][j] + 1); } } } vector > left_spruce(rows, vector (columns, 0)); for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { left_spruce[i][j] = height[i][j]; if(j == 0) { left_spruce[i][j] = min(left_spruce[i][j], 1); } if(j > 0) { left_spruce[i][j] = min(left_spruce[i][j], left_spruce[i][j - 1] + 1); } } } vector > right_spruce(rows, vector (columns, 0)); for(int i = 0; i < rows; i++) { for(int j = columns - 1; j >= 0; j--) { right_spruce[i][j] = height[i][j]; if(j == columns - 1) { right_spruce[i][j] = min(right_spruce[i][j], 1); } if(j < columns - 1) { right_spruce[i][j] = min(right_spruce[i][j], right_spruce[i][j + 1] + 1); } } } long long total_spruce = 0; for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { int spruce_here = min(right_spruce[i][j], left_spruce[i][j]); total_spruce += spruce_here; } } cout << total_spruce << "\n"; } ================================================ FILE: 2020/Div 2/689 Div 2/Explanations/Mathematical Expression Explanation.txt ================================================ Let us go case by case and eliminiate the simple cases. If there is only 1 sign, then we have to use that sign everywhere. Suppose there is (+-), we will use addition everywhere. Suppose there is (-*), we will use multiplication everywhere except near a 0. ----- The case (+*) is the same as (+*-). We can eliminate the minus sign and just solve it with the other two. Now, multiplication is normally better than addition Even, 2 x 2 = 2 + 2, and for all other integers > 2, multiplication is clearly better. The problem is when there are ones. We might be better off adding some ones and then using a multiplication. ----- Now, how do we handle the case where there is both + and * We will solve each segment of non-zero digits separately. ----- Let f(i) be the maximum for the first i digits. Let us iterate over the position of the last plus sign. f(i) = max{f(j) + A[j... i]}, for all j Now, this is a O(n^2) DP, but we can make some observations that ensure we do at most 20 linear scans. ----- When we begin processing a segment, we will put + signs on all the prefix and suffix ones. This is the best because multiplication here would just make the answer 1. Now, we have a segment A[L, R], where A[L] > 1 and A[R] > 1 1. We will find the best value of f(i) only at the non-1 elements. 2. If there are more than 20 non-one elements, we will do multiplication everywhere. ----- Suppose there are 20 elements > 1. 2^{20} is the smallest such product. Suppose we replace any multiplication sign on this segment with an addition sign. The product is reducing at least by 2^{19} and the maximum value we can get by addition is 10^5, which is smaller. So, we are better off doing multiplication everywhere. ----- If A[i] = 1, then f(i) = f(i - 1) + 1 If the last element of the segment is 1, it is better to add 1 then multiply. So, we only need to loop backwards when A[i] > 1, which only happens 20 times. ----- void solve(int left, int right, vector &S, vector &A) { while(left <= right && A[left] == 1) { S[left] = '+'; left++; } if(right <= left) { return; } while(right >= left && A[right] == 1) { S[right - 1] = '+'; right--; } const int MAX_NON_1 = 20; int non_1 = 0; for(int i = left; i <= right; i++) { non_1 += (A[i] != 1); } if(non_1 >= MAX_NON_1) { for(int i = left; i < right; i++) { S[i] = '*'; } return; } for(int i = left; i <= right; i++) { last_plus[i] = 0; max_answer[i] = 0; } for(int i = left; i <= right; i++) { if(A[i] == 1) { max_answer[i] = max_answer[i - 1] + 1; last_plus[i] = i - 1; continue; } long long product_here = 1; for(int j = i; j >= left; j--) { product_here *= A[j]; if(product_here + max_answer[j - 1] > max_answer[i]) { max_answer[i] = max_answer[j - 1] + product_here; last_plus[i] = j - 1; //cout << "Max " << j << " = " << max_answer[j] << " and last plus = " << last_plus[i] << "\n"; } } } for(int i = right; i >= left; i = last_plus[i]) { for(int j = i - 1; j > last_plus[i]; j--) { S[j] = '*'; } S[last_plus[i]] = '+'; } } ================================================ FILE: 2020/Div 2/689 Div 2/Explanations/Random Events Explanation.txt ================================================ Let us look at the rightmost unsorted element. If this element is not in it's correct place, the array will not be sorted. So, we will only look at segments which impact this element. This element will be in it's correct place if at least 1 or more of these segments work. In order to make it easier, we will calculate the probability of failure and subtract 1 from it. ----- void solve() { int no_of_elements, no_of_operations; cin >> no_of_elements >> no_of_operations; int maximum_unsorted = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; if(A[i] != i) { maximum_unsorted = max(maximum_unsorted, i); } } double failure_probability = (maximum_unsorted == 0 ? 0 : 1); for(int i = 1; i <= no_of_operations; i++) { int right; double p; cin >> right >> p; if(right >= maximum_unsorted) { failure_probability *= (1 - p); } } double success_probability = 1 - failure_probability; cout << fixed << setprecision(6) << success_probability << "\n"; } ================================================ FILE: 2020/Div 2/689 Div 2/Explanations/String Generation Explanation.txt ================================================ We will print a string of K a's followed by (cba) concatenated till the end. cbacba... can never form a palindrome of length > 1 ----- void solve() { int length, palindrome_length; cin >> length >> palindrome_length; vector S(length + 3); for(int i = 0; i < palindrome_length; i++) { S[i] = 'a'; } for(int i = palindrome_length; i < length; i += 3) { S[i] = 'c'; S[i + 1] = 'b'; S[i + 2] = 'a'; } for(int i = 0; i < length; i++) { cout << S[i]; } cout << "\n"; } ================================================ FILE: 2020/Div 2/689 Div 2/Explanations/Water Level Explanation.txt ================================================ We need to deal with 3 different cases. 1. Refill < usage 2. Refill = usage 3. Refill > usage ------ When refill < usage, we will refill it everyday to ensure it stays in the limit. We only need to see if we can refill it on the very first day as a special case. ----- When refill = usage, just check if refilling or using it makes it go out of bounds. ----- When refill > usage, we do not want to overflow. So, we will only refill it greedily just when another usage would make the water level drop below L. In fact, we will look at the water level (mod u). As long as we are using without refilling, the remainder is invariant. When we refill it, it becomes (x + R) (mod u). We will check if we every visit a remainder that is already visited. If so, we have reached a cycle and will be within [L, R] indefinitely. ----- int main() { long long left, right, initial, no_of_days, usage, refill; cin >> initial >> left >> right >> no_of_days >> usage >> refill; int possible = true; if(refill < usage) { long long reduction = usage - refill; if(initial + refill > right) { initial -= usage; no_of_days--; } if(left > initial) { possible = false; } long long days_used = (initial - left)/reduction; if(days_used < no_of_days) { possible = false; } } else if(refill == usage) { if(initial + refill > right && initial - refill < left) { possible = false; } } else { vector reached(usage + 1, false); reached[initial%usage] = true; possible = in_between(initial, left, right); while(no_of_days > 0 && possible) { long long days_used = (initial - left)/usage; no_of_days -= days_used; initial -= (days_used*usage); if(no_of_days <= 0) { //cout << "Not enought days\n"; possible = true; break; } initial += refill; //cout << "After refill = " << initial << "\n"; if(initial > right) { //cout << "Overflow\n"; possible = false; break; } if(reached[initial%usage]) { //cout << "Already reached\n"; possible = true; break; } reached[initial%usage] = true; } } cout << (possible ? "Yes" : "No") << "\n"; return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Programs/Divide and Summarize.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 1e5 + 5; vector A(MAX_N, 0), sum(MAX_N, 0); long long get_sum(int left, int right) { return (sum[right] - sum[left - 1]); } void check(map &S, int left, int right) { S[get_sum(left, right)] = true; if(A[left] == A[right]) { return; } int middle_element = (A[left] + A[right])/2; //Points to last occurrence of middle_element int mid = upper_bound(A.begin() + left, A.begin() + right, middle_element) - A.begin() - 1; check(S, left, mid); check(S, mid + 1, right); } void solve() { int no_of_elements, no_of_queries; cin >> no_of_elements >> no_of_queries; A[0] = 0; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin() + 1, A.begin() + no_of_elements + 1); sum[0] = 0; for(int i = 1; i <= no_of_elements; i++) { sum[i] = sum[i - 1] + A[i]; } map possible_sums; check(possible_sums, 1, no_of_elements); while(no_of_queries--) { long long target_sum; cin >> target_sum; cout << (possible_sums.count(target_sum) > 0 ? "Yes" : "No") << "\n"; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Programs/Find the Spruce.cpp ================================================ #include #include using namespace std; void solve() { int rows, columns; cin >> rows >> columns; vector grid(rows); for(int i = 0; i < rows; i++) { cin >> grid[i]; } vector > height(rows, vector (columns, 0)); for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(grid[i][j] == '*') { height[i][j] = (i == 0 ? 1 : height[i - 1][j] + 1); } } } vector > left_spruce(rows, vector (columns, 0)); for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { left_spruce[i][j] = height[i][j]; if(j == 0) { left_spruce[i][j] = min(left_spruce[i][j], 1); } if(j > 0) { left_spruce[i][j] = min(left_spruce[i][j], left_spruce[i][j - 1] + 1); } } } vector > right_spruce(rows, vector (columns, 0)); for(int i = 0; i < rows; i++) { for(int j = columns - 1; j >= 0; j--) { right_spruce[i][j] = height[i][j]; if(j == columns - 1) { right_spruce[i][j] = min(right_spruce[i][j], 1); } if(j < columns - 1) { right_spruce[i][j] = min(right_spruce[i][j], right_spruce[i][j + 1] + 1); } } } long long total_spruce = 0; for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { int spruce_here = min(right_spruce[i][j], left_spruce[i][j]); total_spruce += spruce_here; } } cout << total_spruce << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Programs/Mathematical Expression.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 1e5 + 5; int last_plus[MAX_N], max_answer[MAX_N]; void solve(int left, int right, vector &S, vector &A) { while(left <= right && A[left] == 1) { S[left] = '+'; left++; } if(right <= left) { return; } while(right >= left && A[right] == 1) { S[right - 1] = '+'; right--; } const int MAX_NON_1 = 20; int non_1 = 0; for(int i = left; i <= right; i++) { non_1 += (A[i] != 1); } if(non_1 >= MAX_NON_1) { for(int i = left; i < right; i++) { S[i] = '*'; } return; } for(int i = left; i <= right; i++) { last_plus[i] = 0; max_answer[i] = 0; } for(int i = left; i <= right; i++) { if(A[i] == 1) { max_answer[i] = max_answer[i - 1] + 1; last_plus[i] = i - 1; continue; } long long product_here = 1; for(int j = i; j >= left; j--) { product_here *= A[j]; if(product_here + max_answer[j - 1] > max_answer[i]) { max_answer[i] = max_answer[j - 1] + product_here; last_plus[i] = j - 1; //cout << "Max " << j << " = " << max_answer[j] << " and last plus = " << last_plus[i] << "\n"; } } } for(int i = right; i >= left; i = last_plus[i]) { for(int j = i - 1; j > last_plus[i]; j--) { S[j] = '*'; } S[last_plus[i]] = '+'; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 5, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } string S; cin >> S; sort(S.begin(), S.end()); if(S.size() == 1) { for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << (i < no_of_elements ? S : "\n"); } return 0; } if(S == "+-") { for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << (i < no_of_elements ? "+" : "\n"); } return 0; } if(S == "*-") { for(int i = 1; i <= no_of_elements; i++) { cout << A[i]; if(i < no_of_elements) { cout << (A[i + 1] == 0 ? "-" : "*"); } } cout << "\n"; return 0; } vector signs(no_of_elements + 5, '?'); //Invariant that A[i] = 0 always for(int i = 0, j = 1; i < no_of_elements; i = j) { for(j = i + 1; j <= no_of_elements && A[j] != 0; ) { j++; } //cout << "Solve [" << i + 1 << "," << j - 1 << "]\n"; solve(i + 1, j - 1, signs, A); signs[i - 1] = signs[i] = signs[j - 1] = signs[j] = '+'; /*for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << (i < no_of_elements ? signs[i] : '\n'); }*/ } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << (i < no_of_elements ? signs[i] : '\n'); } return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Programs/Random Events.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, no_of_operations; cin >> no_of_elements >> no_of_operations; int maximum_unsorted = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; if(A[i] != i) { maximum_unsorted = max(maximum_unsorted, i); } } double failure_probability = (maximum_unsorted == 0 ? 0 : 1); for(int i = 1; i <= no_of_operations; i++) { int right; double p; cin >> right >> p; if(right >= maximum_unsorted) { failure_probability *= (1 - p); } } double success_probability = 1 - failure_probability; cout << fixed << setprecision(6) << success_probability << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Programs/String Generation.cpp ================================================ #include #include using namespace std; void solve() { int length, palindrome_length; cin >> length >> palindrome_length; vector S(length + 3); for(int i = 0; i < palindrome_length; i++) { S[i] = 'a'; } for(int i = palindrome_length; i < length; i += 3) { S[i] = 'c'; S[i + 1] = 'b'; S[i + 2] = 'a'; } for(int i = 0; i < length; i++) { cout << S[i]; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/689 Div 2/Programs/Water Level.cpp ================================================ #include #include using namespace std; int in_between(long long x, long long left, long long right) { return (left <= x && x <= right); } int main() { long long left, right, initial, no_of_days, usage, refill; cin >> initial >> left >> right >> no_of_days >> usage >> refill; int possible = true; if(refill < usage) { long long reduction = usage - refill; if(initial + refill > right) { initial -= usage; no_of_days--; } if(left > initial) { possible = false; } long long days_used = (initial - left)/reduction; if(days_used < no_of_days) { possible = false; } } else if(refill == usage) { if(initial + refill > right && initial - refill < left) { possible = false; } } else { vector reached(usage + 1, false); reached[initial%usage] = true; possible = in_between(initial, left, right); while(no_of_days > 0 && possible) { //cout << "Water = " << initial << " "; long long days_used = (initial - left)/usage; no_of_days -= days_used; //cout << "No of days = " << days_used << "\n"; initial -= (days_used*usage); //cout << "After usage = " << initial << "\n"; if(no_of_days <= 0) { //cout << "Not enought days\n"; possible = true; break; } initial += refill; //cout << "After refill = " << initial << "\n"; if(initial > right) { //cout << "Overflow\n"; possible = false; break; } if(reached[initial%usage]) { //cout << "Already reached\n"; possible = true; break; } reached[initial%usage] = true; } } cout << (possible ? "Yes" : "No") << "\n"; return 0; } ================================================ FILE: 2020/Div 2/691 Div 2/Explanation/Move and Turn Explanation.txt ================================================ We will be making independent horizontal steps and vertical steps of n/2. Let us see the number of possibilities of horizontal steps. K right 0 left = K (K - 1) right 1 left = K - 2 (K - 2) right 2 left = K - 4 . . 0 right K left = -K Each of these (K + 1) steps lead to a different result. ----- If n is odd, then we will make one more horizontal step than vertical step or other way around. ----- int main() { int length; cin >> length; int horizontal_steps = length/2, vertical_steps = length/2; long long horizontal_results = (horizontal_steps + 1); long long vertical_results = (vertical_steps + 1); long long answer; if(length%2 == 1) { answer = (horizontal_results + 1)*(vertical_results) + (horizontal_results)*(vertical_results + 1); } else { answer = horizontal_results*vertical_results; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/691 Div 2/Explanation/Red Blue Shuffle Explanation.txt ================================================ The red card is greater than the blue card if they have some prefix where R[i] = B[i] and then R[i] > B[i] Let us iterate over the possibility of the first unequal card. If there are more cards where R[i] > B[i], red is the winner If B[i] > R[i], blue is the winner. ----- void solve() { int length; string R, B; cin >> length >> R >> B; int red_cards = 0, blue_cards = 0; for(int i = 0; i < length; i++) { if(R[i] > B[i]) { red_cards++; } else if(B[i] > R[i]) { blue_cards++; } } if(red_cards == blue_cards) { cout << "EQUAL\n"; } else { cout << (red_cards > blue_cards ? "RED\n" : "BLUE\n"); } } ================================================ FILE: 2020/Div 2/691 Div 2/Explanation/Row GCD Explanation.txt ================================================ - $g = \gcd(a_1 + b_i, a_2 + b_i, a_3 + b_i, \dots , a_n + b_i) = \gcd(a_1 + b_i, a_2 - a_1, a_3 - a_2, \dots , a_n - a_{n - 1})$ - We will precalculate the GCD of the differences before hand so we can find the GCD in one step. ----- int main() { int no_of_elements_a, no_of_elements_b; cin >> no_of_elements_a >> no_of_elements_b; vector A(no_of_elements_a + 1), B(no_of_elements_b + 1); for(int i = 1; i <= no_of_elements_a; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements_b; i++) { cin >> B[i]; } sort(all(A)); vector difference(no_of_elements_a); for(int i = 1; i < no_of_elements_a; i++) { difference[i] = A[i + 1] - A[i]; } long long array_gcd = 0; for(int i = 2; i < no_of_elements_a; i++) { array_gcd = gcd(array_gcd, difference[i]); } vector answer(no_of_elements_b + 1); for(int i = 1; i <= no_of_elements_b; i++) { answer[i] = gcd(A[1] + B[i], array_gcd); } for(int i = 1; i <= no_of_elements_b; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/691 Div 2/Programs/Move and Turn.cpp ================================================ #include using namespace std; int main() { int length; cin >> length; int horizontal_steps = length/2, vertical_steps = length/2; long long horizontal_results = (horizontal_steps + 1); long long vertical_results = (vertical_steps + 1); long long answer; if(length%2 == 1) { answer = (horizontal_results + 1)*(vertical_results) + (horizontal_results)*(vertical_results + 1); } else { answer = horizontal_results*vertical_results; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/691 Div 2/Programs/Red Blue Shuffle.cpp ================================================ #include using namespace std; void solve() { int length; string R, B; cin >> length >> R >> B; int red_cards = 0, blue_cards = 0; for(int i = 0; i < length; i++) { if(R[i] > B[i]) { red_cards++; } else if(B[i] > R[i]) { blue_cards++; } } if(red_cards == blue_cards) { cout << "EQUAL\n"; } else { cout << (red_cards > blue_cards ? "RED\n" : "BLUE\n"); } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/691 Div 2/Programs/Row GCD.cpp ================================================ #include #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() long long gcd(long long a, long long b) { if(min(a, b) == 0) return max(a, b); return gcd(min(a, b), max(a, b)%min(a, b)); } int main() { int no_of_elements_a, no_of_elements_b; cin >> no_of_elements_a >> no_of_elements_b; vector A(no_of_elements_a + 1), B(no_of_elements_b + 1); for(int i = 1; i <= no_of_elements_a; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements_b; i++) { cin >> B[i]; } sort(all(A)); vector difference(no_of_elements_a); for(int i = 1; i < no_of_elements_a; i++) { difference[i] = A[i + 1] - A[i]; } long long array_gcd = 0; for(int i = 2; i < no_of_elements_a; i++) { array_gcd = gcd(array_gcd, difference[i]); } vector answer(no_of_elements_b + 1); for(int i = 1; i <= no_of_elements_b; i++) { answer[i] = gcd(A[1] + B[i], array_gcd); } for(int i = 1; i <= no_of_elements_b; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 2/692 Div 2/Explanations/Fair Numbers Explanation.txt ================================================ In Any interval [L, L + X], there will be at least one multiple of x. The LCM of (1, 2, ... , 9) is 2520. In any interval of 2520 integers, there is at least one number that is divisible by all 9 digits. So the gap in between two fair integers cannot exceed 2520. This allows us to compute it using brute force. ----- int fair(long long n) { long long value = n; while(n) { int digit = n%10; if(digit != 0 && value%digit != 0) {//cout << value << " not divisible " return false; } n /= 10; } return true; } void solve() { long long n; cin >> n; long long answer; for(answer = n; !fair(answer); answer++); cout << answer << "\n"; } ================================================ FILE: 2020/Div 2/692 Div 2/Explanations/In Game Chat Explanation.txt ================================================ Count the suffix of ) and compare with the rest of the string ----- void solve() { int length; string S; cin >> length >> S; int suffix = 0; for(int i = length - 1; i >= 0; i--) { if(S[i] != ')') { break; } suffix++; } //cout << "String Read : " << S << " Suffix = " << suffix << "\n"; int prefix = length - suffix; cout << (prefix < suffix ? "Yes" : "No") << "\n"; } ================================================ FILE: 2020/Div 2/692 Div 2/Programs/Fair Numbers.cpp ================================================ #include using namespace std; int fair(long long n) { long long value = n; while(n) { int digit = n%10; if(digit != 0 && value%digit != 0) {//cout << value << " not divisible " return false; } n /= 10; } return true; } void solve() { long long n; cin >> n; long long answer; for(answer = n; !fair(answer); answer++); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/692 Div 2/Programs/In Game Chat.cpp ================================================ #include using namespace std; void solve() { int length; string S; cin >> length >> S; int suffix = 0; for(int i = length - 1; i >= 0; i--) { if(S[i] != ')') { break; } suffix++; } //cout << "String Read : " << S << " Suffix = " << suffix << "\n"; int prefix = length - suffix; cout << (prefix < suffix ? "Yes" : "No") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Explanations/Grade Allocation Explanation.txt ================================================ We will make score[1] = total_sum or highest_score, whichever is lower ----- #include #include using namespace std; void solve() { int no_of_students, highest_score; cin >> no_of_students >> highest_score; vector score(no_of_students + 1); for(int i = 1; i <= no_of_students; i++) { cin >> score[i]; } int remaining_sum = 0; for(int i = 2; i <= no_of_students; i++) { remaining_sum += score[i]; } score[1] = min(highest_score, score[1] + remaining_sum); cout << score[1] << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Explanations/Nash Matrix Explanation.txt ================================================ There are two types of components in this graph Those that are in a cycle and those that have a 'sink'. For all those vertices that end up in a sink, we will start from the sink and do a DFS to cover all cells reachable from it For the cycle, we will do this If X[i][j] = -1 and Y[i][j] = -1, we will look at any of it's neighbours which are -1 Whichever neighbour is -1, we will create a loop between them like LR or RL or UD or DU This will lead to a cycle of length 2. Any -1 cell cluster that is connected to this 2-cycle will eventually fall into a cycle too ----- A finer point needs to be said here About the components that end up in a sink, we must always start from the sink and then go 'outwards'. We cannot start from any random point of the component and then go 'inwards' Suppose we have (2, 2) (2, 2) (2, 2) (2, 2) My algorithm was labelling it as RL UX Which is wrong because RL ends up in a loop It should be RD LX The main reason for this is that I was starting the DFS from any point in the component. I should only be starting the DFS from the 'sink' or the starting point of the component ----- #include #include #include using namespace std; const int MAX_N = 1e3 + 5, NO_OF_DIRECTIONS = 4; char grid[MAX_N][MAX_N]; int X[MAX_N][MAX_N], Y[MAX_N][MAX_N]; char direction[NO_OF_DIRECTIONS] = {'U', 'R', 'L', 'D'}; char reverse_direction[NO_OF_DIRECTIONS] = {'D', 'L', 'R', 'U'}; int next_x[NO_OF_DIRECTIONS] = {-1, 0, 0, 1}; int next_y[NO_OF_DIRECTIONS] = {0, 1, -1, 0}; void find_looping_partner(int i, int j) { for(int d = 0; d < NO_OF_DIRECTIONS; d++) { int next_i = i + next_x[d]; int next_j = j + next_y[d]; if(X[next_i][next_j] == -1 && Y[next_i][next_j] == -1) { grid[i][j] = direction[d]; grid[next_i][next_j] = reverse_direction[d]; return; } } } void dfs(int i, int j, int final_x, int final_y, char D) { grid[i][j] = D; for(int d = 0; d < NO_OF_DIRECTIONS; d++) { int next_i = i + next_x[d]; int next_j = j + next_y[d]; if(grid[next_i][next_j] != 0) { continue; } if(X[next_i][next_j] == final_x && Y[next_i][next_j] == final_y) { dfs(next_i, next_j, final_x, final_y, reverse_direction[d]); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { cin >> X[i][j] >> Y[i][j]; } } memset(grid, 0, sizeof(grid)); for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(grid[i][j] != 0) { continue; } if(X[i][j] == i && Y[i][j] == j) { dfs(i, j, X[i][j], Y[i][j], 'X'); } if(X[i][j] == -1 && Y[i][j] == -1) { find_looping_partner(i, j); } } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(grid[i][j] == 0) { cout << "INVALID\n"; return 0; } } } cout << "VALID\n"; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { cout << grid[i][j]; } cout << "\n"; } return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Explanations/Primitive Primes Explanation.txt ================================================ Let A[i] be the first coefficient of A that is not a multiple of p Let B[j] be the first coefficient of B that is not a multiple of p Then, our claim is that the coefficient of degree (i + j) of A.B is not a multiple of p ----- How do we calculate the coefficient of degree k of polynomial A.B Coefficient [k] = Sum(A[i] B[i - k]) ----- Now, let us look at coefficient of (i + j) A[0]B[i + j] + A[1]B[i + j - 1] + .... + A[i - 1]B[i + j - (i - 1)] + A[i]B[j] + A[i + 1]B[j - 1] + A[i + 2]B[j - 2] + ... + A[i + j]B[0] Since A[i] is the first coefficient of A that is not a multiple of p, All of A[0, ... , i - 1] is a multiple of p Similarly all of B[0, .... , j - 1] is a multiple of p So, this means that all the terms in the first and third line are a multiple of p because at least one of the terms of each product is a multiple of p This means coefficient (i + j) = A[i]B[j] (mod p) This cannot be = 0 (mod p) Hence, (i + j) is the answer ------ #include #include using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_terms_A, no_of_terms_B, p; cin >> no_of_terms_A >> no_of_terms_B >> p; vector A(no_of_terms_A + 1); for(int i = 0; i < no_of_terms_A; i++) { cin >> A[i]; } vector B(no_of_terms_B + 1); for(int i = 0; i < no_of_terms_B; i++) { cin >> B[i]; } int first_A = 0; while(A[first_A]%p == 0) { first_A++; } int first_B = 0; while(B[first_B]%p == 0) { first_B++; } int answer = first_A + first_B; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Explanations/String Modification Explanation.txt ================================================ Let us simulate the process for each k S[k] goes to S[1] S[k + 1] goes to S[2] and so on The ending of the string is either S[1], S[2], ... , S[k - 1] or S[k - 1], S[k - 2], .... , S[1] depending on whether k is even or odd respectively ----- void solve() { int length; string S; cin >> length >> S; string smallest = S, smallest_here = S; int best_k = 1; for(int k = 2; k <= length; k++) { for(int i = 0, j = k - 1 + i; j < length; i++, j++) { smallest_here[i] = S[j]; //cout << smallest_here[i]; } //cout << "\n"; for(int j = 0, i = length - k + 1; i < length; i++, j++) { smallest_here[i] = S[j]; } if( (length - k + 1)%2 == 1) { reverse(smallest_here.begin() + length - k + 1, smallest_here.end()); } //cout << "k = " << k << " S = " << smallest_here << "\n"; if(smallest_here < smallest) { smallest = smallest_here; best_k = k; } } cout << smallest << "\n" << best_k << "\n"; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Explanations/Team Building Explanation.txt ================================================ Let us suppose the option to play in the audience does not exist. Then, we can do a straightforward DP, f(i, m) Let f(i, m) represent the highest strength we can have for the first i people with mask = m If m = 1001001, it means that we have taken the first, fourth and seventh player The transition is, f(i, m) = max(f(i - 1, m xor 2^p) + A[i][p], f(i - 1, m)) ----- Now, since we have the additional requirement of audience If two people are not playing, it is always better to choose the higher audience person for the audience position Let us sort all the players in descending order of their audience strength ----- Now, if we are at player i and have taken mask m = 10001001 It means we have taken 3 players in the team And the remaining (i - 1) - 3 players are in the audience Now, we have an additional transition apart from the normal transition. We have to check if the i-th person can be in the audience f(i, m) = A[i] + f(i - 1, m) ----- f(0, 0) = 0 And another thing we have to be careful about is to not visit any unvisited state. Before transitioning, we have to ensuring f(i - 1, m) is not -1 Otherwise, it is not possible ----- f(1, 100011011) is not attainable because we have not yet seen 5 people So, before transitioning to f(i - 1, m) we have to check if it is not -1 and is attainable ----- #include #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; const int MAX_N = 1e5 + 5, MAX_M = (1 << 7) + 1; long long max_till[MAX_N][MAX_M], value[MAX_N][9]; int no_of_bits(int n) { int count = 0; while(n) { count += (n%2); n /= 2; } return count; } int is_bit_set(int n, int bit) { return ( (n & (1 << bit)) != 0); } int main() { int no_of_elements, no_of_players, audience; cin >> no_of_elements >> no_of_players >> audience; vector < pair > A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i].first; A[i].second = i; } sort(all(A)); reverse(all(A)); for(int i = 1; i <= no_of_elements; i++) { for(int j = 0; j < no_of_players; j++) { cin >> value[i][j]; } } memset(max_till, -1, sizeof(max_till)); max_till[0][0] = 0; for(int i = 1; i <= no_of_elements; i++) { int index = A[i].second; //cout << "(" << A[i].first << "," << A[i].second << ")\n"; for(int m = 0; m < (1 << no_of_players); m++) { int players = no_of_bits(m); int audience_so_far = (i - 1) - players; if(players > i) { continue; } if(audience_so_far < audience) { if(max_till[i - 1][m] != -1) { //cout << "Audience = " << A[i].first << "\n"; max_till[i][m] = max_till[i - 1][m] + A[i].first; } } else { if(max_till[i - 1][m] != -1) { max_till[i][m] = max_till[i - 1][m]; } } for(int bit = 0; bit < no_of_players; bit++) { if(is_bit_set(m, bit) && max_till[i - 1][m^(1 << bit)] != -1) { //cout << "Choice is " << max_till[i][m] << " and " << value[index][bit] << " + " << max_till[i - 1][m^(1 << bit)] << "\n"; max_till[i][m] = max(max_till[i][m], value[index][bit] + max_till[i - 1][m^(1 << bit)]); } } //cout << "f(" << i << "," << m << ") = " << max_till[i][m] << "\n"; } } int total = (1 << no_of_players) - 1; cout << max_till[no_of_elements][total] << "\n"; return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Programs/Grade Allocation.cpp ================================================ #include #include using namespace std; void solve() { int no_of_students, highest_score; cin >> no_of_students >> highest_score; vector score(no_of_students + 1); for(int i = 1; i <= no_of_students; i++) { cin >> score[i]; } int remaining_sum = 0; for(int i = 2; i <= no_of_students; i++) { remaining_sum += score[i]; } score[1] = min(highest_score, score[1] + remaining_sum); cout << score[1] << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Programs/Nash Matrix.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e3 + 5, NO_OF_DIRECTIONS = 4; char grid[MAX_N][MAX_N]; int X[MAX_N][MAX_N], Y[MAX_N][MAX_N]; char direction[NO_OF_DIRECTIONS] = {'U', 'R', 'L', 'D'}; char reverse_direction[NO_OF_DIRECTIONS] = {'D', 'L', 'R', 'U'}; int next_x[NO_OF_DIRECTIONS] = {-1, 0, 0, 1}; int next_y[NO_OF_DIRECTIONS] = {0, 1, -1, 0}; void find_looping_partner(int i, int j) { for(int d = 0; d < NO_OF_DIRECTIONS; d++) { int next_i = i + next_x[d]; int next_j = j + next_y[d]; if(X[next_i][next_j] == -1 && Y[next_i][next_j] == -1) { grid[i][j] = direction[d]; grid[next_i][next_j] = reverse_direction[d]; return; } } } void dfs(int i, int j, int final_x, int final_y, char D) { grid[i][j] = D; for(int d = 0; d < NO_OF_DIRECTIONS; d++) { int next_i = i + next_x[d]; int next_j = j + next_y[d]; if(grid[next_i][next_j] != 0) { continue; } if(X[next_i][next_j] == final_x && Y[next_i][next_j] == final_y) { dfs(next_i, next_j, final_x, final_y, reverse_direction[d]); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { cin >> X[i][j] >> Y[i][j]; } } memset(grid, 0, sizeof(grid)); for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(grid[i][j] != 0) { continue; } if(X[i][j] == i && Y[i][j] == j) { dfs(i, j, X[i][j], Y[i][j], 'X'); } if(X[i][j] == -1 && Y[i][j] == -1) { find_looping_partner(i, j); } } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(grid[i][j] == 0) { cout << "INVALID\n"; return 0; } } } cout << "VALID\n"; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { cout << grid[i][j]; } cout << "\n"; } return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Programs/Primitive Primes.cpp ================================================ #include #include using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_terms_A, no_of_terms_B, p; cin >> no_of_terms_A >> no_of_terms_B >> p; vector A(no_of_terms_A + 1); for(int i = 0; i < no_of_terms_A; i++) { cin >> A[i]; } vector B(no_of_terms_B + 1); for(int i = 0; i < no_of_terms_B; i++) { cin >> B[i]; } int first_A = 0; while(A[first_A]%p == 0) { first_A++; } int first_B = 0; while(B[first_B]%p == 0) { first_B++; } int answer = first_A + first_B; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Programs/String Modification.cpp ================================================ #include #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; string smallest = S, smallest_here = S; int best_k = 1; for(int k = 2; k <= length; k++) { for(int i = 0, j = k - 1 + i; j < length; i++, j++) { smallest_here[i] = S[j]; //cout << smallest_here[i]; } //cout << "\n"; for(int j = 0, i = length - k + 1; i < length; i++, j++) { smallest_here[i] = S[j]; } if( (length - k + 1)%2 == 1) { reverse(smallest_here.begin() + length - k + 1, smallest_here.end()); } //cout << "k = " << k << " S = " << smallest_here << "\n"; if(smallest_here < smallest) { smallest = smallest_here; best_k = k; } } cout << smallest << "\n" << best_k << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 2/CodeCraft 2020/Programs/Team Building.cpp ================================================ #include #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; const int MAX_N = 1e5 + 5, MAX_M = (1 << 7) + 1; long long max_till[MAX_N][MAX_M], value[MAX_N][9]; int no_of_bits(int n) { int count = 0; while(n) { count += (n%2); n /= 2; } return count; } int is_bit_set(int n, int bit) { return ( (n & (1 << bit)) != 0); } int main() { int no_of_elements, no_of_players, audience; cin >> no_of_elements >> no_of_players >> audience; vector < pair > A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i].first; A[i].second = i; } sort(all(A)); reverse(all(A)); for(int i = 1; i <= no_of_elements; i++) { for(int j = 0; j < no_of_players; j++) { cin >> value[i][j]; } } memset(max_till, -1, sizeof(max_till)); max_till[0][0] = 0; for(int i = 1; i <= no_of_elements; i++) { int index = A[i].second; //cout << "(" << A[i].first << "," << A[i].second << ")\n"; for(int m = 0; m < (1 << no_of_players); m++) { int players = no_of_bits(m); int audience_so_far = (i - 1) - players; if(players > i) { continue; } if(audience_so_far < audience) { if(max_till[i - 1][m] != -1) { //cout << "Audience = " << A[i].first << "\n"; max_till[i][m] = max_till[i - 1][m] + A[i].first; } } else { if(max_till[i - 1][m] != -1) { max_till[i][m] = max_till[i - 1][m]; } } for(int bit = 0; bit < no_of_players; bit++) { if(is_bit_set(m, bit) && max_till[i - 1][m^(1 << bit)] != -1) { //cout << "Choice is " << max_till[i][m] << " and " << value[index][bit] << " + " << max_till[i - 1][m^(1 << bit)] << "\n"; max_till[i][m] = max(max_till[i][m], value[index][bit] + max_till[i - 1][m^(1 << bit)]); } } //cout << "f(" << i << "," << m << ") = " << max_till[i][m] << "\n"; } } int total = (1 << no_of_players) - 1; cout << max_till[no_of_elements][total] << "\n"; return 0; } ================================================ FILE: 2020/Div 3/605 Div 3/Explanations/Nearly Opposite Parity.cpp ================================================ Let us divide these problems into two subproblems 1. Find the closest even integer to every odd integer 2. Find the closest odd integer to every even integer ----- Let us draw a 'reverse' graph. If it is possible to go from A[i] to A[j], we will draw a directed edge from A[i] to A[j] We will do Multi Source BFS with all the even integers as the sources and calculate the minimum distance to each A[i] ----- Then, we will do the same for all even integers void bfs(vector &A, vector &answer, int parity) { vector distance(A.size() + 1, oo); queue Q; for(int i = 1; i < A.size(); i++) { if(A[i]%2 != parity) { distance[i] = 0; Q.push(i); } } while(!Q.empty()) { int index = Q.front(); Q.pop(); for(int v = 0; v < graph[index].size(); v++) { int next = graph[index][v]; if(1 + distance[index] < distance[next]) { distance[next] = 1 + distance[index]; Q.push(next); } } } for(int i = 1; i < A.size(); i++) { if(A[i]%2 == parity) { answer[i] = (distance[i] == oo ? -1 : distance[i]); } } } ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; if(1 <= i - A[i]) { graph[i - A[i]].push_back(i); } if(i + A[i] <= no_of_elements) { graph[i + A[i]].push_back(i); } } vector answer(no_of_elements + 1, oo); bfs(A, answer, EVEN); bfs(A, answer, ODD); for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/605 Div 3/Explanations/Remove One Element Explanation.txt ================================================ We can solve this problem with DP // // main.cpp // Remove One Element // // Created by Saikat Ghosh on 13/12/19. // Copyright © 2019 Saikat Ghosh. All rights reserved. // #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int WITHOUT_DELETE = 0, WITH_DELETE = 1; vector > max_length_till(no_of_elements + 1, vector (2, 0)); max_length_till[1][WITHOUT_DELETE] = 1; max_length_till[1][WITH_DELETE] = 1; for(int i = 2; i <= no_of_elements; i++) { max_length_till[i][WITH_DELETE] = 1; max_length_till[i][WITHOUT_DELETE] = 1; if(i >= 1 && A[i] > A[i - 1]) { max_length_till[i][WITHOUT_DELETE] = max_length_till[i - 1][WITHOUT_DELETE] + 1; max_length_till[i][WITH_DELETE] = 1 + max_length_till[i - 1][WITH_DELETE]; } if(i >= 2 && A[i] > A[i - 2]) { max_length_till[i][WITH_DELETE] = max(max_length_till[i][WITH_DELETE], 1 + max_length_till[i - 2][WITHOUT_DELETE]); } } int answer = 0; for(int i = 1; i <= no_of_elements; i++) { int answer_here = max(max_length_till[i][WITHOUT_DELETE], max_length_till[i][WITH_DELETE]); answer = max(answer, answer_here); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/605 Div 3/Programs/Nearly Opposite Parity.cpp ================================================ #include #include #include using namespace std; const int ODD = 1, EVEN = 0, oo = 1e9, MAX_N = 2e5 + 5; vector graph[MAX_N]; void bfs(vector &A, vector &answer, int parity) { vector distance(A.size() + 1, oo); queue Q; for(int i = 1; i < A.size(); i++) { if(A[i]%2 != parity) { distance[i] = 0; Q.push(i); } } while(!Q.empty()) { int index = Q.front(); Q.pop(); for(int v = 0; v < graph[index].size(); v++) { int next = graph[index][v]; if(1 + distance[index] < distance[next]) { distance[next] = 1 + distance[index]; Q.push(next); } } } for(int i = 1; i < A.size(); i++) { if(A[i]%2 == parity) { answer[i] = (distance[i] == oo ? -1 : distance[i]); } } } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; if(1 <= i - A[i]) { graph[i - A[i]].push_back(i); } if(i + A[i] <= no_of_elements) { graph[i + A[i]].push_back(i); } } vector answer(no_of_elements + 1, oo); bfs(A, answer, EVEN); bfs(A, answer, ODD); for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/605 Div 3/Programs/Remove One Element.cpp ================================================ // // main.cpp // Remove One Element // // Created by Saikat Ghosh on 13/12/19. // Copyright © 2019 Saikat Ghosh. All rights reserved. // #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int WITHOUT_DELETE = 0, WITH_DELETE = 1; vector > max_length_till(no_of_elements + 1, vector (2, 0)); max_length_till[1][WITHOUT_DELETE] = 1; max_length_till[1][WITH_DELETE] = 1; for(int i = 2; i <= no_of_elements; i++) { max_length_till[i][WITH_DELETE] = 1; max_length_till[i][WITHOUT_DELETE] = 1; if(i >= 1 && A[i] > A[i - 1]) { max_length_till[i][WITHOUT_DELETE] = max_length_till[i - 1][WITHOUT_DELETE] + 1; max_length_till[i][WITH_DELETE] = 1 + max_length_till[i - 1][WITH_DELETE]; } if(i >= 2 && A[i] > A[i - 2]) { max_length_till[i][WITH_DELETE] = max(max_length_till[i][WITH_DELETE], 1 + max_length_till[i - 2][WITHOUT_DELETE]); } } int answer = 0; for(int i = 1; i <= no_of_elements; i++) { int answer_here = max(max_length_till[i][WITHOUT_DELETE], max_length_till[i][WITH_DELETE]); answer = max(answer, answer_here); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Explanations/Candies Division Explanation.txt ================================================ After giving everyone C/N number of candies, we will look at the remainder. We can only give (C/2) or (C mod N) candies - whichever is lesser. void solve() { int no_of_candies, no_of_kids; cin >> no_of_candies >> no_of_kids; int candies_given_to_one_kid = no_of_candies/no_of_kids; int candies_given = no_of_kids*candies_given_to_one_kid; no_of_candies %= no_of_kids; candies_given += min(no_of_candies, no_of_kids/2); cout << candies_given << "\n"; } ================================================ FILE: 2020/Div 3/611 Div 3/Explanations/Christmas Trees Explanation.txt ================================================ We will first look at all points which are at a distance 1 from a tree. Then, we will look at all points which are at a distance 2 from a tree. Then, we will look at all points which are at a distance 3 from a tree. This suggests BFS. We will insert all the Christmas trees as sources. After visiting a point, we will insert (x + 1) and (x - 1) into the queue if we have not already visited it. If we insert (x + 1) or (x - 1) after x, then d(x + 1) = d(x - 1) = d(x) + 1 This is the minimum distance to either (x + 1) or (x - 1). The reason is that we are performing BFS. If we had another path to (x + 1) or (x - 1) from y, and d(y) < d(x), then we would have visited y before we had visited x. ------ int main() { int no_of_trees, no_of_people; cin >> no_of_trees >> no_of_people; vector X(no_of_trees); for(int i = 0; i < no_of_trees; i++) { cin >> X[i]; } map distance; queue Q; for(int i = 0; i < no_of_trees; i++) { Q.push(X[i]); distance[X[i]] = 0; } long long total_distance = 0; vector people; while(!Q.empty() && people.size() < no_of_people) { int current = Q.front(); Q.pop(); if(distance[current] != 0) { total_distance += distance[current]; people.push_back(current); } if(distance.count(current + 1) == 0) { distance[current + 1] = distance[current] + 1; Q.push(current + 1); } if(distance.count(current - 1) == 0) { distance[current - 1] = distance[current] + 1; Q.push(current - 1); } } cout << total_distance << "\n"; for(int i = 0; i < no_of_people; i++) { cout << people[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Explanations/DIY Garland Explanation.txt ================================================ Let us make a few simple observations - 1. The first vertex is the root. 2. Leaves are the vertices which are never mentioned in the list. 3. If we have multiple leaves, then the leaf which has the greater number has their parent coming first. 4. If there is a situation where we must match a vertex to a leaf, we must choose the largest available leaf. 5. The i-th edge will start from the i-th vertex on the list. ------ When we are at vertex A[i], we know that cutting a wire from A[i] is more important than the wire from A[i + 1]. Having said that all the vertices affected by cutting the wire from A[i + 1] will also be effected by cutting the wire from A[i] if we draw an edge between A[i] and A[i + 1]. So, we will simply draw an edge between A[i] and A[i + 1] if we have not drawn an edge to A[i + 1] before. If we have, then we will simply connect A[i] to the largest leaf available at the time. ----- int main() { int no_of_lamps; cin >> no_of_lamps; vector index(no_of_lamps); for(int i = 1; i < no_of_lamps; i++) { cin >> index[i]; } vector used(no_of_lamps + 1, false); int root = index[1]; int current = no_of_lamps; cout << root << "\n"; for(int i = 1; i < no_of_lamps; i++) { used[index[i]] = true; while(used[current]) { current--; } if(i == no_of_lamps - 1 || used[index[i + 1]]) { cout << index[i] << " " << current << "\n"; used[current] = true; } else { cout << index[i] << " " << index[i + 1] << "\n"; } } return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Explanations/Friends and Gifts Explanation.txt ================================================ Let us draw a graph to represent the permutation. Each vertex should have exactly 1 edge coming in and exactly 1 edge coming out. After we draw the graph, there will be some vertices which are isolated. If there are no isolated vertices, then we are good. If there is one isolated vertex, we will draw an edge from here to so me other vertex which does not have an incoming edge. (There have to be n incoming and n outgoing edges. If 1 vertex does not have an outgoing edge, it means some other vertex does not have an incoming edge.) If there are more than one isolated vertices, then we will create a cycle with them. After we are done, there will be some vertices which don't have an incoming edge and some vertices which don't have an outgoing edge, but not both. (As we already took care of the isolated vertices.) ----- By our previous proof, they will be equal in number and we will just match them. ----- int main() { int no_of_friends; cin >> no_of_friends; vector A(no_of_friends + 1); for(int i = 1; i <= no_of_friends; i++) { cin >> A[i]; } vector indegree(no_of_friends + 1); vector outdegree(no_of_friends + 1); for(int i = 1; i <= no_of_friends; i++) { if(A[i] != 0) { indegree[A[i]]++; outdegree[i]++; } } vector isolated_vertices; for(int i = 1; i <= no_of_friends; i++) { if(indegree[i] == 0 && outdegree[i] == 0) { isolated_vertices.push_back(i); } } if(isolated_vertices.size() == 1) { int v = isolated_vertices[0]; for(int i = 1; i <= no_of_friends; i++) { if(indegree[i] == 0 && i != v) { A[v] = i; indegree[i]++; outdegree[v]++; break; } } } else if(isolated_vertices.size() > 1) { for(int i = 0; i < isolated_vertices.size(); i++) { int u = isolated_vertices[i], v = isolated_vertices[(i + 1)%isolated_vertices.size()]; A[u] = v; indegree[v]++; outdegree[u]++; } } vector empty_in; vector empty_out; for(int i = 1; i <= no_of_friends; i++) { if(indegree[i] == 0) { empty_in.push_back(i); } if(outdegree[i] == 0) { empty_out.push_back(i); } } for(int i = 0; i < empty_out.size(); i++) { int u = empty_out[i], v = empty_in[i]; A[u] = v; } for(int i = 1; i <= no_of_friends; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Explanations/Minutes Before the New Year Explanation.txt ================================================ We will calculate the number of minutes left. void solve() { int hours, minutes; cin >> hours >> minutes; const int MAX_HOUR = 23, MAX_MINUTE = 60; int remaining_minutes = 60*(MAX_HOUR - hours) + (MAX_MINUTE - minutes); cout << remaining_minutes << "\n"; } ================================================ FILE: 2020/Div 3/611 Div 3/Explanations/New Year Parties Explanation.txt ================================================ Let us divide the problem into two subproblems - Maximizing and Minimizing ----- I solved the Maximising problem using Greedy. The idea is that we will make each element as small as possible. int maximise_houses(int n, vector X) { set S; for(int i = 1; i <= n; i++) { if(S.find(X[i] - 1) == S.end()) { S.insert(X[i] - 1); } else if(S.find(X[i]) == S.end()) { S.insert(X[i]); } else if(S.find(X[i] + 1) == S.end()) { S.insert(X[i] + 1); } } return S.size(); } ----- I solved the minimizing problems using a DP. There is also a Greedy solution int minimise_houses(int n, vector X) { vector > minimum_houses(n + 1, vector (4, 0)); const int BACKWARD = 0, SAME = 1, FORWARD = 2; for(int i = 1; i <= n; i++) { if(i == 1) { minimum_houses[i][BACKWARD] = minimum_houses[i][SAME] = minimum_houses[i][FORWARD] = 1; //continue; } else if(X[i - 1] < X[i] - 2) { minimum_houses[i][BACKWARD] = minimum_houses[i][SAME] = minimum_houses[i][FORWARD] = 1 + min_3(minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); //continue; } else if(X[i - 1] + 1 == X[i] - 1) { minimum_houses[i][BACKWARD] = min_3(minimum_houses[i - 1][FORWARD], 1 + minimum_houses[i - 1][SAME], 1 + minimum_houses[i - 1][BACKWARD]); minimum_houses[i][SAME] = minimum_houses[i][FORWARD] = 1 + min_3(minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); //continue; } else if(X[i - 1] + 1 == X[i]) { minimum_houses[i][BACKWARD] = min_3(1 + minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], 1 + minimum_houses[i - 1][FORWARD]); minimum_houses[i][SAME] = min_3(1 + minimum_houses[i - 1][BACKWARD], 1 + minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); minimum_houses[i][FORWARD] = 1 + min_3(minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); //continue; } else if(X[i - 1] == X[i]) { minimum_houses[i][BACKWARD] = minimum_houses[i - 1][BACKWARD]; minimum_houses[i][SAME] = minimum_houses[i - 1][SAME]; minimum_houses[i][FORWARD] = minimum_houses[i - 1][FORWARD]; //continue; } } return min_3(minimum_houses[n][BACKWARD], minimum_houses[n][SAME], minimum_houses[n][FORWARD]); } ================================================ FILE: 2020/Div 3/611 Div 3/Programs/Candies Division.cpp ================================================ #include using namespace std; void solve() { int no_of_candies, no_of_kids; cin >> no_of_candies >> no_of_kids; int candies_given_to_one_kid = no_of_candies/no_of_kids; int candies_given = no_of_kids*candies_given_to_one_kid; no_of_candies %= no_of_kids; candies_given += min(no_of_candies, no_of_kids/2); cout << candies_given << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Programs/Christmas Trees.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_trees, no_of_people; cin >> no_of_trees >> no_of_people; vector X(no_of_trees); for(int i = 0; i < no_of_trees; i++) { cin >> X[i]; } map distance; queue Q; for(int i = 0; i < no_of_trees; i++) { Q.push(X[i]); distance[X[i]] = 0; } long long total_distance = 0; vector people; while(!Q.empty() && people.size() < no_of_people) { int current = Q.front(); Q.pop(); if(distance[current] != 0) { total_distance += distance[current]; people.push_back(current); } if(distance.count(current + 1) == 0) { distance[current + 1] = distance[current] + 1; Q.push(current + 1); } if(distance.count(current - 1) == 0) { distance[current - 1] = distance[current] + 1; Q.push(current - 1); } } cout << total_distance << "\n"; for(int i = 0; i < no_of_people; i++) { cout << people[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Programs/DIY Garland.cpp ================================================ #include #include using namespace std; int main() { int no_of_lamps; cin >> no_of_lamps; vector index(no_of_lamps); for(int i = 1; i < no_of_lamps; i++) { cin >> index[i]; } vector used(no_of_lamps + 1, false); int root = index[1]; int current = no_of_lamps; cout << root << "\n"; for(int i = 1; i < no_of_lamps; i++) { used[index[i]] = true; while(used[current]) { current--; } if(i == no_of_lamps - 1 || used[index[i + 1]]) { cout << index[i] << " " << current << "\n"; used[current] = true; } else { cout << index[i] << " " << index[i + 1] << "\n"; } } return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Programs/Friends and Gifts.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_friends; cin >> no_of_friends; vector A(no_of_friends + 1); for(int i = 1; i <= no_of_friends; i++) { cin >> A[i]; } vector indegree(no_of_friends + 1); vector outdegree(no_of_friends + 1); for(int i = 1; i <= no_of_friends; i++) { if(A[i] != 0) { indegree[A[i]]++; outdegree[i]++; } } vector isolated_vertices; for(int i = 1; i <= no_of_friends; i++) { if(indegree[i] == 0 && outdegree[i] == 0) { isolated_vertices.push_back(i); } } if(isolated_vertices.size() == 1) { int v = isolated_vertices[0]; for(int i = 1; i <= no_of_friends; i++) { if(indegree[i] == 0 && i != v) { A[v] = i; indegree[i]++; outdegree[v]++; break; } } } else if(isolated_vertices.size() > 1) { for(int i = 0; i < isolated_vertices.size(); i++) { int u = isolated_vertices[i], v = isolated_vertices[(i + 1)%isolated_vertices.size()]; A[u] = v; indegree[v]++; outdegree[u]++; } } vector empty_in; vector empty_out; for(int i = 1; i <= no_of_friends; i++) { if(indegree[i] == 0) { empty_in.push_back(i); } if(outdegree[i] == 0) { empty_out.push_back(i); } } for(int i = 0; i < empty_out.size(); i++) { int u = empty_out[i], v = empty_in[i]; A[u] = v; } for(int i = 1; i <= no_of_friends; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Programs/Minutes Before the New Year.cpp ================================================ #include using namespace std; void solve() { int hours, minutes; cin >> hours >> minutes; const int MAX_HOUR = 23, MAX_MINUTE = 60; int remaining_minutes = 60*(MAX_HOUR - hours) + (MAX_MINUTE - minutes); cout << remaining_minutes << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/611 Div 3/Programs/New Year Parties.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int min_3(int a, int b, int c) { return min(a, min(b, c)); } int maximise_houses(int n, vector X) { set S; for(int i = 1; i <= n; i++) { if(S.find(X[i] - 1) == S.end()) { S.insert(X[i] - 1); } else if(S.find(X[i]) == S.end()) { S.insert(X[i]); } else if(S.find(X[i] + 1) == S.end()) { S.insert(X[i] + 1); } } return S.size(); } int minimise_houses(int n, vector X) { vector > minimum_houses(n + 1, vector (4, 0)); const int BACKWARD = 0, SAME = 1, FORWARD = 2; for(int i = 1; i <= n; i++) { if(i == 1) { minimum_houses[i][BACKWARD] = minimum_houses[i][SAME] = minimum_houses[i][FORWARD] = 1; //continue; } else if(X[i - 1] < X[i] - 2) { minimum_houses[i][BACKWARD] = minimum_houses[i][SAME] = minimum_houses[i][FORWARD] = 1 + min_3(minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); //continue; } else if(X[i - 1] + 1 == X[i] - 1) { minimum_houses[i][BACKWARD] = min_3(minimum_houses[i - 1][FORWARD], 1 + minimum_houses[i - 1][SAME], 1 + minimum_houses[i - 1][BACKWARD]); minimum_houses[i][SAME] = minimum_houses[i][FORWARD] = 1 + min_3(minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); //continue; } else if(X[i - 1] + 1 == X[i]) { minimum_houses[i][BACKWARD] = min_3(1 + minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], 1 + minimum_houses[i - 1][FORWARD]); minimum_houses[i][SAME] = min_3(1 + minimum_houses[i - 1][BACKWARD], 1 + minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); minimum_houses[i][FORWARD] = 1 + min_3(minimum_houses[i - 1][BACKWARD], minimum_houses[i - 1][SAME], minimum_houses[i - 1][FORWARD]); //continue; } else if(X[i - 1] == X[i]) { minimum_houses[i][BACKWARD] = minimum_houses[i - 1][BACKWARD]; minimum_houses[i][SAME] = minimum_houses[i - 1][SAME]; minimum_houses[i][FORWARD] = minimum_houses[i - 1][FORWARD]; //continue; } } return min_3(minimum_houses[n][BACKWARD], minimum_houses[n][SAME], minimum_houses[n][FORWARD]); } int main() { int no_of_friends; cin >> no_of_friends; vector X(no_of_friends + 1); for(int i = 1; i <= no_of_friends; i++) { cin >> X[i]; } sort(all(X)); int minimum_houses = minimise_houses(no_of_friends, X); int maximum_houses = maximise_houses(no_of_friends, X); cout << minimum_houses << " " << maximum_houses << "\n"; return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Explanations/Collecting Coins Explanation.txt ================================================ The total number of coins is (a + b + c + n). At the end, every group must have T/3 coins. We must ensure that T is divisible by 3 and then that each group has less than T/3 coins. void solve() { int a, b, c, n; cin >> a >> b >> c >> n; int total = (a + b + c) + n; cout << (total%3 == 0 && a <= total/3 && b <= total/3 && c <= total/3 ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 3/615 Div 3/Explanations/Collecting Packages Explanation.txt ================================================ We will visit the points in order of their x's. For a given x, we must visit the points in ascending order of y's. As we are only allowed to go up, we have to ensure that the y's also only go up as we go from 1 x to another. 1. Sort the points by their X 2. For each X, sort the points by their Y 3. Check if the Y's are in non-decreasing order as we go from one Y to another. ----- int sort_by_x(point &P, point &Q) { if(P.x == Q.x) { return (P.y < Q.y); } return (P.x < Q.x); } void solve() { int no_of_points; cin >> no_of_points; vector P(no_of_points); for(int i = 0; i < no_of_points; i++) { cin >> P[i].x >> P[i].y; } sort(all(P), sort_by_x); int y_is_sorted = true; for(int i = 1; i < no_of_points; i++) { if(P[i - 1].y > P[i].y) { y_is_sorted = false; break; } } if(!y_is_sorted) { cout << "NO\n"; return; } string answer; for(int x = 0, y = 0, i = 0; i < no_of_points; i++) { while(x != P[i].x) {//cout << "Right\n" << answer << "\n"; answer += "R"; x++; } while(y != P[i].y) { //cout << "Up\n" << answer << "\n"; answer += "U"; y++; } } cout << "YES\n"; cout << answer << "\n"; } ================================================ FILE: 2020/Div 3/615 Div 3/Explanations/MEX Maximising Explanation.txt ================================================ 1. We can only add or subtract x from A[i]. So A[i] (mod x) is invariant. 2. We will 'spread' out the A[i]'s across each mod. Suppose A[i] = 1 (mod x). Suppose, we have already have (1, x + 1, 2x + 1). We will give A[i] the value = 3x + 1. We will greedily give A[i] the smallest untaken value. ----- This ensures that we are maximising the Mex at each step because we are taking the smallest untaken number we can at each step. ---- To calculate the Mex, we can have another loop. Although it looks like it is O(N^2), it is not because the loops are independent. ----- int main() { long long no_of_operations, x; cin >> no_of_operations >> x; map is_present; map last; int mex = 0; for(int i = 1; i <= no_of_operations; i++) { long long current; cin >> current; current %= x; is_present[x*last[current] + current] = true; last[current]++; while(is_present[mex]) { mex++; } cout << mex << "\n"; } return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Explanations/Obtain a Permutation Explanation.txt ================================================ The column of any element is invariant across all operations. Every element will stay in it's column. ----- Let us find the number of moves for each column seperately. Now, how do we find out the minimum number of moves for a given column ? Let us calculate the number of moves for each rotation from 1 to N. We will then select the rotation that minimises the number of moves. A given column i, will have all elements = i (mod M) ----- Now we will see how to count the number of moves for i rotations. We will do i moves - Rotations We just have to count the number of Changing moves. We can do it like this - for(int r = 0; r < rows; r++) { operations[r] = r; for(int i = 1; i <= rows; i++) { int expected = (i - 1)*columns + columns; int actual = A[ (i + r)mod rows + 1][j]; if(expected != actual) operations[r]++ } } Basically, what we are doing is counting the number of operations for each rotation. But, this is O(MN) for each column. We can make a beautiful observation to make it O(M) for each iteration ! ----- Now, here is what we will observe. A[i][j] will be correct only for at most ONE rotation. This is because the element at spot (i, j) is fixed. A[i][j] will fall into the correct spot in only one spot ! So, we will initially assume, rotation r will cost (r + N). Then, we will go through all N elements and decrement the cost only on it's best rotation. The code is given below ----- long long ceil(long long n, long long d) { return (n/d + (n%d != 0)); } long long calculate_best_cost(int column_no) { vector rotation_cost(rows + 1, 0); for(int rotations = 0; rotations < rows; rotations++) { rotation_cost[rotations] = rotations + rows; //cout << "Cost " << rotations << " = " << rotation_cost[rotations] << "\n"; } for(int i = 1; i <= rows; i++) { if(A[i][column_no]%columns != column_no%columns) { continue; } int best_place = ceil(A[i][column_no], columns); if(best_place > rows) { continue; } int best_rotation; if(best_place <= i) { best_rotation = (i - best_place); } else { best_rotation = (i - 1) + (rows - best_place + 1); } //cout << i << " " << column_no << " Best place = " << best_place << " " << best_rotation << "\n"; rotation_cost[best_rotation]--; //cout << "Cost of " << best_rotation << " = " << rotation_cost[best_rotation] << "\n"; } long long best_cost = rotation_cost[0]; for(int rotations = 1; rotations < rows; rotations++) { best_cost = min(best_cost, rotation_cost[rotations]); } //cout << "Column " << column_no << " = " << best_cost << "\n"; return best_cost; } ================================================ FILE: 2020/Div 3/615 Div 3/Explanations/Product of Three Numbers Explanation.txt ================================================ Let us look at the prime factorisation of N. Case 1 - N has >= 3 prime factors Then, a = p1, b = p2, c = N/(p1p2) c will have a term of p3 in it which is not there in a or b so it cannot be equal ------ Case 2 - N has 2 prime factors Case 2a - One of p1, p2 has exponent > 2 Let it be p2 a = p1, b = p2, c = N/(p1p2) As Exp(p2) > 2, the Exponent of p2 in c will be more than 1. This ensures that c will not be equal to b Case 2b - p1 = p2 = 2 Then, a = p1, b = p2, c = N/(p1p2) Case 2c - One of p1, p2 = 1 and the other is 2 If only one of them has exponent 2, it is not possible as a = p1, b = p2, c = N/(p1p2) and c will be equal to one of (a, b) Case 2d - Both p1, p2 have exponent 1 If they both have exponent = 1, it is not possible. It is possible everywhere other than when min(p1, p2) = 1 and max(p1, p2) <= 2 ------ Case 3 - N has 1 prime factor a = p1, b = p1^2, c = p1^3 (at least) It is not possible if the exponent is less than 6 ------ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void factorise(int n, vector &P, vector &E) { for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { int exponent = 0; while(n%i == 0) { n /= i; exponent++; } P.push_back(i); E.push_back(exponent); } } if(n > 1) { P.push_back(n); E.push_back(1); } } void solve() { int n; cin >> n; vector primes; vector exponents; factorise(n, primes, exponents); if(primes.size() >= 3) { cout << "YES\n"; cout << primes[0] << " " << primes[1] << " " << n/(primes[0]*primes[1]) << "\n"; return; } if(primes.size() == 1) { if(exponents[0] < 6) { cout << "NO\n"; return; } long long f1 = primes[0], f2 = primes[0]*primes[0]; cout << "YES\n"; cout << f1 << " " << f2 << " " << n/(f1*f2) << "\n"; return; } if(primes.size() == 2) { if(min(exponents[0], exponents[1]) == 1 && max(exponents[0], exponents[1]) <= 2) { cout << "NO\n"; return; } cout << "YES\n"; cout << primes[0] << " " << primes[1] << " " << n/(primes[0]*primes[1]) << "\n"; return; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Explanations/Three Paths on a Tree Explanation.txt ================================================ The problem is to find the triameter of a tree. Here is what we will do. We will first find the diamter of the tree. We can do this by the following way - 1. Start from the root and go as far as possible using DFS. Let the point with the furthest depth be a. 2. Start from a and do another DFS and go as far as possible. Let the point with the furthest depth be b. a-b is the diamater of the tree. ----- Now, how to find the third point ? For every vertex in the graph, we have to calculate the distance to the diameter. To do this, we will first store all the vertices of the diameter in a Queue. Then, we will perform multi source BFS. This will help us in calculating the distance from the diameter to every vertex in the tree. ----- #include #include #include using namespace std; const int MAX_L = 23, MAX_N = 2e5 + 5, oo = 1e9; vector tree[MAX_N]; int parent[MAX_N][MAX_L], depth[MAX_N]; vector lies_on_diameter(MAX_N, false); int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0) ; } void dfs(int v, int parent_v) { depth[v] = depth[parent_v] + 1; parent[v][0] = parent_v; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); } } int dfs_diameter(int v, int parent_v, int destination) { if(v == destination) { lies_on_diameter[v] = true; return true; } for(int i = 0; i < tree[v].size(); i++) { int child = tree[v][i]; if(child == parent_v) { continue; } if(dfs_diameter(child, v, destination)) { lies_on_diameter[v] = true; return true; } } return false; } void precompute_parents(int no_of_vertices) { for(int l = 1; l < MAX_L; l++) { for(int i = 1; i <= no_of_vertices; i++) { int ancestor = parent[i][l - 1]; parent[i][l] = parent[ancestor][l - 1]; } } } int LCA(int u, int v) { if(depth[v] < depth[u]) { swap(u, v); } int difference = depth[v] - depth[u]; for(int i = MAX_L - 1; i >= 0; i--) { if(is_bit_set(difference, i)) { v = parent[v][i]; } } if(u == v) { return u; } for(int i = MAX_L - 1; i >= 0; i--) { if(parent[u][i] != parent[v][i]) { u = parent[u][i]; v = parent[v][i]; } } return parent[u][0]; } int tree_distance(int u, int v) { return (depth[u] + depth[v] - 2*depth[LCA(u, v)]); } int main() { int no_of_vertices; cin >> no_of_vertices; int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } depth[0] = 0; dfs(1, 0); precompute_parents(no_of_vertices); int max_depth = 0; int a = 1, b = 1, c = 1; for(int v = 1; v <= no_of_vertices; v++) { if(depth[v] > max_depth) { max_depth = depth[v]; b = v; } } int edges_covered = 0; for(int i = 1; i <= no_of_vertices; i++) { if(tree_distance(i, b) > edges_covered) { edges_covered = tree_distance(i, b); a = i; //cout << "a = " << a << " and distance = " << edges_covered << "\n"; } } dfs_diameter(a, 0, b); queue Q; vector distance(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { if(lies_on_diameter[i]) { Q.push(i); distance[i] = 0; } else { distance[i] = oo; } } int new_edges = -1; while(!Q.empty()) { int v = Q.front(); Q.pop(); if(distance[v] > new_edges && v != a && v != b) { new_edges = distance[v]; c = v; } for(int i = 0; i < tree[v].size(); i++) { int child = tree[v][i]; if(distance[child] > distance[v] + 1) { distance[child] = distance[v] + 1; Q.push(child); } } } edges_covered += new_edges; cout << edges_covered << "\n"; cout << a << " " << b << " " << c << "\n"; return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Programs/Collecting Coins.cpp ================================================ #include using namespace std; void solve() { int a, b, c, n; cin >> a >> b >> c >> n; int total = (a + b + c) + n; cout << (total%3 == 0 && a <= total/3 && b <= total/3 && c <= total/3 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Programs/Collecting Packages.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct point { int x, y; point(){}; }; int sort_by_x(point &P, point &Q) { if(P.x == Q.x) { return (P.y < Q.y); } return (P.x < Q.x); } void solve() { int no_of_points; cin >> no_of_points; vector P(no_of_points); for(int i = 0; i < no_of_points; i++) { cin >> P[i].x >> P[i].y; } sort(all(P), sort_by_x); int y_is_sorted = true; for(int i = 1; i < no_of_points; i++) { if(P[i - 1].y > P[i].y) { y_is_sorted = false; break; } } if(!y_is_sorted) { cout << "NO\n"; return; } string answer; for(int x = 0, y = 0, i = 0; i < no_of_points; i++) { while(x != P[i].x) {//cout << "Right\n" << answer << "\n"; answer += "R"; x++; } while(y != P[i].y) { //cout << "Up\n" << answer << "\n"; answer += "U"; y++; } } cout << "YES\n"; cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Programs/MEX Maximising.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { long long no_of_operations, x; cin >> no_of_operations >> x; map is_present; map last; int mex = 0; for(int i = 1; i <= no_of_operations; i++) { long long current; cin >> current; current %= x; is_present[x*last[current] + current] = true; last[current]++; while(is_present[mex]) { mex++; } cout << mex << "\n"; } return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Programs/Obtain a Permutation.cpp ================================================ #include #include using namespace std; int rows, columns; vector > A; long long ceil(long long n, long long d) { return (n/d + (n%d != 0)); } long long calculate_best_cost(int column_no) { vector rotation_cost(rows + 1, 0); for(int rotations = 0; rotations < rows; rotations++) { rotation_cost[rotations] = rotations + rows; //cout << "Cost " << rotations << " = " << rotation_cost[rotations] << "\n"; } for(int i = 1; i <= rows; i++) { if(A[i][column_no]%columns != column_no%columns) { continue; } int best_place = ceil(A[i][column_no], columns); if(best_place > rows) { continue; } int best_rotation; if(best_place <= i) { best_rotation = (i - best_place); } else { best_rotation = (i - 1) + (rows - best_place + 1); } //cout << i << " " << column_no << " Best place = " << best_place << " " << best_rotation << "\n"; rotation_cost[best_rotation]--; //cout << "Cost of " << best_rotation << " = " << rotation_cost[best_rotation] << "\n"; } long long best_cost = rotation_cost[0]; for(int rotations = 1; rotations < rows; rotations++) { best_cost = min(best_cost, rotation_cost[rotations]); } //cout << "Column " << column_no << " = " << best_cost << "\n"; return best_cost; } int main() { cin >> rows >> columns; A.resize(rows + 1); for(int i = 0; i <= rows; i++) { A[i].resize(columns + 1); } for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { cin >> A[i][j]; } } long long moves = 0; for(int i = 1; i <= columns; i++) { moves += calculate_best_cost(i); } cout << moves << "\n"; return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Programs/Paths on a Tree.cpp ================================================ #include #include #include using namespace std; const int MAX_L = 23, MAX_N = 2e5 + 5, oo = 1e9; vector tree[MAX_N]; int parent[MAX_N][MAX_L], depth[MAX_N]; vector lies_on_diameter(MAX_N, false); int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0) ; } void dfs(int v, int parent_v) { depth[v] = depth[parent_v] + 1; parent[v][0] = parent_v; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); } } int dfs(int v, int parent_v, int destination) { if(v == destination) { lies_on_diameter[v] = true; return true; } for(int i = 0; i < tree[v].size(); i++) { int child = tree[v][i]; if(child == parent_v) { continue; } if(dfs(child, v, destination)) { lies_on_diameter[v] = true; return true; } } return false; } void precompute_parents(int no_of_vertices) { for(int l = 1; l < MAX_L; l++) { for(int i = 1; i <= no_of_vertices; i++) { int ancestor = parent[i][l - 1]; parent[i][l] = parent[ancestor][l - 1]; } } } int LCA(int u, int v) { if(depth[v] < depth[u]) { swap(u, v); } int difference = depth[v] - depth[u]; for(int i = MAX_L - 1; i >= 0; i--) { if(is_bit_set(difference, i)) { v = parent[v][i]; } } if(u == v) { return u; } for(int i = MAX_L - 1; i >= 0; i--) { if(parent[u][i] != parent[v][i]) { u = parent[u][i]; v = parent[v][i]; } } return parent[u][0]; } int tree_distance(int u, int v) { return (depth[u] + depth[v] - 2*depth[LCA(u, v)]); } int main() { int no_of_vertices; cin >> no_of_vertices; int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } depth[0] = 0; dfs(1, 0); precompute_parents(no_of_vertices); int max_depth = 0; int a = 1, b = 1, c = 1; for(int v = 1; v <= no_of_vertices; v++) { if(depth[v] > max_depth) { max_depth = depth[v]; b = v; } } int edges_covered = 0; for(int i = 1; i <= no_of_vertices; i++) { if(tree_distance(i, b) > edges_covered) { edges_covered = tree_distance(i, b); a = i; //cout << "a = " << a << " and distance = " << edges_covered << "\n"; } } dfs(a, 0, b); queue Q; vector distance(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { if(lies_on_diameter[i]) { Q.push(i); distance[i] = 0; } else { distance[i] = oo; } } int new_edges = -1; while(!Q.empty()) { int v = Q.front(); Q.pop(); if(distance[v] > new_edges && v != a && v != b) { new_edges = distance[v]; c = v; } for(int i = 0; i < tree[v].size(); i++) { int child = tree[v][i]; if(distance[child] > distance[v] + 1) { distance[child] = distance[v] + 1; Q.push(child); } } } edges_covered += new_edges; cout << edges_covered << "\n"; cout << a << " " << b << " " << c << "\n"; return 0; } ================================================ FILE: 2020/Div 3/615 Div 3/Programs/Product of Three Numbers.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void factorise(int n, vector &P, vector &E) { for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { int exponent = 0; while(n%i == 0) { n /= i; exponent++; } P.push_back(i); E.push_back(exponent); } } if(n > 1) { P.push_back(n); E.push_back(1); } } void solve() { int n; cin >> n; vector primes; vector exponents; factorise(n, primes, exponents); if(primes.size() >= 3) { cout << "YES\n"; cout << primes[0] << " " << primes[1] << " " << n/(primes[0]*primes[1]) << "\n"; return; } if(primes.size() == 1) { if(exponents[0] < 6) { cout << "NO\n"; return; } long long f1 = primes[0], f2 = primes[0]*primes[0]; cout << "YES\n"; cout << f1 << " " << f2 << " " << n/(f1*f2) << "\n"; return; } if(primes.size() == 2) { if(min(exponents[0], exponents[1]) == 1 && max(exponents[0], exponents[1]) <= 2) { cout << "NO\n"; return; } cout << "YES\n"; cout << primes[0] << " " << primes[1] << " " << n/(primes[0]*primes[1]) << "\n"; return; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Explanations/Array with Odd Sum Explanation.txt ================================================ If there are an odd number of odd numbers, then the sum is odd If there are an even number of odd numbers and there is at least one even number, we can make the even number odd and get an odd sum If there are no odd numbers, the sum will always be even ----- void solve() { int no_of_elements; cin >> no_of_elements; int odd_count = 0; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; odd_count += (x%2 == 1); } cout << ((odd_count%2 == 1) || (odd_count > 0 && odd_count%2 == 0 && odd_count != no_of_elements) ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 3/617 Div 3/Explanations/Fight with Monsters Explanation.txt ================================================ 1. We will let the moves go as they are intended. 2. Subtract H[i] by a, then subtract H[i] by b. Then again by a, then by b and so on. 3. If the last move was done by a, then we don't need to do anything. If the last move was done by b, then we can use a's in the intended ------ We can deal with H[i] mod(a + b) 1. We will write H[i] = H[i] mod (a + b) 2. If H[i] = 0 mod(a + b), then we will write H[i] = (a + b) 3. We will subtract a from H[i] If H[i] > 0, then we will calculate the number of moves required for a to make this 0 We will calculate the number of moves required for each element. ------ We know the number of steps required for each of the N elements. We have an array S We must maximise the number of elements chosen such that the sum is <= k We can do this by sorting S and then taking the smallest elements. ------ int main() { int no_of_elements, attack, opponent_attack, secrets; cin >> no_of_elements >> attack >> opponent_attack >> secrets; vector H(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> H[i]; } vector skips_required(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { H[i] %= (attack + opponent_attack); if(H[i] == 0) { H[i] = (attack + opponent_attack); } H[i] = max(H[i] - attack, 0); skips_required[i] = ceil(H[i], attack); } sort(skips_required.begin(), skips_required.end()); long long total_skips = 0, points = 0; for(int i = 1; i <= no_of_elements; i++) { if(total_skips + skips_required[i] > secrets) { break; } total_skips += skips_required[i]; points++; } cout << points << "\n"; return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Explanations/Food Buying Explanation.txt ================================================ We can just be greedy and simulate the problem. We will use 10(X/10) coins. We will get (X/10) extra coins We will repeat the same with the (X/10) coins that we have now and keep doing this until we have at least 10 coins ----- void solve() { int budget; cin >> budget; long long no_of_moves = 0; while(budget >= 10) { long long move = budget/10; budget = budget - 10*move + move; no_of_moves += 10*move; } no_of_moves += budget; cout << no_of_moves << "\n"; } ================================================ FILE: 2020/Div 3/617 Div 3/Explanations/String Colouring (Easy Version) Explanation.txt ================================================ Let us make an observation For every character S[j] that comes after S[i], If S[j] > S[i], S[j] will have to meet S[i] at some point. We need to draw an edge between all pairs (i, j) such that (i < j) and (S[i] > S[j]) and then check for bipartite matching. We can do this in O(n^2) time. We will colour a point red if it is uncoloured and then colour all it's neighbours blue. If any of it's neighbours is forced to be red, then it is not possible. ----- int main() { int length; string S; cin >> length >> S; vector colour(length, UNCOLOURED); for(int i = 0; i < length; i++) { if(colour[i] == UNCOLOURED) { colour[i] = RED; } for(int j = i + 1; j < length; j++) { if(S[j] < S[i] && colour[j] == UNCOLOURED) { colour[j] = other(colour[i]); continue; } if(S[j] < S[i] && colour[i] == colour[j]) { cout << "NO\n"; return 0; } } } cout << "YES\n"; for(int i = 0; i < length; i++) { cout << colour[i]; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Explanations/String Colouring (Hard Version) Explanation.txt ================================================ There is a theorem called Dilworth's Theorem. It can be applied here. We have to count the minimum number of non-decreasing sequences in this array. This is equal to the length of the longest non-increasing sequence in the array. We will calculate the length of the longest non-increasing sequence. As the size of the alphabet is small, we can do it in O(26N) time. ----- int main() { int length; string S; cin >> length >> S; const int NO_OF_ALPHABETS = 26; vector max_till(NO_OF_ALPHABETS); vector sequence_no(length, 1); int no_of_sequences = 0; for(int i = 0; i < length; i++) { for(int alpha = S[i] - 'a' + 1; alpha < NO_OF_ALPHABETS; alpha++) { sequence_no[i] = max(sequence_no[i], max_till[alpha] + 1); } max_till[S[i] - 'a'] = max(max_till[S[i] - 'a'], sequence_no[i]); no_of_sequences = max(no_of_sequences, sequence_no[i]); } cout << no_of_sequences << "\n"; for(int i = 0; i < length; i++) { cout << sequence_no[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Explanations/Yet Another Walking Robot Explanation.txt ================================================ We will keep track of (x, y) at every stage. Suppose we have done i steps and are at (x, y) and we were at (x, y) at step p too. Then, [p + 1, i] is a substring we can remove. For every i, we will check which was the last point at which we were at (x, y) Accordingly, we will check the size of the segment [L, R] and check if it is the smallest segment we have encountered so far ----- void solve() { int length; string S; cin >> length >> S; map , int> position; int minimum_distance = length + 1, left = 0, right = length + 1; position[make_pair(0, 0)] = -1; for(int x = 0, y = 0, i = 0; i < length; i++) { switch(S[i]) { case 'L' : x++; break; case 'R' : x--; break; case 'U' : y++; break; case 'D' : y--; break; } if(position.count(make_pair(x, y)) != 0) { int last_i = position[make_pair(x, y)] + 1; int distance = (i) - (last_i - 1); if(distance < minimum_distance) { minimum_distance = distance; left = last_i ; right = i; } } position[make_pair(x, y)] = i; } if(minimum_distance > length) { cout << "-1\n"; return; } cout << left + 1 << " " << right + 1 << "\n"; } ================================================ FILE: 2020/Div 3/617 Div 3/Programs/Array with Odd Sum.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; int odd_count = 0; for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; odd_count += (x%2 == 1); } cout << ((odd_count%2 == 1) || (odd_count > 0 && odd_count%2 == 0 && odd_count != no_of_elements) ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Programs/Fight with Monsters.cpp ================================================ #include #include #include using namespace std; int ceil(int a, int b) { return (a/b) + (a%b != 0); } int main() { int no_of_elements, attack, opponent_attack, secrets; cin >> no_of_elements >> attack >> opponent_attack >> secrets; vector H(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> H[i]; } vector skips_required(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { H[i] %= (attack + opponent_attack); if(H[i] == 0) { H[i] = (attack + opponent_attack); } H[i] = max(H[i] - attack, 0); skips_required[i] = ceil(H[i], attack); } sort(skips_required.begin(), skips_required.end()); long long total_skips = 0, points = 0; for(int i = 1; i <= no_of_elements; i++) { if(total_skips + skips_required[i] > secrets) { break; } total_skips += skips_required[i]; points++; } cout << points << "\n"; return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Programs/Food Buying.cpp ================================================ #include #include using namespace std; void solve() { int budget; cin >> budget; long long no_of_moves = 0; while(budget >= 10) { long long move = budget/10; budget = budget - 10*move + move; no_of_moves += 10*move; } no_of_moves += budget; cout << no_of_moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Programs/String Coloring (Hard Version).cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; const int NO_OF_ALPHABETS = 26; vector max_till(NO_OF_ALPHABETS); vector sequence_no(length, 1); int no_of_sequences = 0; for(int i = 0; i < length; i++) { for(int alpha = S[i] - 'a' + 1; alpha < NO_OF_ALPHABETS; alpha++) { sequence_no[i] = max(sequence_no[i], max_till[alpha] + 1); } max_till[S[i] - 'a'] = max(max_till[S[i] - 'a'], sequence_no[i]); no_of_sequences = max(no_of_sequences, sequence_no[i]); } cout << no_of_sequences << "\n"; for(int i = 0; i < length; i++) { cout << sequence_no[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Programs/String Colouring (Easy Version).cpp ================================================ #include #include #include using namespace std; const int MAX_N = 205, UNCOLOURED = -1, RED = 0, BLUE = 1; vector graph[MAX_N]; int other(int c) { return (c == RED ? BLUE : RED); } int main() { int length; string S; cin >> length >> S; vector colour(length, UNCOLOURED); for(int i = 0; i < length; i++) { if(colour[i] == UNCOLOURED) { colour[i] = RED; } for(int j = i + 1; j < length; j++) { if(S[j] < S[i] && colour[j] == UNCOLOURED) { colour[j] = other(colour[i]); continue; } if(S[j] < S[i] && colour[i] == colour[j]) { cout << "NO\n"; return 0; } } } cout << "YES\n"; for(int i = 0; i < length; i++) { cout << colour[i]; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/617 Div 3/Programs/Yet Another Walking Robot.cpp ================================================ #include #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; map , int> position; int minimum_distance = length + 1, left = 0, right = length + 1; position[make_pair(0, 0)] = -1; for(int x = 0, y = 0, i = 0; i < length; i++) { switch(S[i]) { case 'L' : x++; break; case 'R' : x--; break; case 'U' : y++; break; case 'D' : y--; break; } if(position.count(make_pair(x, y)) != 0) { int last_i = position[make_pair(x, y)] + 1; int distance = (i) - (last_i - 1); if(distance < minimum_distance) { minimum_distance = distance; left = last_i ; right = i; } } position[make_pair(x, y)] = i; } if(minimum_distance > length) { cout << "-1\n"; return; } cout << left + 1 << " " << right + 1 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Explanations/Add Odd or Subtract Even Explanation.txt ================================================ We can always make b from a in at most 2 moves. If the difference is > 0 and odd, then we can reach in 1 move by adding the required amount. Otherwise, we can reach in 2 moves by adding 2 odd integers. If the difference is < 0 and even, then we can reach in 1 move by subtracting the required amount. Otherwise, we can reach in 2 moves by subtracting a big even integer followed by adding an odd integer. ----- #include #include using namespace std; void solve() { long long a, b; cin >> a >> b; long long d = (b - a); int moves = 0; if(d < 0) { moves = (d%2 == 0 ? 1 : 2); } else if(d > 0) { moves = (d%2 == 1 ? 1 : 2); } cout << moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Explanations/Construct the Binary Tree Explanation.txt ================================================ First, we will calculate the minimum and maximum sum possible. The minimum sum is achieved when the tree is as balanced as possible. This means that level 2 is completely filled before moving to level 3 Level 3 is completely filled before moving to level 4 And so on The maximum sum is achieved when the tree is a chain 1 + 2 + 3 + ... + n - 1 If the desired sum is outside this range, then it is not possible. Otherwise, we will start with the tree having maximum sum and keep reducing the sum by 1 till we arrive at the desired sum ----- How to reduce the sum by 1 ? We will choose the leaf with the lowest depth d We will try to move it to some vertex of depth (d - 2) which has less than 2 children If a leaf can't be moved in this way, we will consider it 'immobile' and search for another one at a greater depth This process will continue till we reach the desired sum Of course, we will always reach the desired sum because this process only ends when the tree becomes completely balanced and we have already checked that condition ----- int is_power_of_2(int n) { return ( (n&(n - 1)) == 0 ); } void solve() { int no_of_vertices, total_depth_sum; cin >> no_of_vertices >> total_depth_sum; long long maximum_sum = (no_of_vertices*(no_of_vertices - 1))/2; long long minimum_sum = 0; for(int i = 1, level = 0; i <= no_of_vertices; i++) { if(is_power_of_2(i)) { level++; } minimum_sum += (level - 1); } if(total_depth_sum < minimum_sum || maximum_sum < total_depth_sum) { cout << "NO\n"; return; } vector depth(no_of_vertices + 1, 0); vector parent(no_of_vertices + 1, 0); vector no_of_children(no_of_vertices + 1, 1); for(int i = 1; i <= no_of_vertices; i++) { parent[i] = i - 1; depth[i] = i - 1; } no_of_children[no_of_vertices] = 0; vector immobile(no_of_vertices + 1, false); for(long long sum = maximum_sum; sum > total_depth_sum; ) { int first_v = 0; for(int i = 1; i <= no_of_vertices; i++) { if(!immobile[i] && no_of_children[i] == 0 && (first_v == 0 || depth[i] < depth[first_v])) { first_v = i; } } int best_parent = 0; for(int i = 1; i <= no_of_vertices; i++) { if(depth[i] == depth[first_v] - 2 && no_of_children[i] < 2) { best_parent = i; } } if(best_parent == 0) { immobile[first_v] = true; continue; } sum--; no_of_children[parent[first_v]]--; depth[first_v]--; parent[first_v] = best_parent; no_of_children[best_parent]++; } cout << "YES\n"; for(int i = 2; i <= no_of_vertices; i++) { cout << parent[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Explanations/Moving Points Explanation.txt ================================================ https://qr.ae/Td8Mfd Let us sort the points in order - x1, x2, ... , xn For a given x_i, which x_j <= x_i does it not intersect with ? With all those x_j, for which v_j <= v_i Maintain a segment tree where the indices are the velocities and the values are pairs (number of points, sum of points) which have this velocity. For any given point x_j, we will take the sum in the range [1, v_i] The answer will increase by Number_of_points*x_i - Sum(x) ----- #include #include #include #include #define all(v) (v).begin(), (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; struct Point { long long distance, velocity; Point(){}; Point(long long D, long long V) { distance = D; velocity = V; } }; int sort_by_distance(const Point &P, const Point &Q) { return (P.distance < Q.distance); } const int MAX_N = 2e5 + 5; pair sum_tree[3*MAX_N]; void update(int n, int left, int right, int position, long long value) { if(position < left || right < position) { return; } if(left == right) { sum_tree[n].first += value; sum_tree[n].second++; //cout << "Sum Tree " << n << " = " << sum_tree[n].first << "," << sum_tree[n].second << "\n"; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); sum_tree[n].second = sum_tree[LEFT(n)].second + sum_tree[RIGHT(n)].second; sum_tree[n].first = sum_tree[LEFT(n)].first + sum_tree[RIGHT(n)].first; //cout << "Sum Tree " << n << " = " << sum_tree[n].first << "," << sum_tree[n].second << "\n"; } pair get(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || query_right < query_left) { return make_pair(0, 0); } if(query_left <= left && right <= query_right) { return sum_tree[n]; } int mid = (left + right)/2; pair left_answer = get(LEFT(n), left, mid, query_left, query_right); pair right_answer = get(RIGHT(n), mid + 1, right, query_left, query_right); pair answer; answer.second = left_answer.second + right_answer.second; answer.first = left_answer.first + right_answer.first; return answer; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_points; cin >> no_of_points; vector P(no_of_points); for(int i = 0; i < no_of_points; i++) { cin >> P[i].distance; } for(int i = 0; i < no_of_points; i++) { cin >> P[i].velocity; } sort(all(P), sort_by_distance); vector velocities; for(int i = 0; i < no_of_points; i++) { velocities.push_back(P[i].velocity); } sort(all(velocities)); map effective_index; effective_index[velocities[0]] = 1; for(int i = 1; i < no_of_points; i++) { if(velocities[i] == velocities[i - 1]) { continue; } effective_index[velocities[i]] = effective_index[velocities[i - 1]] + 1; } for(int i = 0; i < 3*MAX_N; i++) { sum_tree[i] = make_pair(0, 0); } long long answer = 0; for(int i = 0; i < no_of_points; i++) { pair Q = get(1, 1, no_of_points, 1, effective_index[P[i].velocity]); long long total = Q.first; int no_of_points_here = Q.second; //cout << "At x = " << P[i].distance << " V = " << P[i].velocity << "\n"; //cout << "No of Points = " << no_of_points_here << " Total = " << total << "\n"; //cout << "Range = [1, " << effective_index[P[i].velocity] - 1 << "]\n"; answer += ( (no_of_points_here)*P[i].distance - total); //cout << "Answer = " << answer << "\n"; update(1, 1, no_of_points, effective_index[P[i].velocity], P[i].distance); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Explanations/Perform the Combo Explanation.txt ================================================ Whenever there is a mistake at position i, we will add the frequency[a] in [1, i] to answer[a] We will add the frequency of every alphabet to it's answer at the end as well ----- 1. We will sort P 2. We will keep track of the frequency of each letter as we go from left to right. 3. If i is a position where there is a mistake, then we will add the frequency[1, P] of every alphabet to the total number of times the alphabet is no_of_hit ----- void solve() { int length, no_of_tries; cin >> length >> no_of_tries; string S; cin >> S; vector P(no_of_tries + 1); for(int i = 1; i <= no_of_tries; i++) { cin >> P[i]; } const int NO_OF_ALPHABETS = 26; vector no_of_hits(NO_OF_ALPHABETS, 0); vector frequency(NO_OF_ALPHABETS, 0); sort(all(P)); vector no_of_mistakes_here(length + 1, 0); for(int i = 1; i <= no_of_tries; i++) { no_of_mistakes_here[P[i] - 1]++; } no_of_mistakes_here[length - 1] = 1; for(int i = 0, j = 1; i < length; i++) { frequency[S[i] - 'a']++; if( (j <= no_of_tries && i + 1 == P[j]) || i + 1 == length) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { no_of_hits[alpha] += no_of_mistakes_here[i]*frequency[alpha]; //cout << "F" << alpha << " = " << no_of_hits[alpha] << "\n"; } while(j <= no_of_tries && i + 1 == P[j]) { j++; } } } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { cout << no_of_hits[alpha] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 3/624 Div 3/Explanations/Three Integers Explanation.txt ================================================ Let us fix some value of a. We will iterate over the multiples of a to choose b And then, we will iterate over the multiples of b to choose c I set the limit as 4 x 10^4 It is enough to make the limit 2 x 10^4 The reason is that we never need to fix a for any value greater than 2a. Suppose there is some triplet (a', b', c') where a' > 2a, then we can replace it by (1, b', c') and that satisfies the same condition with a lower number of moves. ----- void solve() { const int oo = 1e9, LIMIT = 4e4; int a, b, c; cin >> a >> b >> c; int best_moves = oo; int x = a, y = b, z = c; for(int i = 1; i <= LIMIT; i++) { for(int j = i; j <= LIMIT; j += i) { for(int k = j; k <= LIMIT; k += j) { int moves_here = abs(i - a) + abs(j - b) + abs(k - c); if(moves_here < best_moves) { best_moves = moves_here; x = i; y = j; z = k; } } } } cout << best_moves << "\n"; cout << x << " " << y << " " << z << "\n"; } ================================================ FILE: 2020/Div 3/624 Div 3/Explanations/WeirdSort Explanation.txt ================================================ There are some segments inside which we can conduct swaps. Elements can never go outside these segments. We will sort each of these segments and then check if the entire array is sorted. ----- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_allowed(no_of_elements + 1, false); vector P(m + 1); for(int i = 1; i <= m; i++) { cin >> P[i]; is_allowed[P[i]] = true; } for(int i = 1; i <= no_of_elements; i++) { if(!is_allowed[i]) { continue; } int j = i; while(j <= no_of_elements && is_allowed[j]) { j++; } sort(A.begin() + i, A.begin() + j + 1); } int is_possible_to_sort = true; for(int i = 1; i < no_of_elements; i++) { if(A[i] > A[i + 1]) { is_possible_to_sort = false; } } cout << (is_possible_to_sort ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Programs/Add Odd or Subtract Even.cpp ================================================ #include #include using namespace std; void solve() { long long a, b; cin >> a >> b; long long d = (b - a); int moves = 0; if(d < 0) { moves = (d%2 == 0 ? 1 : 2); } else if(d > 0) { moves = (d%2 == 1 ? 1 : 2); } cout << moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Programs/Construct the Binary Tree.cpp ================================================ #include #include using namespace std; int is_power_of_2(int n) { return ( (n&(n - 1)) == 0 ); } void solve() { int no_of_vertices, total_depth_sum; cin >> no_of_vertices >> total_depth_sum; long long maximum_sum = (no_of_vertices*(no_of_vertices - 1))/2; long long minimum_sum = 0; for(int i = 1, level = 0; i <= no_of_vertices; i++) { if(is_power_of_2(i)) { level++; } minimum_sum += (level - 1); } if(total_depth_sum < minimum_sum || maximum_sum < total_depth_sum) { cout << "NO\n"; return; } vector depth(no_of_vertices + 1, 0); vector parent(no_of_vertices + 1, 0); vector no_of_children(no_of_vertices + 1, 1); for(int i = 1; i <= no_of_vertices; i++) { parent[i] = i - 1; depth[i] = i - 1; } no_of_children[no_of_vertices] = 0; vector immobile(no_of_vertices + 1, false); for(long long sum = maximum_sum; sum > total_depth_sum; ) { int first_v = 0; for(int i = 1; i <= no_of_vertices; i++) { if(!immobile[i] && no_of_children[i] == 0 && (first_v == 0 || depth[i] < depth[first_v])) { first_v = i; } } int best_parent = 0; for(int i = 1; i <= no_of_vertices; i++) { if(depth[i] == depth[first_v] - 2 && no_of_children[i] < 2) { best_parent = i; } } if(best_parent == 0) { immobile[first_v] = true; continue; } sum--; no_of_children[parent[first_v]]--; depth[first_v]--; parent[first_v] = best_parent; no_of_children[best_parent]++; } cout << "YES\n"; for(int i = 2; i <= no_of_vertices; i++) { cout << parent[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Programs/Moving Points.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; struct Point { long long distance, velocity; Point(){}; Point(long long D, long long V) { distance = D; velocity = V; } }; int sort_by_distance(const Point &P, const Point &Q) { return (P.distance < Q.distance); } const int MAX_N = 2e5 + 5; pair sum_tree[3*MAX_N]; void update(int n, int left, int right, int position, long long value) { if(position < left || right < position) { return; } if(left == right) { sum_tree[n].first += value; sum_tree[n].second++; //cout << "Sum Tree " << n << " = " << sum_tree[n].first << "," << sum_tree[n].second << "\n"; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); sum_tree[n].second = sum_tree[LEFT(n)].second + sum_tree[RIGHT(n)].second; sum_tree[n].first = sum_tree[LEFT(n)].first + sum_tree[RIGHT(n)].first; //cout << "Sum Tree " << n << " = " << sum_tree[n].first << "," << sum_tree[n].second << "\n"; } pair get(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || query_right < query_left) { return make_pair(0, 0); } if(query_left <= left && right <= query_right) { return sum_tree[n]; } int mid = (left + right)/2; pair left_answer = get(LEFT(n), left, mid, query_left, query_right); pair right_answer = get(RIGHT(n), mid + 1, right, query_left, query_right); pair answer; answer.second = left_answer.second + right_answer.second; answer.first = left_answer.first + right_answer.first; return answer; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_points; cin >> no_of_points; vector P(no_of_points); for(int i = 0; i < no_of_points; i++) { cin >> P[i].distance; } for(int i = 0; i < no_of_points; i++) { cin >> P[i].velocity; } sort(all(P), sort_by_distance); vector velocities; for(int i = 0; i < no_of_points; i++) { velocities.push_back(P[i].velocity); } sort(all(velocities)); map effective_index; effective_index[velocities[0]] = 1; for(int i = 1; i < no_of_points; i++) { if(velocities[i] == velocities[i - 1]) { continue; } effective_index[velocities[i]] = effective_index[velocities[i - 1]] + 1; } for(int i = 0; i < 3*MAX_N; i++) { sum_tree[i] = make_pair(0, 0); } long long answer = 0; for(int i = 0; i < no_of_points; i++) { pair Q = get(1, 1, no_of_points, 1, effective_index[P[i].velocity]); long long total = Q.first; int no_of_points_here = Q.second; //cout << "At x = " << P[i].distance << " V = " << P[i].velocity << "\n"; //cout << "No of Points = " << no_of_points_here << " Total = " << total << "\n"; //cout << "Range = [1, " << effective_index[P[i].velocity] - 1 << "]\n"; answer += ( (no_of_points_here)*P[i].distance - total); //cout << "Answer = " << answer << "\n"; update(1, 1, no_of_points, effective_index[P[i].velocity], P[i].distance); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Programs/Perform the Combo.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int length, no_of_tries; cin >> length >> no_of_tries; string S; cin >> S; vector P(no_of_tries + 1); for(int i = 1; i <= no_of_tries; i++) { cin >> P[i]; } const int NO_OF_ALPHABETS = 26; vector no_of_hits(NO_OF_ALPHABETS, 0); vector frequency(NO_OF_ALPHABETS, 0); sort(all(P)); vector no_of_mistakes_here(length + 1, 0); for(int i = 1; i <= no_of_tries; i++) { no_of_mistakes_here[P[i] - 1]++; } no_of_mistakes_here[length - 1] = 1; for(int i = 0, j = 1; i < length; i++) { frequency[S[i] - 'a']++; if( (j <= no_of_tries && i + 1 == P[j]) || i + 1 == length) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { no_of_hits[alpha] += no_of_mistakes_here[i]*frequency[alpha]; //cout << "F" << alpha << " = " << no_of_hits[alpha] << "\n"; } while(j <= no_of_tries && i + 1 == P[j]) { j++; } } } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { cout << no_of_hits[alpha] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Programs/Three Integers.cpp ================================================ #include #include using namespace std; void solve() { const int oo = 1e9, LIMIT = 4e4; int a, b, c; cin >> a >> b >> c; int best_moves = oo; int x = a, y = b, z = c; for(int i = 1; i <= LIMIT; i++) { for(int j = i; j <= LIMIT; j += i) { for(int k = j; k <= LIMIT; k += j) { int moves_here = abs(i - a) + abs(j - b) + abs(k - c); if(moves_here < best_moves) { best_moves = moves_here; x = i; y = j; z = k; } } } } cout << best_moves << "\n"; cout << x << " " << y << " " << z << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/624 Div 3/Programs/Weirdsort.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_allowed(no_of_elements + 1, false); vector P(m + 1); for(int i = 1; i <= m; i++) { cin >> P[i]; is_allowed[P[i]] = true; } for(int i = 1; i <= no_of_elements; i++) { if(!is_allowed[i]) { continue; } int j = i; while(j <= no_of_elements && is_allowed[j]) { j++; } sort(A.begin() + i, A.begin() + j + 1); } int is_possible_to_sort = true; for(int i = 1; i < no_of_elements; i++) { if(A[i] > A[i + 1]) { is_possible_to_sort = false; } } cout << (is_possible_to_sort ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Explanations/Frog Jumps Explanation.txt ================================================ It is always best to only jump to the 'R' If we jump from (i to j) to a L and then jump somewhere to k, we could have have gone directly from (i to k) with a smaller step size. The best path is to jump across the R's. The answer is the largest distance between R's or the longest substring of L's ----- void solve() { string S; cin >> S; int answer = 0, last_r = -1; for(int i = 0; i <= S.size(); i++) { if(i == S.size() || S[i] == 'R') { answer = max(answer, i - last_r); last_r = i; } } cout << answer << "\n"; } ================================================ FILE: 2020/Div 3/627 Div 3/Explanations/Maximum White Subtree Explanation.txt ================================================ Firstly, we will write +1 in the white vertices and -1 in the black vertices. Now, the problem is reduced to finding the maximum sum of any subtree containing v for all v. ----- 1. We will find the maximum sum for the subtree rooted at v, for every vertex v We will do this using a DFS function. We will add sum_from[child] to sum_from[v] only if sum_from[child] > 0 void dfs(int v, int parent_v) { sum_from[v] = (colour[v] == WHITE ? 1 : -1); for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); sum_from[v] += max(sum_from[child_v], 0); } } ------ 2. Now, a subtree containing v might also contain some of it's parents. Once again, we will start from the root and go downwards. For every vertex v, we will find out the value of sum_from[parent] without sum_from[v] (If Sum_from[v] > 0, then subtract sum_from[v] from sum_from[parent]. If Sum_from[v] < 0, then no need to subtract as it was never added to sum_from[parent].) If sum_from[parent] without sum_from[v] is > 0, then we will add it to sum_from[v] The important invariant here is that we are going downwards from the arbitrary root we decided. In the first DFS, we found out the maximum sum at subtree rooted at v 'downwards' In the second DFS, we check if we can add some subtree of the parent as well 'upwards' When we have come to v, we have already found out the maximum sum at it's parent so we can be assured that it is the final answer for v ----- void dfs_adjust(int v, int parent_v) { for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } int parent_sum = sum_from[v]; if(sum_from[child_v] > 0) { parent_sum -= sum_from[child_v]; } if(parent_sum > 0) { sum_from[child_v] += parent_sum; } dfs_adjust(child_v, v); } } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1; i <= no_of_vertices; i++) { cin >> colour[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } dfs(1, 0); dfs_adjust(1, 0); for(int i = 1; i <= no_of_vertices; i++) { cout << sum_from[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Explanations/Pair of Topics Explanation.txt ================================================ 1. If (A[i] + A[j] > B[i] + B[j]), we will re-write the sum to write each term as a function of index A[i] - B[i] > B[j] - A[j] A[i] - B[i] > -(A[j] - B[j]) ----- 2. We will make another array V[i] = A[i] - B[i] Now, it is just like counting inversions so we can do this with a segment tree. The range of the elements is too big so we will assign a 'rank' to each V[i] and -V[i] ----- 3. We will process elements 1 by 1 from i = 1 to N While inserting V[i], we will count the number of elements already processed from [-V[i] + 1, N] Then, we will add 1 to the position [V[i]], indicating we have processed it ----- int main() { int no_of_topics; cin >> no_of_topics; vector A(no_of_topics + 1); for(int i = 1; i <= no_of_topics; i++) { cin >> A[i]; } vector B(no_of_topics + 1); for(int i = 1; i <= no_of_topics; i++) { cin >> B[i]; } vector value(no_of_topics + 1); vector sorted_value; for(int i = 1; i <= no_of_topics; i++) { value[i] = A[i] - B[i]; sorted_value.push_back(value[i]); sorted_value.push_back(-value[i]); } sort(all(sorted_value)); map effective_index; for(int i = 0; i < sorted_value.size(); i++) { if(i == 0) { effective_index[sorted_value[i]] = 1; } else if(sorted_value[i] != sorted_value[i - 1]) { effective_index[sorted_value[i]] = effective_index[sorted_value[i - 1]] + 1; } } long long no_of_good_pairs = 0; memset(sum_tree, 0, sizeof(sum_tree)); for(int i = 1; i <= no_of_topics; i++) { no_of_good_pairs += get_sum(1, 1, 2*no_of_topics, effective_index[-value[i]] + 1, 2*no_of_topics); update(1, 1, 2*no_of_topics, effective_index[value[i]], 1); } cout << no_of_good_pairs << "\n"; return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Explanations/Sleeping Schedule Explanation.txt ================================================ Let f(i, s) be the maximum number of good sleeps from [i, n] if we sleep at time s on day i We can compute this DP in O(N.H) time ----- Suppose we start at time s on day i, then we have 2 options for starting on day (i + 1). We can either wait time = A[i + 1] or time = A[i + 1] - 1 1. (S + A[i + 1])%H 2. (S + A[i + 1] - 1)%H We will look at the best value of f(i + 1, next_start) and update f(i, s) accordingly ----- f(i, s) = (L <= S && S <= R) + max{ f(i + 1, next_start_1), f(i + 1, next_start_2)} The final answer = max{f(1, A[1]), f(1, A[1] - 1)} as there are only 2 options in the beginning ----- int main() { int no_of_times, no_of_hours, left, right; cin >> no_of_times >> no_of_hours >> left >> right; vector A(no_of_times + 1, 0); for(int i = 1; i <= no_of_times; i++) { cin >> A[i]; } for(int i = no_of_times; i >= 1; i--) { if(i == no_of_times) { for(int start = 0; start < no_of_hours; start++) { max_ways[i][start] = (left <= start && start <= right); } continue; } for(int start = 0; start < no_of_hours; start++) { int next_start_1 = (start + A[i + 1])%no_of_hours; int next_start_2 = (start + A[i + 1] - 1 + no_of_hours)%no_of_hours; int best_next_start; if(max_ways[i + 1][next_start_1] < max_ways[i + 1][next_start_2]) { best_next_start = next_start_2; } else { best_next_start = next_start_1; } max_ways[i][start] = (left <= start && start <= right) + max_ways[i + 1][best_next_start]; } } int answer = max(max_ways[1][A[1]], max_ways[1][A[1] - 1]); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Explanations/Yet Another Palindrome Problem Explanation.txt ================================================ There are 2 types of palindromes of length 3 - (axa) and (aaa) 1. If we have any alphabet who's frequency is 3, we are done 2. If we have any alphabet who's frequency is 2, we can append any of the alphabets in between them. We just have to be careful if frequency[A[i]] = 2 and (A[i] = A[i - 1]) as there is no middle character ----- void solve() { int no_of_elements; cin >> no_of_elements; int palindrome_possible = false; vector frequency(no_of_elements + 1, 0); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; if(frequency[A[i]] == 3) { palindrome_possible = true; } if(frequency[A[i]] == 2 && (i > 1 && A[i] != A[i - 1]) ) { palindrome_possible = true; } } cout << (palindrome_possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 3/627 Div 3/Explanations/Yet Another Tetris Problem Explanation.txt ================================================ 1. Firstly, adding 2 does not do anything to the parity 2. When we subtract 1 from every integer. If there are x odd integers and (n - x) even integers, there will be x even integers and (n - x) odd integers. 3. Ultimately, 0 is an even integer so we need N even integers. This is not possible if there are both even and odd integers in the beginning ----- Conversely, it is always possible when all the integers have the same parity In every addition step, we will try to make all other integers equal to the maximum integer As the process goes on till at least one A[i] > 0, we will always try to make the other columns = maximum column ----- void solve() { int no_of_columns; cin >> no_of_columns; const int MAX_HEIGHT = 105; vector frequency(2, 0); vector height(no_of_columns + 1); for(int i = 1; i <= no_of_columns; i++) { cin >> height[i]; frequency[height[i]%2]++; } cout << (frequency[0] == 0 || frequency[1] == 0 ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 3/627 Div 3/Programs/Frog Jumps.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { string S; cin >> S; int answer = 0, last_r = -1; for(int i = 0; i <= S.size(); i++) { if(i == S.size() || S[i] == 'R') { answer = max(answer, i - last_r); last_r = i; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Programs/Maximum White Subtree.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 5, WHITE = 1, BLACK = 0; vector tree[MAX_N]; int colour[MAX_N], sum_from[MAX_N]; void dfs(int v, int parent_v) { sum_from[v] = (colour[v] == WHITE ? 1 : -1); for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); sum_from[v] += max(sum_from[child_v], 0); } } void dfs_adjust(int v, int parent_v) { for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } int parent_sum = sum_from[v]; if(sum_from[child_v] > 0) { parent_sum -= sum_from[child_v]; } if(parent_sum > 0) { sum_from[child_v] += parent_sum; } dfs_adjust(child_v, v); } } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1; i <= no_of_vertices; i++) { cin >> colour[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } dfs(1, 0); dfs_adjust(1, 0); for(int i = 1; i <= no_of_vertices; i++) { cout << sum_from[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Programs/Pair of Topics.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; const int MAX_N = 1e6 + 5; int sum_tree[3*MAX_N]; void update(int n, int left, int right, int position, int value) { if(position < left || right < position) { return; } if(left == right) { sum_tree[n] += value; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int get_sum(int n, int left, int right, int query_left, int query_right) { if(right < left || query_right < left || right < query_left) { return 0; } if(query_left <= left && right <= query_right) { return sum_tree[n]; } int mid = (left + right)/2; int left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); int right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } int main() { int no_of_topics; cin >> no_of_topics; vector A(no_of_topics + 1); for(int i = 1; i <= no_of_topics; i++) { cin >> A[i]; } vector B(no_of_topics + 1); for(int i = 1; i <= no_of_topics; i++) { cin >> B[i]; } vector value(no_of_topics + 1); vector sorted_value; for(int i = 1; i <= no_of_topics; i++) { value[i] = A[i] - B[i]; sorted_value.push_back(value[i]); sorted_value.push_back(-value[i]); } sort(all(sorted_value)); map effective_index; for(int i = 0; i < sorted_value.size(); i++) { if(i == 0) { effective_index[sorted_value[i]] = 1; } else if(sorted_value[i] != sorted_value[i - 1]) { effective_index[sorted_value[i]] = effective_index[sorted_value[i - 1]] + 1; } } long long no_of_good_pairs = 0; memset(sum_tree, 0, sizeof(sum_tree)); for(int i = 1; i <= no_of_topics; i++) { no_of_good_pairs += get_sum(1, 1, 2*no_of_topics, effective_index[-value[i]] + 1, 2*no_of_topics); update(1, 1, 2*no_of_topics, effective_index[value[i]], 1); } cout << no_of_good_pairs << "\n"; return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Programs/Sleeping Schedule.cpp ================================================ #include #include using namespace std; const int MAX_N = 2005; int max_ways[MAX_N][MAX_N]; int main() { int no_of_times, no_of_hours, left, right; cin >> no_of_times >> no_of_hours >> left >> right; vector A(no_of_times + 1, 0); for(int i = 1; i <= no_of_times; i++) { cin >> A[i]; } for(int i = no_of_times; i >= 1; i--) { if(i == no_of_times) { for(int start = 0; start < no_of_hours; start++) { max_ways[i][start] = (left <= start && start <= right); } continue; } for(int start = 0; start < no_of_hours; start++) { int next_start_1 = (start + A[i + 1])%no_of_hours; int next_start_2 = (start + A[i + 1] - 1 + no_of_hours)%no_of_hours; int best_next_start; if(max_ways[i + 1][next_start_1] < max_ways[i + 1][next_start_2]) { best_next_start = next_start_2; } else { best_next_start = next_start_1; } max_ways[i][start] = (left <= start && start <= right) + max_ways[i + 1][best_next_start]; } } int answer = max(max_ways[1][A[1]], max_ways[1][A[1] - 1]); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Programs/Yet Another Palindrome Problem.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; int palindrome_possible = false; vector frequency(no_of_elements + 1, 0); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; if(frequency[A[i]] == 3) { palindrome_possible = true; } if(frequency[A[i]] == 2 && (i > 1 && A[i] != A[i - 1]) ) { palindrome_possible = true; } } cout << (palindrome_possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/627 Div 3/Programs/Yet Another Tetris Problem.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_columns; cin >> no_of_columns; const int MAX_HEIGHT = 105; vector frequency(2, 0); vector height(no_of_columns + 1); for(int i = 1; i <= no_of_columns; i++) { cin >> height[i]; frequency[height[i]%2]++; } cout << (frequency[0] == 0 || frequency[1] == 0 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Explanations/Carousel Explanation.txt ================================================ 1. If all the characters have the same value, the answer is 1 2. Otherwise, there are at least 2 characters requiring at least 2 colours. If the length is even, then (1 2 1 2 1 2 .... ) achieves a 2 colouring If the length is odd, then we will look for any pair (A[i], A[i + 1]) that have the same character. We will merge them into one point and then reduce it to our even case. 3. Otherwise, there are no same neighbours and we colour it (1 2 1 2 1 2 ... 1 2 3) ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } set distinct; for(int i = 0; i < no_of_elements; i++) { distinct.insert(A[i]); } int no_of_colours = 1; vector colour(no_of_elements + 1, 1); if(distinct.size() == 1) { no_of_colours = 1; for(int i = 0; i < no_of_elements; i++) { colour[i] = 1; } } else if(no_of_elements%2 == 0) { no_of_colours = 2; for(int i = 0; i < no_of_elements; i++) { colour[i] = (i%2 == 0 ? 2 : 1); } } else { no_of_colours = 2; int equal_point = -1; for(int i = 0; i < no_of_elements; i++) { if(A[i] == A[(i + 1)%no_of_elements]) { equal_point = (i + 1)%no_of_elements; break; } } if(equal_point != -1) { for(int i = 0; i < no_of_elements; i++) { if(i < equal_point) { colour[i] = (i%2 == 0 ? 2 : 1); } else if(i == equal_point) { colour[i] = ((i + 1)%2 == 0 ? 2 : 1); //Same as Previous } else if(i > equal_point) { colour[i] = (i%2 == 0 ? 1 : 2); } } } else { no_of_colours = 3; for(int i = 0; i < no_of_elements; i++) { colour[i] = (i%2 == 0 ? 2 : 1); } colour[no_of_elements - 1] = 3; } } cout << no_of_colours << "\n"; for(int i = 0; i < no_of_elements; i++) { cout << colour[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 3/629 Div 3/Explanations/Divisibility Problem Explanation.txt ================================================ We will always try to make a = the next multiple of b We just have to add enough to make a = 0 (mod b) If a = 0 (mod b) already, then we do not need to add anything ----- void solve() { int a, b; cin >> a >> b; a %= b; int answer = (a == 0 ? 0 : b - a); cout << answer << "\n"; } ================================================ FILE: 2020/Div 3/629 Div 3/Explanations/Kth Beautiful String Explanation.txt ================================================ There can only be 2 b's Let us iterate over the position of the first b from the left. If b is in position i, then the second b can be placed in (i - 1) positions. When b is in position 2, there can be 1 string When b is in position 3, there can be 2 strings And so on ----- We will keep changing the position of the first b till the number of strings is more than K Once the number of substrings is more than K, we will find the position of the second b ----- Initially, the second 'b' is at the position next to the first 'b'. Suppose the first 'b' is fixed at position 5, then we can have aaab baaa aaab abaa aaab aaba aaab aaab We will move the second 'b' (no_of_strings - k) positions from position 4 So, position_2 = position_1 - (no_of_strings - k) - 1 ------ void solve() { int length, k; cin >> length >> k; int position_1 = 0, position_2 = 0; int string_position = 0; for(int i = 2; i <= length; i++) { string_position += (i - 1); if(string_position >= k) { position_1 = i; break; } } position_2 = position_1 - (string_position - k) - 1; for(int i = length; i >= 1; i--) { cout << (i == position_1 || i == position_2 ? 'b' : 'a'); } cout << "\n"; } ================================================ FILE: 2020/Div 3/629 Div 3/Explanations/Ternary XOR Explanation.txt ================================================ 1. Let us go digit by digit 2. If T[i] = 2, Then, A[i] = 1 and B[i] = 1 3. If T[i] = 1, then A[i] = 1 and B[i] = 0 After doing this, we will do the following, We will look for the first i, where A[i] > B[i] For every j from that point, we will make A[i] = 0 and accordingly update B[i] ----- Suppose, A = 110100011 B = 110000010 Here, A[4] > B[4] and A[i] = B[i] for 1 <= i <= 3 After this, we can maintain the same XOR by just making everything in A = 0 A = 110100000 B = 110000021 ----- #include #include #define all(v) (v).begin(),(v).end() using namespace std; void solve() { int length; string X; cin >> length >> X; string A, B; for(int i = 0; i < X.size(); i++) { switch(X[i]) { case '2' : A += '1'; B += '1'; break; case '1' : A += '1'; B += '0'; break; case '0' : A += '0'; B += '0'; break; } } for(int i = 0, is_equal = true; i < X.size(); i++) { if(is_equal) { if(A[i] != B[i]) { is_equal = false; } continue; } if(A[i] == '1' && B[i] == '0') { A[i] = '0'; B[i] = '1'; } if(A[i] == '1' && B[i] == '1') { A[i] = '0'; B[i] = '2'; } } cout << A << "\n" << B << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Explanations/Tree Queries Explanation.txt ================================================ We have to make 2 elegant observations The first observation is that we can replace all the vertices by it's parent 1. If v lies on the path from [1, x], then it's parent, p[v] must also lie on this path 2. If v does not lie on the path, then it has to be at a distance 1 from [1, x], which means that it's parent p[v] must lie on the path [1, x]. ----- So, we will replace all the vertices except the root - 1 and the deepest vertex - v by it's parent. Now, we are given a list of vertices and must check if they all lie on the same path. ----- We can use a very important property of DFS here. We will maintain a 'timer' and will keep track of the time we go 'in' to every vertex v and the time we go 'out' on every vertex v. If vertex v lies in the subtree of vertex u, then time_in[v] < time_in[u] and time_out[u] < time_out[v] We have to check this for all the vertices in our path. ----- One thing to keep in mind is that in DFS for any two vertices, [time_in[v], time_out[v]] and [time_in[u], time_out[u]] will never 'intersect'. They will either be completely disjoint or one will be contained inside the other. So, we have to check that every vertex in our path completely contains the 'last' vertex v If any vertex does not satisfy this, then a path is not possible. Otherwise, it is always possible ----- void dfs(int v, int parent_v, int &time) { time_in[v] = time++; parent[v] = parent_v; depth[v] = depth[parent_v] + 1; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v, time); } time_out[v] = time++; } void solve() { int no_of_query_vertices; cin >> no_of_query_vertices; vector v(no_of_query_vertices + 1); for(int i = 1; i <= no_of_query_vertices; i++) { cin >> v[i]; } int max_depth = 0; int last_v = 0; for(int i = 1; i <= no_of_query_vertices; i++) { if(depth[v[i]] > max_depth) { max_depth = depth[v[i]]; last_v = v[i]; } } for(int i = 1; i <= no_of_query_vertices; i++) { if(v[i] == last_v || v[i] == 1) { continue; } v[i] = parent[v[i]]; } int lies_on_one_path = true; for(int i = 1; i <= no_of_query_vertices; i++) { //cout << "V = " << v[i] << " Time In = " << time_in[v[i]] << " Time Out = " << time_out[v[i]] << "\n"; if(time_in[v[i]] > time_out[last_v] || time_out[v[i]] < time_in[last_v]) { lies_on_one_path = false; } } cout << (lies_on_one_path ? "YES\n" : "NO\n"); } int main() { int no_of_vertices, no_of_queries; cin >> no_of_vertices >> no_of_queries; tree.resize(no_of_vertices + 1); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } parent.resize(no_of_vertices + 1); depth.resize(no_of_vertices + 1); time_in.resize(no_of_vertices + 1); time_out.resize(no_of_vertices + 1); int time = 0; dfs(1, 0, time); /*for(int v = 1; v <= no_of_vertices; v++) { cout << "V = " << v << " Time in = " << time_in[v] << " Time out = " << time_out[v] << "\n"; }*/ for(int i = 1; i <= no_of_queries; i++) { solve(); } return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Programs/Carousel.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } set distinct; for(int i = 0; i < no_of_elements; i++) { distinct.insert(A[i]); } int no_of_colours = 1; vector colour(no_of_elements + 1, 1); if(distinct.size() == 1) { no_of_colours = 1; for(int i = 0; i < no_of_elements; i++) { colour[i] = 1; } } else if(no_of_elements%2 == 0) { no_of_colours = 2; for(int i = 0; i < no_of_elements; i++) { colour[i] = (i%2 == 0 ? 2 : 1); } } else { no_of_colours = 2; int equal_point = -1; for(int i = 0; i < no_of_elements; i++) { if(A[i] == A[(i + 1)%no_of_elements]) { equal_point = (i + 1)%no_of_elements; break; } } if(equal_point != -1) { for(int i = 0; i < no_of_elements; i++) { if(i < equal_point) { colour[i] = (i%2 == 0 ? 2 : 1); } else if(i == equal_point) { colour[i] = ((i + 1)%2 == 0 ? 2 : 1); //Same as Previous } else if(i > equal_point) { colour[i] = (i%2 == 0 ? 1 : 2); } } } else { no_of_colours = 3; for(int i = 0; i < no_of_elements; i++) { colour[i] = (i%2 == 0 ? 2 : 1); } colour[no_of_elements - 1] = 3; } } cout << no_of_colours << "\n"; for(int i = 0; i < no_of_elements; i++) { cout << colour[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Programs/Divisibility Problem.cpp ================================================ #include using namespace std; void solve() { int a, b; cin >> a >> b; a %= b; int answer = (a == 0 ? 0 : b - a); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Programs/Kth Beautiful String.cpp ================================================ #include using namespace std; void solve() { int length, k; cin >> length >> k; int position_1 = 0, position_2 = 0; int string_position = 0; for(int i = 2; i <= length; i++) { string_position += (i - 1); if(string_position >= k) { position_1 = i; break; } } position_2 = position_1 - (string_position - k) - 1; for(int i = length; i >= 1; i--) { cout << (i == position_1 || i == position_2 ? 'b' : 'a'); } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Programs/Ternary XOR.cpp ================================================ #include #include #define all(v) (v).begin(),(v).end() using namespace std; void solve() { int length; string X; cin >> length >> X; string A, B; for(int i = 0; i < X.size(); i++) { switch(X[i]) { case '2' : A += '1'; B += '1'; break; case '1' : A += '1'; B += '0'; break; case '0' : A += '0'; B += '0'; break; } } for(int i = 0, is_equal = true; i < X.size(); i++) { if(is_equal) { if(A[i] != B[i]) { is_equal = false; } continue; } if(A[i] == '1' && B[i] == '0') { A[i] = '0'; B[i] = '1'; } if(A[i] == '1' && B[i] == '1') { A[i] = '0'; B[i] = '2'; } } cout << A << "\n" << B << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/629 Div 3/Programs/Tree Queries.cpp ================================================ #include #include using namespace std; vector parent, time_in, time_out, depth; vector > tree; void dfs(int v, int parent_v, int &time) { time_in[v] = time++; parent[v] = parent_v; depth[v] = depth[parent_v] + 1; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v, time); } time_out[v] = time++; } void solve() { int no_of_query_vertices; cin >> no_of_query_vertices; vector v(no_of_query_vertices + 1); for(int i = 1; i <= no_of_query_vertices; i++) { cin >> v[i]; } int max_depth = 0; int last_v = 0; for(int i = 1; i <= no_of_query_vertices; i++) { if(depth[v[i]] > max_depth) { max_depth = depth[v[i]]; last_v = v[i]; } } for(int i = 1; i <= no_of_query_vertices; i++) { if(v[i] == last_v || v[i] == 1) { continue; } v[i] = parent[v[i]]; } int lies_on_one_path = true; for(int i = 1; i <= no_of_query_vertices; i++) { //cout << "V = " << v[i] << " Time In = " << time_in[v[i]] << " Time Out = " << time_out[v[i]] << "\n"; if(time_in[v[i]] > time_out[last_v] || time_out[v[i]] < time_in[last_v]) { lies_on_one_path = false; } } cout << (lies_on_one_path ? "YES\n" : "NO\n"); } int main() { int no_of_vertices, no_of_queries; cin >> no_of_vertices >> no_of_queries; tree.resize(no_of_vertices + 1); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } parent.resize(no_of_vertices + 1); depth.resize(no_of_vertices + 1); time_in.resize(no_of_vertices + 1); time_out.resize(no_of_vertices + 1); int time = 0; dfs(1, 0, time); /*for(int v = 1; v <= no_of_vertices; v++) { cout << "V = " << v << " Time in = " << time_in[v] << " Time out = " << time_out[v] << "\n"; }*/ for(int i = 1; i <= no_of_queries; i++) { solve(); } return 0; } ================================================ FILE: 2020/Div 3/634 Div 3/Explanations/Anti Sudoku Explanation.txt ================================================ There is a very elegant solution. We can replace all the 1's with 2's. In fact, we can take any digit and replace it with some other digit. Since, each digit occurs once in every row, column and box, replacing their occurences, leads to 2 of some digit in every row, column and box ----- My solution was a little different from this thought. We can create a bijection between any two solved Sudoku's We can always relabel 1 Sudoku to get another. For example, if we want to create a Sudoku where the top line is 123456789 Then, we can take some solved Sudoku Whatever is in the first cell, we will relabel it with 1 Whatever is in the second cell, we will relabel it with 2 and so on So, they have already given the solution for 1 Sudoku puzzle ----- 1. We will reduce the Sudoku puzzle in the question to the one we have 2. We will use the solution of this Sudoku puzzle to create the solution of that Sudoku puzzle ----- void solve() We { const int MAX_N = 9; vector grid(MAX_N); for(int i = 0; i < MAX_N; i++) { cin >> grid[i]; } /* Make it equivalent to this 154873296 386592714 729641835 863725149 975314628 412968357 631457982 598236471 247189563*/ /*Make it equivalent to this - 154873396 336592714 729645835 863725145 979314628 412958357 631457992 998236471 247789563*/ grid[0][6] = grid[0][5]; grid[1][1] = grid[1][0]; grid[2][5] = grid[2][8]; grid[3][8] = grid[3][5]; grid[4][2] = grid[4][0]; grid[5][4] = grid[5][7]; grid[6][7] = grid[6][8]; grid[7][0] = grid[7][1]; grid[8][3] = grid[8][2]; for(int i = 0; i < MAX_N; i++) { cout << grid[i] << "\n";; } } ================================================ FILE: 2020/Div 3/634 Div 3/Explanations/Candies and Two Sisters Explanation.txt ================================================ a lies in [n/2, n - 1] and b lies in [n/2, 1] When n is even, then we cannot use n/2. So, answer is (n/2 - 1) Otherwise answer is (n/2) ---- void solve() { long long n; cin >> n; long long no_of_ways = (n/2) - (n%2 == 0 ? 1 : 0); cout << no_of_ways << "\n"; } ================================================ FILE: 2020/Div 3/634 Div 3/Explanations/Construct the String Explanation.txt ================================================ We will place blocks of length A The block with have (b - 1) distinct letters followed by (a - b) occurences of b For example here is a block with 5 distinct characters of length 9 abcdeeeee We will simply place blocks like this next to each other. When we slide the window, if the right pointer adds a new distinct character, the left pointer removes a new distinct character. This ensures every window of length A has B distinct characters ----- void solve() { int length, substring, distinct; cin >> length >> substring >> distinct; string S; for(int i = 0; i < length; i++) { if(i < substring) { if(i < distinct) { S += (char)('a' + i); } else { S += S.back(); } } else { S += S[i - substring]; } } cout << S << "\n"; } ================================================ FILE: 2020/Div 3/634 Div 3/Explanations/Robots on a Grid Explanation.txt ================================================ Fact - If 2 Robots intersect, they will do so in the first NM moves Once two robots meet, they will always move together. So, if they meet in <= NM moves, they will be together after NM moves. Let us look at the structure of the graph. It is a functional graph where each vertex has exactly one outgoing edge. So, the graph consists of some cycles and some tress which go into cycles. As the graph has MN vertices in total, after MN moves, every robot will be inside a cycle. (The length of the path going into a cycle cannot be greater than MN). If 2 robots are inside a cycle and not coincident, they will never meet since they move an equal distance in the same direction each time and the distance between them remains constant ! ---- Now, how do we find out where a Robot ends up in NM moves ? We can use binary lifting for this. 1. We will do a DFS and find out f(0, i, j), that is where the robot at cell (i, j) goes in 2^0 = 1 move 2. Then, we will use it to recursively build this table f(L, i, j) = f(L - 1, f(L - 1, i, j)) That is we will see where we go from (i, j) in 2^{L - 1} steps And we will see where we will reach if we take 2^{L - 1} steps from there 2^{L - 1} + 2^{L - 1} = 2^L ----- This table is built is O(NM log(NM)) time For every (NM) cells, we will find out the ultimate destination it is in after (NM) steps ----- For every cell, we will keep track of the number of black and white cells which reach here after (NM) moves. Since robots can never meet, if there are multiple robots finishing at (i, j), only one of them can be in the initial grid. If possible, we will choose a black square robot. Once we are done, we will scan all NM squares If black_starts(i, j) > 0, then we will update the number of black robots If white_starts(i, j) > 0, then we will update the number of white robots ------ int get_next(int x, int y) { switch(S[x][y]) { case 'U' : return label(x - 1, y); case 'R' : return label(x, y + 1); case 'L' : return label(x, y - 1); case 'D' : return label(x + 1, y); } return 0; } void dfs(int v) { if(visited[v]) { return; } visited[v] = true; int x = v/columns, y = v%columns; int next = get_next(x, y); //cout << "At " << v << " " << x << "," << y << " Next = " << next << "\n"; step[0][v] = next; dfs(next); } void solve() { cin >> rows >> columns; colour.resize(rows); for(int i = 0; i < rows; i++) { cin >> colour[i]; } S.resize(rows); for(int i = 0; i < rows; i++) { cin >> S[i]; } visited.resize(rows*columns, false); for(int i = 0; i < rows*columns; i++) { visited[i] = false; } for(int i = 0; i < MAX_L; i++) { step[i].resize(rows*columns); } for(int v = 0; v < rows*columns; v++) { if(!visited[v]) { dfs(v); } } for(int l = 1; l < MAX_L; l++) { for(int i = 0; i < rows*columns; i++) { int previous_step = step[l - 1][i]; //cout << "L = " << l << "Start at " << i/columns << "," << i%columns << " previous = " << previous_step/columns << "," << previous_step%columns <<" and finish at " << step[l - 1][previous_step]/columns << " " << step[l - 1][previous_step]%columns << "\n"; step[l][i] = step[l - 1][previous_step]; } } vector black_starts(rows*columns); vector white_starts(rows*columns); int total_steps = rows*columns; for(int i = 0; i < rows*columns; i++) { int finish = i; for(int bit = MAX_L - 1; bit >= 0; bit--) { if(is_bit_set(total_steps, bit)) { finish = step[bit][finish]; } } const char BLACK = '0', WHITE = '1'; int start_x = i/columns, start_y = i%columns; if(colour[start_x][start_y] == BLACK) { black_starts[finish]++; } else { white_starts[finish]++; } //cout << "Start at " << start_x << "," << start_y << " and finish at " << finish/columns << " " << finish%columns << "\n"; } int total = 0, black = 0; for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(black_starts[label(i, j)] > 0) { total++; black++; } else if(white_starts[label(i, j)] > 0) { total++; } } } cout << total << " " << black << "\n"; } ================================================ FILE: 2020/Div 3/634 Div 3/Explanations/Three Blocks Palindrome Explanation.txt ================================================ Let us keep track of the positions of each of the alphabets. Now, we will iterate over the possible choices for the 'outer' alphabet. If we take p of the alphabet, we should take p/2 of it's left most and p/2 of it's right most. We will choose the alphabet which occurs most frequently in [L, R] gap as y ----- The trick here is that the outer 2 loops visits each letter at most once. So the over complexity is O(n) even though it looks like it's O(n^2) Total Complexity is O(n.AL) where AL is the size of the alphabet ----- void solve() { int no_of_elements; cin >> no_of_elements; int max_n = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; max_n = max(max_n, A[i]); } vector > position(max_n + 1); vector > frequency(max_n + 1, vector (no_of_elements + 1, 0)); for(int i = 1; i <= no_of_elements; i++) { position[A[i]].push_back(i); for(int alpha = 1; alpha <= max_n; alpha++) { frequency[alpha][i] = frequency[alpha][i - 1]; } frequency[A[i]][i]++; } int answer = 0; for(int i = 1; i <= max_n; i++) { answer = max(answer, position[i].size()); for(int p = 0; 2*p < position[i].size(); p++) { int left = position[i][p] + 1; int right = position[i][position[i].size() - p - 1] - 1; if(left > right) { break; } int max_middle = 0; for(int middle = 1; middle <= max_n; middle++) { int middle_frequency = frequency[middle][right] - frequency[middle][left - 1]; max_middle = max(max_middle, middle_frequency); } answer = max(answer, 2*(p + 1) + max_middle); } } cout << answer << "\n"; } ================================================ FILE: 2020/Div 3/634 Div 3/Explanations/Two Teams Composing Explanation.txt ================================================ We will iterate over all elements and check the cost if this element is the one in the same set. ---- There are 2 possibilities - 1. We put all it's occurences in the 'Same' bucket and all the distinct in the other This is given by min(distinct - 1, frequency[A[i]]) [1, 2, 3], [4, 4, 4] 2. We put one of it's occurences in the 'Distinct' bucket and all else in the 'Same' bucket This is given by min(distinct, frequency[A[i]] - 1) [1, 2, 3, 4] [4, 4, 4, 4] ----- We will iterate over all of them and choose the best ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } set distinct; map frequency; for(int i = 1; i <= no_of_elements; i++) { distinct.insert(A[i]); frequency[A[i]]++; } int team_size = 0; for(int i = 1; i <= no_of_elements; i++) { int team_size_here_1 = min(distinct.size() - 1, frequency[A[i]]); int team_size_here_2 = min(distinct.size(), frequency[A[i]] - 1); int team_size_here = max(team_size_here_1, team_size_here_2); team_size = max(team_size, team_size_here); } cout << team_size << "\n"; } ================================================ FILE: 2020/Div 3/634 Div 3/Programs/Anti Sudoku.cpp ================================================ #include #include using namespace std; void solve() { const int MAX_N = 9; vector grid(MAX_N); for(int i = 0; i < MAX_N; i++) { cin >> grid[i]; } /* Make it equivalent to this 154873296 386592714 729641835 863725149 975314628 412968357 631457982 598236471 247189563*/ /*Make it equivalent to this - 154873396 336592714 729645835 863725145 979314628 412958357 631457992 998236471 247789563*/ grid[0][6] = grid[0][5]; grid[1][1] = grid[1][0]; grid[2][5] = grid[2][8]; grid[3][8] = grid[3][5]; grid[4][2] = grid[4][0]; grid[5][4] = grid[5][7]; grid[6][7] = grid[6][8]; grid[7][0] = grid[7][1]; grid[8][3] = grid[8][2]; for(int i = 0; i < MAX_N; i++) { cout << grid[i] << "\n";; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/634 Div 3/Programs/Candies and Two Sisters.cpp ================================================ #include using namespace std; void solve() { long long n; cin >> n; long long no_of_ways = (n/2) - (n%2 == 0 ? 1 : 0); cout << no_of_ways << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/634 Div 3/Programs/Construct the String.cpp ================================================ #include using namespace std; void solve() { int length, substring, distinct; cin >> length >> substring >> distinct; string S; for(int i = 0; i < length; i++) { if(i < substring) { if(i < distinct) { S += (char)('a' + i); } else { S += S.back(); } } else { S += S[i - substring]; } } cout << S << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/634 Div 3/Programs/Robots on a Grid.cpp ================================================ #include #include using namespace std; const int MAX_L = 25; int rows, columns; vector colour; vector S; vector > step(MAX_L); vector visited; int label(int x, int y) { return x*columns + y; } int is_bit_set(int n, int bit) { return ((n&(1 << bit)) != 0); } int get_next(int x, int y) { switch(S[x][y]) { case 'U' : return label(x - 1, y); case 'R' : return label(x, y + 1); case 'L' : return label(x, y - 1); case 'D' : return label(x + 1, y); } return 0; } void dfs(int v) { if(visited[v]) { return; } visited[v] = true; int x = v/columns, y = v%columns; int next = get_next(x, y); //cout << "At " << v << " " << x << "," << y << " Next = " << next << "\n"; step[0][v] = next; dfs(next); } void solve() { cin >> rows >> columns; colour.resize(rows); for(int i = 0; i < rows; i++) { cin >> colour[i]; } S.resize(rows); for(int i = 0; i < rows; i++) { cin >> S[i]; } visited.resize(rows*columns, false); for(int i = 0; i < rows*columns; i++) { visited[i] = false; } for(int i = 0; i < MAX_L; i++) { step[i].resize(rows*columns); } for(int v = 0; v < rows*columns; v++) { if(!visited[v]) { dfs(v); } } for(int l = 1; l < MAX_L; l++) { for(int i = 0; i < rows*columns; i++) { int previous_step = step[l - 1][i]; //cout << "L = " << l << "Start at " << i/columns << "," << i%columns << " previous = " << previous_step/columns << "," << previous_step%columns <<" and finish at " << step[l - 1][previous_step]/columns << " " << step[l - 1][previous_step]%columns << "\n"; step[l][i] = step[l - 1][previous_step]; } } vector black_starts(rows*columns); vector white_starts(rows*columns); int total_steps = rows*columns; for(int i = 0; i < rows*columns; i++) { int finish = i; for(int bit = MAX_L - 1; bit >= 0; bit--) { if(is_bit_set(total_steps, bit)) { finish = step[bit][finish]; } } const char BLACK = '0', WHITE = '1'; int start_x = i/columns, start_y = i%columns; if(colour[start_x][start_y] == BLACK) { black_starts[finish]++; } else { white_starts[finish]++; } //cout << "Start at " << start_x << "," << start_y << " and finish at " << finish/columns << " " << finish%columns << "\n"; } int total = 0, black = 0; for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(black_starts[label(i, j)] > 0) { total++; black++; } else if(white_starts[label(i, j)] > 0) { total++; } } } cout << total << " " << black << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/634 Div 3/Programs/Three Blocks Palindrome.cpp ================================================ #include #include #define max(a, b) (a > b ? a : b) using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; int max_n = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; max_n = max(max_n, A[i]); } vector > position(max_n + 1); vector > frequency(max_n + 1, vector (no_of_elements + 1, 0)); for(int i = 1; i <= no_of_elements; i++) { position[A[i]].push_back(i); for(int alpha = 1; alpha <= max_n; alpha++) { frequency[alpha][i] = frequency[alpha][i - 1]; } frequency[A[i]][i]++; } int answer = 0; for(int i = 1; i <= max_n; i++) { answer = max(answer, position[i].size()); for(int p = 0; 2*p < position[i].size(); p++) { int left = position[i][p] + 1; int right = position[i][position[i].size() - p - 1] - 1; if(left > right) { break; } int max_middle = 0; for(int middle = 1; middle <= max_n; middle++) { int middle_frequency = frequency[middle][right] - frequency[middle][left - 1]; max_middle = max(max_middle, middle_frequency); } answer = max(answer, 2*(p + 1) + max_middle); } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/634 Div 3/Programs/Two Teams Composing.cpp ================================================ #include #include #include #include #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } set distinct; map frequency; for(int i = 1; i <= no_of_elements; i++) { distinct.insert(A[i]); frequency[A[i]]++; } int team_size = 0; for(int i = 1; i <= no_of_elements; i++) { int team_size_here_1 = min(distinct.size() - 1, frequency[A[i]]); int team_size_here_2 = min(distinct.size(), frequency[A[i]] - 1); int team_size_here = max(team_size_here_1, team_size_here_2); team_size = max(team_size, team_size_here); } cout << team_size << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/636 Div 3/Explanations/Constant Palindrome Sum Explanation.txt ================================================ Ultimately, the sum will be in [1, 2k] We will iterate over all x in [1, 2k] and find the best x. ----- There are 3 types of pairs - 1. Pairs with 0 changes 2. Pairs with 1 changes 3. Pairs with 2 changes ---- Pairs with 0 changes are those pairs who's sum = x Every pair can be changed to have sum = k Pairs with 2 changes = Total pair - 1_change - 2_changes Now, we only need to count the number of pairs with exactly 1 change ----- We have a pair (A[i], A[n - i + 1]) What are the possible sums we can get ? Suppose, without loss of generality, that A[i] < A[n - i + 1] Then, the smallest sum we can get is (A[i], 1) And, the largest sum we can get is (k, A[n - i + 1]) We can get every sum in the range [A[i] + 1, A[n - i + 1] + k] ----- Now, let us discuss a different problems, We have a list of lines - [L1, R1] [L2, R2] [L3, R3] . . [Ln, Rn] How do we calculate the number of lines that cover the point x ? Let us say that a line [L, R] starts at point L and ends at point R Then, Lines Covering x = lines Covering (x - 1) + Lines starting from(x) - Lines ending at (x) ----- We can do 1 sweep and calculate the number of lines meeting at every x from [1, 2k] ---- One thing to keep in mind is that the range [A[i] + 1, A[n - i + 1] + k] covers (A[i], A[n - i + 1]) But (A[i], A[n - i + 1]) requires 0 changes So, the number of 1-changes for x = Lines Covering x - Frequency(x) The number of 2-changes for x = (Total Pairs - Number of 1-changes - Number of 0-changes) ----- void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector frequency(2*k + 1, 0); for(int i = 1; i <= no_of_elements/2; i++) { frequency[A[i] + A[no_of_elements - i + 1]]++; } vector lines_starting_at(2*k + 2); vector lines_ending_at(2*k + 2); for(int i = 1; i <= no_of_elements/2; i++) { lines_starting_at[min(A[i], A[no_of_elements - i + 1]) + 1]++; lines_ending_at[max(A[i], A[no_of_elements - i + 1]) + k + 1]++; } vector lines_passing_through(2*k + 1, 0); for(int i = 1; i <= 2*k; i++) { lines_passing_through[i] = lines_passing_through[i - 1] + lines_starting_at[i] - lines_ending_at[i]; } int answer = no_of_elements; for(int x = 1; x <= 2*k; x++) { int changes_1 = lines_passing_through[x] - frequency[x]; int changes_2 = no_of_elements/2 - changes_1 - frequency[x]; answer = min(answer, changes_1 + 2*changes_2); } cout << answer << "\n"; } ================================================ FILE: 2020/Div 3/636 Div 3/Programs/Constant Palindrome Sum.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector frequency(2*k + 1, 0); for(int i = 1; i <= no_of_elements/2; i++) { frequency[A[i] + A[no_of_elements - i + 1]]++; } vector lines_starting_at(2*k + 2); vector lines_ending_at(2*k + 2); for(int i = 1; i <= no_of_elements/2; i++) { lines_starting_at[min(A[i], A[no_of_elements - i + 1]) + 1]++; lines_ending_at[max(A[i], A[no_of_elements - i + 1]) + k + 1]++; } vector lines_passing_through(2*k + 1, 0); for(int i = 1; i <= 2*k; i++) { lines_passing_through[i] = lines_passing_through[i - 1] + lines_starting_at[i] - lines_ending_at[i]; //cout << "L " << i << " = " << lines_passing_through[i] << "\n"; } int answer = no_of_elements; for(int x = 1; x <= 2*k; x++) { int changes_1 = lines_passing_through[x] - frequency[x]; int changes_2 = no_of_elements/2 - changes_1 - frequency[x]; //cout << "Changes 1 = " << changes_1 << " Changes 2 = " << changes_2 << " for " << x << "\n"; answer = min(answer, changes_1 + 2*changes_2); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/661 Div 3/Explanations/Binary String to Subsequence Explanation.txt ================================================ Let us keep track of the list of available sequences ending with 1 and with 0 When we are at S[i], we will check if there are any available sequences ending with it's complement. If there are, then we will match S[i] with that and update it accordingly. For example, if S[i] = 0, and we have sequence number 3 ending with 1, we will append s[i] to the third sequence ----- We will maintain a set of all avaialable sequences ending with both numbers When we process S[i], we will check if it's complement is empty or if there is some available sequence We will update it accordingly ----- void solve() { int length; string S; cin >> length >> S; vector sequence_no(length + 1); set available_label[2]; int no_of_sequences = 1; available_label[0].insert(1); available_label[1].insert(1); for(int i = 0; i < length; i++) { int current = S[i] - '0'; int complement = 1 - current; if(available_label[complement].size() == 0) { no_of_sequences++; sequence_no[i] = no_of_sequences; available_label[current].insert(sequence_no[i]); } else { auto it = available_label[complement].begin(); sequence_no[i] = *it; available_label[current].insert(sequence_no[i]); available_label[complement].erase(sequence_no[i]); } } cout << no_of_sequences << "\n"; for(int i = 0; i < length; i++) { cout << sequence_no[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 3/661 Div 3/Explanations/Boats Competition Explanation.txt ================================================ For each possible sum between [1, 2n], we will count the number of pairs that are possible. We will do this by maintaining the frequency of each integer and then making as many matches as possible. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector frequency(2*no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } int maximum_teams = 0; for(int pair_sum = 1; pair_sum < 2*no_of_elements + 1; pair_sum++) { int max_teams_now = 0; for(int i = 1; i <= no_of_elements; i++) { if(pair_sum - i >= i) { if(i != pair_sum - i) { max_teams_now += min(frequency[pair_sum - i], frequency[i]); } else { max_teams_now += frequency[i]/2; } } } maximum_teams = max(maximum_teams, max_teams_now); } cout << maximum_teams << "\n"; } ================================================ FILE: 2020/Div 3/661 Div 3/Explanations/Gifts Fixing Explanation.txt ================================================ We will have to make every element in each sequence equal to their minimum. We can calculate the number of subtractions required for both (A[i], B[i]). We will do as many operations of the pair as we can and then only do on the single. The total number of operations like this is max(A[i] - target_A, B[i] - target_B) ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } const int oo = 1e9 + 9; int target_A = oo, target_B = oo; for(int i = 1; i <= no_of_elements; i++) { target_A = min(target_A, A[i]); target_B = min(target_B, B[i]); } long long no_of_moves = 0; for(int i = 1; i <= no_of_elements; i++) { long long a_moves_here = A[i] - target_A, b_moves_here = B[i] - target_B; no_of_moves += max(a_moves_here, b_moves_here); } cout << no_of_moves << "\n"; } ================================================ FILE: 2020/Div 3/661 Div 3/Explanations/Remove Smallest Explanation.txt ================================================ Let us look at the sorted list A[1] <= A[2] <= A[3] <= A[4] <= A[5] <= ... <= A[n] If it satisfies the condition, then each contiguous pair can only differ by 1. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int possible = true; for(int i = 2; i <= no_of_elements; i++) { if(A[i] - A[i - 1] > 1) { possible = false; break; } } cout << (possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Div 3/661 Div 3/Programs/Binary String to Subsequences.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int length; string S; cin >> length >> S; vector sequence_no(length + 1); set available_label[2]; int no_of_sequences = 1; available_label[0].insert(1); available_label[1].insert(1); for(int i = 0; i < length; i++) { int current = S[i] - '0'; int complement = 1 - current; if(available_label[complement].size() == 0) { no_of_sequences++; sequence_no[i] = no_of_sequences; available_label[current].insert(sequence_no[i]); } else { auto it = available_label[complement].begin(); sequence_no[i] = *it; available_label[current].insert(sequence_no[i]); available_label[complement].erase(sequence_no[i]); } } cout << no_of_sequences << "\n"; for(int i = 0; i < length; i++) { cout << sequence_no[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/661 Div 3/Programs/Boats Competition.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector frequency(2*no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } int maximum_teams = 0; for(int pair_sum = 1; pair_sum < 2*no_of_elements + 1; pair_sum++) { int max_teams_now = 0; for(int i = 1; i <= no_of_elements; i++) { if(pair_sum - i >= i) { if(i != pair_sum - i) { max_teams_now += min(frequency[pair_sum - i], frequency[i]); } else { max_teams_now += frequency[i]/2; } } } maximum_teams = max(maximum_teams, max_teams_now); } cout << maximum_teams << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/661 Div 3/Programs/Gifts Fixing.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } const int oo = 1e9 + 9; int target_A = oo, target_B = oo; for(int i = 1; i <= no_of_elements; i++) { target_A = min(target_A, A[i]); target_B = min(target_B, B[i]); } long long no_of_moves = 0; for(int i = 1; i <= no_of_elements; i++) { long long a_moves_here = A[i] - target_A, b_moves_here = B[i] - target_B; no_of_moves += max(a_moves_here, b_moves_here); } cout << no_of_moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/661 Div 3/Programs/Remove Smallest.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int possible = true; for(int i = 2; i <= no_of_elements; i++) { if(A[i] - A[i - 1] > 1) { possible = false; break; } } cout << (possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/674 Div 3/Programs/Number of Subsequences.cpp ================================================ #include #include using namespace std; long long sum_till(long long n) { return (n*(n + 1))/2; } long long sum(long long L, long long R) { return sum_till(R) - sum_till(L - 1); } int main() { int length; string S; cin >> length >> S; vector prefix_questions(S.size() + 1, 0); vector prefix_a(S.size() + 1, 0); prefix_a[0] = (S[0] == 'a'); prefix_questions[0] = (S[0] == '?'); for(int i = 1; i < S.size(); i++) { prefix_a[i] = prefix_a[i - 1] + (S[i] == 'a'); prefix_questions[i] = prefix_questions[i - 1] + (S[i] == '?'); } vector suffix_questions(S.size() + 1, 0); vector suffix_c(S.size() + 1, 0); for(int i = S.size() - 1; i >= 0; i--) { suffix_c[i] = suffix_c[i + 1] + (S[i] == 'c'); suffix_questions[i] = suffix_questions[i + 1] + (S[i] == '?'); } const int MOD = 1e9 + 7; vector power_3(length + 1, 1); for(int i = 1; i <= length; i++) { power_3[i] = (3*power_3[i - 1])%MOD; } long long answer = 0; for(int i = 1; i < S.size() - 1; i++) { if(S[i] == 'b' || S[i] == '?') { long long a_s = prefix_a[i - 1], c_s = suffix_c[i + 1]; long long before_questions = prefix_questions[i - 1], after_questions = suffix_questions[i + 1]; long long prefix_value = (a_s*power_3[before_questions])%MOD + (before_questions > 0 ? (before_questions*power_3[before_questions - 1])%MOD : 0); prefix_value %= MOD; long long suffix_value = (c_s*power_3[after_questions])%MOD + (after_questions > 0 ? (after_questions*power_3[after_questions - 1] )%MOD : 0); suffix_value %= MOD; answer = (answer + prefix_value*suffix_value)%MOD; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Div 3/686 Div 3/Explanations/Array Partition Explanation.txt ================================================ Whenever we have to compute triplets, it's always a good idea to iterate over the middle to use symmetry. Let us iterate over A[i]. Suppose A[i] is the minimum of some segment. Let L[i], R[i] be the left and right border of A[i]. They denote the maximum range [L[i], R[i]] in which A[i] can be the minimum. ------ We can precompute L[i], R[i] in O(n) time using a stack. Initially, the stack has a 0. We will keep popping the stack till the top is < A[i] Finally, the top of the stack will be the first element on the left that is > A[i] We do the same thing on the right. ----- void compress_coordinates(int no_of_elements) { vector sorted_A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sorted_A[i] = A[i]; } sort(sorted_A.begin(), sorted_A.end()); map label; label[sorted_A[1]] = 1; for(int i = 2; i <= no_of_elements; i++) { label[sorted_A[i]] = (sorted_A[i] == sorted_A[i - 1] ? label[sorted_A[i - 1]] : label[sorted_A[i - 1]] + 1); } for(int i = 1; i <= no_of_elements; i++) { A[i] = label[A[i]]; //cout << A[i] << " "; indices[A[i]].push_back(i); } } ----- The prefix either ends at L[i] or at some occurrence of A[i], whichever comes later. We will iterate over all indices p in [L[i], i] such that A[p] = A[i] And check if the maximum in [1, p] = A[p] We will also iterate over all indices s in [i, R[i]], such that A[s] = A[i] And check if the maximum in [s, n] = A[s] ----- 1. In order to store the indices of all the elements in a vector, we will do coordinate compression in order to use the array elements as indices 2. We will use a prefix maximum array and a suffix maximum array in order to get the prefix maximum and suffix maximum in O(1) time. 3. In order to clear the time limit, we will not check every single index of A[i] for every i. The prefix maximum has the property that it only increases. Suppose (j < k). Then Prefix Maximum[j] <= Prefix Maximum[k] So, if A[j] = A[k] = A[i] And Prefix Maximum[k] = A[i], then Prefix Maximum[j] = A[i] If we want to find an x, such that Prefix Maximum[x] = A[i], we only need to look at the first occurrence of A[i] in the array. But since we need the minimum of the second segment minimum to be A[i], we will look for the first occurrence of A[i] >= (L[i] - 1) We will do a similar thing for the suffix. ----- For every A[i], we will be checking at most 4 indices 1. The first index to the right of (L[i] - 1) 2. L[i] - 1 3. The first index to the left of (R[i] + 1) 4. R[i] + 1 So, the entire loop runs in O(n) time, with a possible O(log n) factor for finding the indices closest to (L[i] - 1) and (R[i] + 1) ----- void solve() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; indices[i].clear(); } compress_coordinates(no_of_elements); vector prefix_maximum(no_of_elements + 1); vector suffix_maximum(no_of_elements + 5); compute_prefix_and_suffix_max(no_of_elements, prefix_maximum, suffix_maximum); vector left_border(no_of_elements + 1); vector right_border(no_of_elements + 1); compute_borders(no_of_elements, left_border, right_border); for(int i = 1; i <= no_of_elements; i++) { //cout << "For " << i << " is minimum in [" << left_border[i] << " " << right_border[i] << "]\n"; if(indices[A[i]].size() < 3 || i == indices[A[i]][0] || i == indices[A[i]].back()) { continue; } if(prefix_maximum[left_border[i] - 1] > A[i] || suffix_maximum[right_border[i] + 1] > A[i]) { continue; } int p = upper_bound(all(indices[A[i]]), left_border[i] - 2) - indices[A[i]].begin(); if(indices[A[i]][p] == i) { p--; } int s = lower_bound(all(indices[A[i]]), right_border[i] - 1) - indices[A[i]].begin(); if(s == indices[A[i]].size() || indices[A[i]][s] > right_border[i] + 1) { s--; } while(s < indices[A[i]].size() && indices[A[i]][s] <= i) { s++; } int prefix, suffix; //cout << "p = " << indices[A[i]][p] << " s = " << indices[A[i]][s] << "\n"; int left_possible = false; while(p >= 0) { prefix = max(indices[A[i]][p], left_border[i] - 1); //cout << "Prefix = " << prefix << " Maximum = " << prefix_maximum[prefix] << "\n"; if(prefix_maximum[prefix] == A[i]) { left_possible = true; break; } if(p < left_border[i] - 1) { break; } p--; } if(!left_possible) { continue; } int right_possible = false; while(s < indices[A[i]].size()) { suffix = min(indices[A[i]][s], right_border[i] + 1); //cout << "Prefix = " << suffix<< " Maximum = " << suffix_maximum[suffix] << "\n"; if(suffix_maximum[suffix] == A[i]) { right_possible = true; break; } if(s > right_border[i] + 1) { break; } s++; } if(!right_possible) { continue; } int part_1 = prefix, part_2 = (suffix - 1) - prefix; int part_3 = no_of_elements - (part_1 + part_2); cout << "YES\n"; cout << part_1 << " " << part_2 << " " << part_3 << "\n"; return; } cout << "NO\n"; } ================================================ FILE: 2020/Div 3/686 Div 3/Explanations/Number Into Sequence Explanation.txt ================================================ Since A[i] has to be divisible by each A[1, i - 1], All A[1, k] must have the same prime factor. Suppose p^k is the prime with the largest exponent in the prime factorization of N. We can have k elements p, p, p, .... , (N/p^{k - 1}) ----- void solve() { long long n; cin >> n; long long final_n = n; pair best_prime; vector > prime_exponents; for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { int exponent = 0; while(n%i == 0) { n /= i; exponent++; } prime_exponents.push_back(make_pair(exponent, i)); best_prime = max(best_prime, prime_exponents.back()); } } if(n > 1) { prime_exponents.push_back(make_pair(1, n)); best_prime = max(best_prime, prime_exponents.back()); } cout << best_prime.first << "\n"; for(int i = 1; i < best_prime.first; i++) { cout << best_prime.second << " "; final_n /= best_prime.second; } cout << final_n << "\n"; } ================================================ FILE: 2020/Div 3/686 Div 3/Explanations/Number of Simple Paths Explanation.txt ================================================ A connected graph with N vertices and N edges has exactly 1 cycle. ----- We can prove this with Mathematical Induction. It is true for a graph with 2 vertices. Suppose it is true for a graph with n vertices. Consider a graph of (n + 1) vertices. Either it is a single cycle of length (n + 1), or it will have at least 1 leaf. We can delete the leaf and get a graph of n vertices and n edges, and use the Induction Hypothesis. ----- The Graph looks like a ring where each vertex is the root of a tree. Suppose the sizes of the subtree are (S1, S2, ... Sk) Instead of counting paths, let us count source-destination pairs. There are 2 types of pairs of vertices 1. Pairs within the same subtree 2. Pairs in different subtrees Pairs in the same subtree have only 1 path between them. Pairs in different subtrees have 2 paths between them because of the cycle. The cycle gives us exactly 2 paths between every pair of roots. Suppose we are processing the i-th subtree. The number of pairs of different trees = Si(S1 + S2 + ... + S{i - 1} + S{i + 1} + ... + Sk) In order to avoid overcounting this and ensuring each pair is only counted once, I only added it with the prefix. So pairs between S[3] and S[5], will be added to the total only when we are processing the 5-th subtree ------ void solve() { cin >> no_of_vertices; cycle.clear(); for(int i = 1; i <= no_of_vertices; i++) { graph[i].clear(); parent[i] = 0; visited[i] = false; lies_on_cycle[i] = false; } for(int i = 1; i <= no_of_vertices; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } long long remaining = 0; long long answer = 0; dfs(1, 0); for(int i = 0; i < cycle.size(); i++) { int v = cycle[i]; long long subtree_here = dfs_without_cycle(v, 0); long long inside = choose_2(subtree_here); long long inside_outside = 2*(subtree_here*remaining); //cout << "Multiplying 2 " << inside << " " << remaining << " = " << inside_outside << "\n"; answer += (inside + inside_outside); remaining += subtree_here; } cout << answer << "\n"; } ----- Here is how to DFS to find a cycle. Keep track of number of times a vertex is visited and the parent of each vertex. When we are visiting a vertex for the second time, we have found a cycle and must go back. void dfs(int v, int parent_v) { if(visited[v] == 2) { return ; } if(visited[v] == 1) { lies_on_cycle[v] = true; cycle.push_back(v); int u = parent_v; while(u != v) { cycle.push_back(u); lies_on_cycle[u] = true; u = parent[u]; visited[u] = 2; } return; } visited[v] = 1; parent[v] = parent_v; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); } visited[v] = 2; } ----- In order to DFS to find the size of the subtree rooted at v, do a normal DFS but ignore the neighbours of v on the cycle int dfs_without_cycle(int v, int parent_v) { int count = 1; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(child_v == parent_v || lies_on_cycle[child_v]) { continue; } count += dfs_without_cycle(child_v, v); } return count; } ================================================ FILE: 2020/Div 3/686 Div 3/Explanations/Sequence Transformation Explanation.txt ================================================ We will condense contiguous segments of 1 element into 1 element. Either they will be deleted together or they will never be touched. Now, let us look at the frequency of each segment. For each element A[i], we will count the number of operations required to make this the last element. If the frequency of segment[A[i]] is N, Then we will need to delete (N + 1) segments in general. We will need to delete (N - 1) segments that lie intermediately 1 prefix 1 suffix We need to separately check if A[i] is in the prefix or the suffix and update the number of operations accordingly. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map segment_frequency; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != A[i - 1]) { segment_frequency[A[i]]++; } } int minimum_operations = no_of_elements; for(map :: iterator it = segment_frequency.begin(); it != segment_frequency.end(); it++) { int operations_here = (it->second) + 1; if(A[1] == it->first) { operations_here--; } if(A[no_of_elements] == it->first) { operations_here--; } minimum_operations = min(minimum_operations, operations_here); } cout << minimum_operations << "\n"; } ================================================ FILE: 2020/Div 3/686 Div 3/Explanations/Special Permutation Explanation.txt ================================================ I printed one cyclic rotation of the matrix ----- void solve() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cout << i%no_of_elements + 1 << " "; } cout << "\n"; } ================================================ FILE: 2020/Div 3/686 Div 3/Explanations/Unique Bid Auction Explanation.txt ================================================ Look for the minimum integer who's frequency is 1 We can also do this by inserting everything into a set and printing the first element of the set. ----- void solve() { int no_of_elements; cin >> no_of_elements; map frequency; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; } const int oo = 1e9 + 9; int winner = -1, answer = oo; for(int i = 1; i <= no_of_elements; i++) { if(frequency[A[i]] == 1 && A[i] < answer) { answer = A[i]; winner = i; } } cout << winner << "\n"; } ================================================ FILE: 2020/Div 3/686 Div 3/Programs/Array Partition.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 2e5 + 5; vector indices[MAX_N]; vector A(MAX_N); void compress_coordinates(int no_of_elements) { vector sorted_A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sorted_A[i] = A[i]; } sort(sorted_A.begin(), sorted_A.end()); map label; label[sorted_A[1]] = 1; for(int i = 2; i <= no_of_elements; i++) { label[sorted_A[i]] = (sorted_A[i] == sorted_A[i - 1] ? label[sorted_A[i - 1]] : label[sorted_A[i - 1]] + 1); } for(int i = 1; i <= no_of_elements; i++) { A[i] = label[A[i]]; //cout << A[i] << " "; indices[A[i]].push_back(i); } } void compute_prefix_and_suffix_max(int no_of_elements, vector &prefix_maximum, vector &suffix_maximum) { for(int i = 1; i <= no_of_elements; i++) { prefix_maximum[i] = max(prefix_maximum[i - 1], A[i]); } for(int i = no_of_elements; i >= 1; i--) { suffix_maximum[i] = max(suffix_maximum[i + 1], A[i]); } } void compute_borders(int no_of_elements, vector &left_border, vector &right_border) { stack > left_S; left_S.push(make_pair(0, 0)); for(int i = 1; i <= no_of_elements; i++) { while(left_S.top().first >= A[i]) { //cout << left_S.top().first << " is greater than " << i << "\n"; left_S.pop(); } left_border[i] = left_S.top().second + 1; //cout << "Left " << i << " is " << left_border[i] << "\n"; left_S.push(make_pair(A[i], i)); } stack > right_S; right_S.push(make_pair(0, no_of_elements + 1)); for(int i = no_of_elements; i >= 1; i--) { while(right_S.top().first >= A[i]) { right_S.pop(); } right_border[i] = right_S.top().second - 1; //cout << "Right " << i << " = " << right_border[i] << "\n"; right_S.push(make_pair(A[i], i)); } } void solve() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; indices[i].clear(); } compress_coordinates(no_of_elements); vector prefix_maximum(no_of_elements + 1); vector suffix_maximum(no_of_elements + 5); compute_prefix_and_suffix_max(no_of_elements, prefix_maximum, suffix_maximum); vector left_border(no_of_elements + 1); vector right_border(no_of_elements + 1); compute_borders(no_of_elements, left_border, right_border); for(int i = 1; i <= no_of_elements; i++) { //cout << "For " << i << " is minimum in [" << left_border[i] << " " << right_border[i] << "]\n"; if(indices[A[i]].size() < 3 || i == indices[A[i]][0] || i == indices[A[i]].back()) { continue; } if(prefix_maximum[left_border[i] - 1] > A[i] || suffix_maximum[right_border[i] + 1] > A[i]) { continue; } int p = upper_bound(all(indices[A[i]]), left_border[i] - 2) - indices[A[i]].begin(); if(indices[A[i]][p] == i) { p--; } int s = lower_bound(all(indices[A[i]]), right_border[i] - 1) - indices[A[i]].begin(); if(s == indices[A[i]].size() || indices[A[i]][s] > right_border[i] + 1) { s--; } while(s < indices[A[i]].size() && indices[A[i]][s] <= i) { s++; } int prefix, suffix; //cout << "p = " << indices[A[i]][p] << " s = " << indices[A[i]][s] << "\n"; int left_possible = false; while(p >= 0) { prefix = max(indices[A[i]][p], left_border[i] - 1); //cout << "Prefix = " << prefix << " Maximum = " << prefix_maximum[prefix] << "\n"; if(prefix_maximum[prefix] == A[i]) { left_possible = true; break; } if(p < left_border[i] - 1) { break; } p--; } if(!left_possible) { continue; } int right_possible = false; while(s < indices[A[i]].size()) { suffix = min(indices[A[i]][s], right_border[i] + 1); //cout << "Prefix = " << suffix<< " Maximum = " << suffix_maximum[suffix] << "\n"; if(suffix_maximum[suffix] == A[i]) { right_possible = true; break; } if(s > right_border[i] + 1) { break; } s++; } if(!right_possible) { continue; } int part_1 = prefix, part_2 = (suffix - 1) - prefix; int part_3 = no_of_elements - (part_1 + part_2); cout << "YES\n"; cout << part_1 << " " << part_2 << " " << part_3 << "\n"; return; } cout << "NO\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) { solve(); } return 0; } ================================================ FILE: 2020/Div 3/686 Div 3/Programs/Number Into Sequence.cpp ================================================ #include #include using namespace std; void solve() { long long n; cin >> n; long long final_n = n; pair best_prime; vector > prime_exponents; for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { int exponent = 0; while(n%i == 0) { n /= i; exponent++; } prime_exponents.push_back(make_pair(exponent, i)); best_prime = max(best_prime, prime_exponents.back()); } } if(n > 1) { prime_exponents.push_back(make_pair(1, n)); best_prime = max(best_prime, prime_exponents.back()); } cout << best_prime.first << "\n"; for(int i = 1; i < best_prime.first; i++) { cout << best_prime.second << " "; final_n /= best_prime.second; } cout << final_n << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/686 Div 3/Programs/Number of Simple Paths.cpp ================================================ #include #include using namespace std; const int MAX_N = 5e5 + 5; int no_of_vertices; vector graph[MAX_N]; vector parent(MAX_N, 0); vector visited(MAX_N, false); vector lies_on_cycle(MAX_N, false); vector cycle; void dfs(int v, int parent_v) { if(visited[v] == 2) { return ; } if(visited[v] == 1) { lies_on_cycle[v] = true; cycle.push_back(v); int u = parent_v; while(u != v) { cycle.push_back(u); lies_on_cycle[u] = true; u = parent[u]; visited[u] = 2; } return; } visited[v] = 1; parent[v] = parent_v; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); } visited[v] = 2; } int dfs_without_cycle(int v, int parent_v) { int count = 1; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(child_v == parent_v || lies_on_cycle[child_v]) { continue; } count += dfs_without_cycle(child_v, v); } return count; } long long choose_2(long long n) { return (n*(n - 1))/2; } void solve() { cin >> no_of_vertices; cycle.clear(); for(int i = 1; i <= no_of_vertices; i++) { graph[i].clear(); parent[i] = 0; visited[i] = false; lies_on_cycle[i] = false; } for(int i = 1; i <= no_of_vertices; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } long long remaining = 0; long long answer = 0; dfs(1, 0); for(int i = 0; i < cycle.size(); i++) { int v = cycle[i]; long long subtree_here = dfs_without_cycle(v, 0); long long inside = choose_2(subtree_here); long long inside_outside = 2*(subtree_here*remaining); //cout << "Multiplying 2 " << inside << " " << remaining << " = " << inside_outside << "\n"; answer += (inside + inside_outside); remaining += subtree_here; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/686 Div 3/Programs/Sequence Transformation.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map segment_frequency; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != A[i - 1]) { segment_frequency[A[i]]++; } } int minimum_operations = no_of_elements; for(map :: iterator it = segment_frequency.begin(); it != segment_frequency.end(); it++) { int operations_here = (it->second) + 1; if(A[1] == it->first) { operations_here--; } if(A[no_of_elements] == it->first) { operations_here--; } minimum_operations = min(minimum_operations, operations_here); } cout << minimum_operations << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/686 Div 3/Programs/Special Permutation.cpp ================================================ #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cout << i%no_of_elements + 1 << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/686 Div 3/Programs/Unique Bid Auction.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; map frequency; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; } const int oo = 1e9 + 9; int winner = -1, answer = oo; for(int i = 1; i <= no_of_elements; i++) { if(frequency[A[i]] == 1 && A[i] < answer) { answer = A[i]; winner = i; } } cout << winner << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Div 3/Explanations/Number of Subsequences Explanation.txt ================================================ Let us iterate over the middle character. Let us fix the middle character at position i, This means that either S[i] = B or S[i] = ? ----- Now, we must arrange the prefix in such a way that there is at least 1 A and arrange the suffix in such a way there is at least 1 C. ----- Suppose there are a A's and q ?'s in the prefix of length i. Now, we must count the number of substrings possible here such that we get at least one A. There are two possibilities. 1. The A comes from one of the A's. There are 'a' different indices from which it can come. Each question mark can be replaced with any of the 3 characters (a, b, c). a.3^q 2. The A comes from one of the question marks. Each of the q question marks can be converted to an A and the other (q - 1) Question Marks can be converted to any of the 3 options. q.3^{q - 1} So, the total ways of choosing the prefix = (a.3^q + q.3^{q - 1}) Similarly, the total ways of choosing the suffix = (c.3^q + q.3^{q - 1}) We will multiply the number of ways of choosing the prefix with the number of ways of choosing the suffix to get the number of sequences centered at S[i]. ----- We will add them all to get the answer. ----- #include #include using namespace std; long long sum_till(long long n) { return (n*(n + 1))/2; } long long sum(long long L, long long R) { return sum_till(R) - sum_till(L - 1); } int main() { int length; string S; cin >> length >> S; vector prefix_questions(S.size() + 1, 0); vector prefix_a(S.size() + 1, 0); prefix_a[0] = (S[0] == 'a'); prefix_questions[0] = (S[0] == '?'); for(int i = 1; i < S.size(); i++) { prefix_a[i] = prefix_a[i - 1] + (S[i] == 'a'); prefix_questions[i] = prefix_questions[i - 1] + (S[i] == '?'); } vector suffix_questions(S.size() + 1, 0); vector suffix_c(S.size() + 1, 0); for(int i = S.size() - 1; i >= 0; i--) { suffix_c[i] = suffix_c[i + 1] + (S[i] == 'c'); suffix_questions[i] = suffix_questions[i + 1] + (S[i] == '?'); } const int MOD = 1e9 + 7; vector power_3(length + 1, 1); for(int i = 1; i <= length; i++) { power_3[i] = (3*power_3[i - 1])%MOD; } long long answer = 0; for(int i = 1; i < S.size() - 1; i++) { if(S[i] == 'b' || S[i] == '?') { long long a_s = prefix_a[i - 1], c_s = suffix_c[i + 1]; long long before_questions = prefix_questions[i - 1], after_questions = suffix_questions[i + 1]; long long prefix_value = (a_s*power_3[before_questions])%MOD + (before_questions > 0 ? (before_questions*power_3[before_questions - 1])%MOD : 0); prefix_value %= MOD; long long suffix_value = (c_s*power_3[after_questions])%MOD + (after_questions > 0 ? (after_questions*power_3[after_questions - 1] )%MOD : 0); suffix_value %= MOD; answer = (answer + prefix_value*suffix_value)%MOD; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Explanations/Berry Jam Explanation.txt ================================================ Let us make a few observations. We want to minimize the number of removals. This is the same as maximising the amount that we choose. In the end, we will be left with some prefix and with some suffix. Suppose we take (x1, y1) from the prefix and (x2, y2) from the suffix. x1 + x2 = y1 + y2 We can also write it as (x1 - y1) = (y2 - y1) We will maintain the prefix frequency of (x1 - y1) for each i. We will also maintain the suffix frequency of (y2 - x2) and also the index at which it reaches the given value. For each i, we will check that if we take i elements from the prefix, how many elements of the suffix do we have to take ? (It is possible that we will not get a good selection even if we select the entire suffix and we will deal with this case.) Please refer my code for more doubts. ----- void solve() { int no_of_jars; cin >> no_of_jars; vector A(2*no_of_jars + 1); for(int i = 1; i <= 2*no_of_jars; i++) { cin >> A[i]; } int suffix_1 = 0, suffix_2 = 0; map suffix_point; for(int i = 2*no_of_jars; i > no_of_jars; i--) { suffix_1 += (A[i] == 1); suffix_2 += (A[i] == 2); suffix_point[suffix_1 - suffix_2] = i; } int maximum_chosen = 0; int prefix_1 = 0, prefix_2 = 0; for(int i = 0; i <= no_of_jars; i++) { prefix_1 += (A[i] == 1); prefix_2 += (A[i] == 2); if(prefix_1 == prefix_2) { maximum_chosen = max(maximum_chosen, i); } if(suffix_point[prefix_2 - prefix_1] != 0) { int chosen_here = i + (2*no_of_jars - (suffix_point[prefix_2 - prefix_1] - 1)); maximum_chosen = max(maximum_chosen, chosen_here); } } int minimum_removals = 2*no_of_jars - maximum_chosen; cout << minimum_removals << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Explanations/Cards Explanation.txt ================================================ Temporary ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Explanations/Shuffle Hashing Explanation.txt ================================================ We can check if 2 strings are permutations of each other by comparing the frequency of all 26 alphabets. We will go through every substring of length |P| in H and check if it is a permutation of P. ----- void solve() { string password, hash; cin >> password >> hash; const int NO_OF_ALPHABETS = 26; vector password_frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < password.size(); i++) { password_frequency[password[i] - 'a']++; } int possible = false; for(int i = 0; i + password.size() <= hash.size() && !possible; i++) { vector hash_frequency(NO_OF_ALPHABETS, 0); for(int j = 0; j < password.size(); j++) { hash_frequency[hash[i + j] - 'a']++; } possible = true; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(password_frequency[alpha] != hash_frequency[alpha]) { possible = false; } } } cout << (possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Explanations/Tests for Problem D Explanation.txt ================================================ The right label for each vertex is more than the number of children it has. Then, one by one we will start labelling the children backwards so that they all intersect. ----- void dfs(int v, int parent_v) { //cout << "At " << v << "\n"; int no_of_children = tree[v].size() - (parent_v == 0 ? 0 : 1); available += no_of_children + 1; right_label[v] = available; //cout << "Size " << v << " = " << tree[v].size() << "\n"; for(int i = 0, child_no = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } child_no++; left_label[child_v] = right_label[v] - child_no; dfs(child_v, v); } } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Programs/A and B.cpp ================================================ #include using namespace std; int possible(int x, int d) { long long sum = x*(x + 1)/2; return (sum >= d && sum%2 == d%2); } void solve() { int a, b; cin >> a >> b; int moves = 0; while(!possible(moves, abs(a - b))) { moves++; } cout << moves << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Programs/Berry Jam.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_jars; cin >> no_of_jars; vector A(2*no_of_jars + 1); for(int i = 1; i <= 2*no_of_jars; i++) { cin >> A[i]; } int suffix_1 = 0, suffix_2 = 0; map suffix_point; for(int i = 2*no_of_jars; i > no_of_jars; i--) { suffix_1 += (A[i] == 1); suffix_2 += (A[i] == 2); suffix_point[suffix_1 - suffix_2] = i; } int maximum_chosen = 0; int prefix_1 = 0, prefix_2 = 0; for(int i = 0; i <= no_of_jars; i++) { prefix_1 += (A[i] == 1); prefix_2 += (A[i] == 2); if(prefix_1 == prefix_2) { maximum_chosen = max(maximum_chosen, i); } if(suffix_point[prefix_2 - prefix_1] != 0) { int chosen_here = i + (2*no_of_jars - (suffix_point[prefix_2 - prefix_1] - 1)); maximum_chosen = max(maximum_chosen, chosen_here); } } int minimum_removals = 2*no_of_jars - maximum_chosen; cout << minimum_removals << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Programs/Shuffle Hashing.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { string password, hash; cin >> password >> hash; const int NO_OF_ALPHABETS = 26; vector password_frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < password.size(); i++) { password_frequency[password[i] - 'a']++; } int possible = false; for(int i = 0; i + password.size() <= hash.size() && !possible; i++) { vector hash_frequency(NO_OF_ALPHABETS, 0); for(int j = 0; j < password.size(); j++) { hash_frequency[hash[i + j] - 'a']++; } possible = true; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(password_frequency[alpha] != hash_frequency[alpha]) { possible = false; } } } cout << (possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 78/Programs/Tests for Problem D.cpp ================================================ #include #include using namespace std; const int MAX_N = 5e5 + 5; int available = 1; vector tree[MAX_N]; int left_label[MAX_N], right_label[MAX_N]; void dfs(int v, int parent_v) { //cout << "At " << v << "\n"; int no_of_children = tree[v].size() - (parent_v == 0 ? 0 : 1); available += no_of_children + 1; right_label[v] = available; //cout << "Size " << v << " = " << tree[v].size() << "\n"; for(int i = 0, child_no = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } child_no++; left_label[child_v] = right_label[v] - child_no; //cout << "Child = " << child_v << "\n"; dfs(child_v, v); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); tree[u].push_back(v); tree[v].push_back(u); } left_label[1] = available; dfs(1, 0); for(int i = 1; i <= no_of_vertices; i++) { cout << left_label[i] << " " << right_label[i] << "\n"; } return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 79/Explanations/New Year Garland Explanation.txt ================================================ Let us assume there are (a1, a2, a3) stones. And a1 < a2 < a3 If a3 > a1 + a2 + 1, there have to be 2 consecutive flowers of a3. Otherwise, we will first place the a3 flowers. Then, we will put the flowers of type a1 in between the flowers from one end and flowers of type a2 in another end. ----- void solve() { long long red, green, blue; cin >> red >> green >> blue; long long total = red + green + blue; long long maximum = max_3(red, green, blue); long long remaining_sum = total - maximum; cout << (maximum <= remaining_sum + 1 ? "Yes\n" : "No\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 79/Explanations/Stack of Presents Explanation.txt ================================================ Here is the optimal idea. Every time we scan through the stack, we will place the gifts in such a way that any future query that can be answered will be answered. We will pick up the maximum index in A at each time. Every time we go to B[j], we will check if the index of B[j] < maximum. If yes, then it will be at the top of the stack when we have to pick it up. Else, if the index k > maximum, then we will update the maximum and take (2k + 1) seconds for this. ------ void solve() { int stack_presents, sent_presents; cin >> stack_presents >> sent_presents; vector A(stack_presents + 1); vector A_index(stack_presents + 1); for(int i = 1; i <= stack_presents; i++) { cin >> A[i]; A_index[A[i]] = i; } vector B(sent_presents + 1); for(int i = 1; i <= sent_presents; i++) { cin >> B[i]; } int max_inserted = 0; long long total_time = 0; for(int i = 1; i <= sent_presents; i++) { int effective_index = A_index[B[i]] - (i - 1); if(max_inserted > A_index[B[i]]) { effective_index = 1; } total_time += 2*(effective_index - 1) + 1; max_inserted = max(max_inserted, A_index[B[i]]); } cout << total_time << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 79/Explanations/Verse for Santa Explanation.txt ================================================ We have to look for any 1 point i, where the prefix sum (i) - prefix maximum(i) <= k ----- void solve() { int no_of_elements, maximum_seconds; cin >> no_of_elements >> maximum_seconds; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector sum_till(no_of_elements + 1, 0); vector max_till(no_of_elements + 1, 0); vector max_index(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; if(A[i] > max_till[i - 1]) { max_till[i] = A[i]; max_index[i] = i; } else { max_till[i] = max_till[i - 1]; max_index[i] = max_index[i - 1]; } } if(sum_till[no_of_elements] <= maximum_seconds) { cout << "0\n"; return; } for(int i = no_of_elements; i >= 1; i--) { if(sum_till[i] - max_till[i] <= maximum_seconds) { cout << max_index[i] << "\n"; return; } } } ================================================ FILE: 2020/Educational Rounds/Educational Round 79/Programs/New Year Garland.cpp ================================================ #include using namespace std; long long max_3(long long a, long long b, long long c) { return max(a, max(b, c)); } void solve() { long long red, green, blue; cin >> red >> green >> blue; long long total = red + green + blue; long long maximum = max_3(red, green, blue); long long remaining_sum = total - maximum; cout << (maximum <= remaining_sum + 1 ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 79/Programs/Stack of Presents.cpp ================================================ #include #include using namespace std; void solve() { int stack_presents, sent_presents; cin >> stack_presents >> sent_presents; vector A(stack_presents + 1); vector A_index(stack_presents + 1); for(int i = 1; i <= stack_presents; i++) { cin >> A[i]; A_index[A[i]] = i; } vector B(sent_presents + 1); for(int i = 1; i <= sent_presents; i++) { cin >> B[i]; } int max_inserted = 0; long long total_time = 0; for(int i = 1; i <= sent_presents; i++) { int effective_index = A_index[B[i]] - (i - 1); if(max_inserted > A_index[B[i]]) { effective_index = 1; } total_time += 2*(effective_index - 1) + 1; max_inserted = max(max_inserted, A_index[B[i]]); } cout << total_time << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 79/Programs/Verse for Santa.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements, maximum_seconds; cin >> no_of_elements >> maximum_seconds; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector sum_till(no_of_elements + 1, 0); vector max_till(no_of_elements + 1, 0); vector max_index(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; if(A[i] > max_till[i - 1]) { max_till[i] = A[i]; max_index[i] = i; } else { max_till[i] = max_till[i - 1]; max_index[i] = max_index[i - 1]; } } if(sum_till[no_of_elements] <= maximum_seconds) { cout << "0\n"; return; } for(int i = no_of_elements; i >= 1; i--) { if(sum_till[i] - max_till[i] <= maximum_seconds) { cout << max_index[i] << "\n"; return; } } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Explanations/Deadline Explanation.txt ================================================ It can be proven that the actual answer will be near square root(d). (We can check this by taking the derivative of the function and setting it to 0). I did a heuristic where I just checked the first 10^6 integers as it is guaranteed to be within the square root of d. ----- void solve() { int n, d; cin >> n >> d; if(d <= n) { cout << "YES\n"; return; } const int N = 2e6; for(int x = 1; x <= min(n, N); x++) { int optimised_d = ceil(d, x + 1); //cout << "d = " << optimised_d << " x = " << x << "\n"; if(optimised_d + x <= n) { cout << "YES\n"; return; } } cout << "NO\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Explanations/Minimax Problem Explanation.txt ================================================ Let us try to binary search the answer. How do we check if it is possible to get x as the minimum element of 2 arrays after such an operation ? We can create a bitmask corresponding to each array. A[i] = 1 if A[i] >= x A[i] = 0 if A[i] < x We will get two bitmasks. When we perform the bitwise OR of the two masks, we will get a 1 if the resulting array has an element >= x and a 0 otherwise. So, to check if a given value of x is possible, we will create a 8-bit bitmask for each array. We will then check if it is possible for us to have 2 arrays such that their bitwise OR results in a bitmask having all ones - 11111111 If yes, then it is possible. We will binary search for the best value of x. We will maintain the invariant that it is always possible to have the minimum >= L and it is never possible to have the minimum >= R Ultimately, L is the best value that the minimum can have. ----- int possible(int x, int &i, int &j) { map map_index; for(int i = 1; i <= no_of_arrays; i++) { int mask = 0; for(int j = 1; j <= no_of_elements; j++) { if(A[i][j] < x) continue; mask |= (1 << (j - 1)); } map_index[mask] = i; } int full_mask = (1 << no_of_elements) - 1; for(auto it = map_index.begin(); it != map_index.end(); it++) { int mask = it->first; for(int m = 0; m <= full_mask; m++) { if((mask|m) == full_mask && map_index.find(m) != map_index.end()) { i = map_index[mask]; j = map_index[m]; return true; } } } return false; } int main() { scanf("%d %d", &no_of_arrays, &no_of_elements); for(int i = 1; i <= no_of_arrays; i++) { for(int j = 1; j <= no_of_elements; j++) { scanf("%d", &A[i][j]); } } int left = 0, right = 1e9 + 1; int best_i = 1, best_j = 1; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, best_i, best_j)) { left = mid; } else { right = mid; } } printf("%d %d\n", best_i, best_j); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Explanations/Two Arrays Alternate Solution Explanation.txt ================================================ https://qr.ae/TVI1Ht int main() { precompute(); int n, length; cin >> n >> length; long long answer = combinations(n + 2*length - 1, 2*length); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Explanations/Two Arrays Explanation.txt ================================================ https://qr.ae/TVI1Ht int main() { precompute(); int n, length; cin >> n >> length; long long answer = 0; for(int a_ending = 1; a_ending <= n; a_ending++) { for(int b_ending = a_ending; b_ending <= n; b_ending++) { answer += (count(1, a_ending, length)*count(b_ending, n, length))%MOD; answer %= MOD; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Explanations/Yet Another Meme Problem Explanation.txt ================================================ a.b + a + b = 10^d a + b, where d is the number of digits of b a.b = a(10^d - 1) b = 10^d - 1 b is a string of all 9s, and a can be any integer in the range ----- void solve() { int a, b; cin >> a >> b; //a.b + a + b = 10a + b => a.b = 9a => a.b = 9a => b = 9 //a.b + a + b = 100a + b => a.b = 99a => b = 99 long long no_of_pairs = 0; for(long long i = 10; i - 1 <= b; i *= 10) { no_of_pairs += a; } cout << no_of_pairs << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Programs/Deadline.cpp ================================================ #include using namespace std; int ceil(int n, int d) { return (n/d + (n%d != 0)); } void solve() { int n, d; cin >> n >> d; if(d <= n) { cout << "YES\n"; return; } const int N = 2e6; for(int x = 1; x <= min(n, N); x++) { int optimised_d = ceil(d, x + 1); //cout << "d = " << optimised_d << " x = " << x << "\n"; if(optimised_d + x <= n) { cout << "YES\n"; return; } } cout << "NO\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Programs/Minimax Problem.cpp ================================================ #include #include using namespace std; const int MAX_A = 3e5 + 5, MAX_N = 8 + 1; int no_of_arrays, no_of_elements; long long A[MAX_A][MAX_N]; int possible(int x, int &i, int &j) { map map_index; for(int i = 1; i <= no_of_arrays; i++) { int mask = 0; for(int j = 1; j <= no_of_elements; j++) { if(A[i][j] < x) continue; mask |= (1 << (j - 1)); } map_index[mask] = i; } int full_mask = (1 << no_of_elements) - 1; for(auto it = map_index.begin(); it != map_index.end(); it++) { int mask = it->first; for(int m = 0; m <= full_mask; m++) { if((mask|m) == full_mask && map_index.find(m) != map_index.end()) { i = map_index[mask]; j = map_index[m]; return true; } } } return false; } int main() { scanf("%d %d", &no_of_arrays, &no_of_elements); for(int i = 1; i <= no_of_arrays; i++) { for(int j = 1; j <= no_of_elements; j++) { scanf("%d", &A[i][j]); } } int left = 0, right = 1e9 + 1; int best_i = 1, best_j = 1; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, best_i, best_j)) { left = mid; } else { right = mid; } } printf("%d %d\n", best_i, best_j); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Programs/Two Arrays Alternate Solution.cpp ================================================ #include using namespace std; const int MAX_N = 1e5 + 5, MOD = 1e9 + 7; long long factorial[MAX_N + 5], inverse_factorial[MAX_N + 5]; long long power(long long x, long long p) { long long result = 1; while(p) { if(p%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; p /= 2; } return result; } void precompute() { factorial[0] = 1; for(int i = 1; i <= MAX_N; i++) { factorial[i] = (i*factorial[i - 1])%MOD; } inverse_factorial[MAX_N] = power(factorial[MAX_N], MOD - 2); for(int i = MAX_N - 1; i >= 0; i--) { //i*(i - 1)! = i! => (i - 1)!^ = i!^ i inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } } long long combinations(long long n, long long k) { if(n < k) { return 0; } long long numerator = factorial[n]; long long denominator_inverse = (inverse_factorial[k]*inverse_factorial[n - k])%MOD; return (numerator*denominator_inverse)%MOD; } int main() { precompute(); int n, length; cin >> n >> length; long long answer = combinations(n + 2*length - 1, 2*length); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Programs/Two Arrays.cpp ================================================ #include using namespace std; const int MAX_N = 1e5 + 5, MOD = 1e9 + 7; long long factorial[MAX_N + 5], inverse_factorial[MAX_N + 5]; long long power(long long x, long long p) { long long result = 1; while(p) { if(p%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; p /= 2; } return result; } void precompute() { factorial[0] = 1; for(int i = 1; i <= MAX_N; i++) { factorial[i] = (i*factorial[i - 1])%MOD; } inverse_factorial[MAX_N] = power(factorial[MAX_N], MOD - 2); for(int i = MAX_N - 1; i >= 0; i--) { //i*(i - 1)! = i! => (i - 1)!^ = i!^ i inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } } long long combinations(long long n, long long k) { if(n < k) { return 0; } long long numerator = factorial[n]; long long denominator_inverse = (inverse_factorial[k]*inverse_factorial[n - k])%MOD; //cout << "C(" << n << "," << k << ") = " << (numerator*denominator_inverse)%MOD << endl; return (numerator*denominator_inverse)%MOD; } //Number of strings of length N consisting of numbers in [L, R] long long count(long long left, long long right, long long length) { //Either first or last element is fixed long long stars = length - 1; long long bars = right - left; return combinations(stars + bars, stars); } int main() { precompute(); int n, length; cin >> n >> length; long long answer = 0; for(int a_ending = 1; a_ending <= n; a_ending++) { for(int b_ending = a_ending; b_ending <= n; b_ending++) { answer += (count(1, a_ending, length)*count(b_ending, n, length))%MOD; answer %= MOD; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 80/Programs/Yet Another Meme Problem.cpp ================================================ #include using namespace std; int digit_count(int n) { int count = 0; while(n) { n /= 10; count++; } return count; } void solve() { int a, b; cin >> a >> b; //a.b + a + b = 10a + b => a.b = 9a => a.b = 9a => b = 9 //a.b + a + b = 100a + b => a.b = 99a => b = 99 long long no_of_pairs = 0; for(long long i = 10; i - 1 <= b; i *= 10) { no_of_pairs += a; } cout << no_of_pairs << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Explanation/Display the Number Explanation.txt ================================================ Given two integers, the one with the larger length is always larger. 1. First, we will try to maximise the length 2. The digit with the minimum cost is 1 3. So, we will put as many 1s as possible 4. If n is even, then we can just put all 1s 5. If n is odd, we will have one segment left over. So we can try using it. 6. 7 costs only 3 segments. So, we will replace one of the 1s with 7 7. Out of all the 1s, it is optimal to replace the 1 which comes first from the left as it is the most significant. ------ oid solve() { int n; scanf("%d", &n); int no_of_1s = 0, no_of_7s = 0; if(n%2 == 0) { no_of_1s = n/2; } else { no_of_1s = (n - 3)/2; no_of_7s = 1; } if(no_of_7s > 0) { printf("7"); } for(int i = 1; i <= no_of_1s; i++) { printf("1"); } printf("\n"); return; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Explanation/Infinite Prefixes Explanation.txt ================================================ Let balance [i] denote the balance of the first i characters. Let us now check if there is some point at which the balance x can be arrived at the i-th characters This means that the entire string will be concatenated some number of times (possibly 0) and then the i-th character will be added. What we are essentially checking is if there is a non-negative integer q such that q(balance[n]) + balance[i] = x ------ We will go through the string and for each character S[i], check if it is possible to end at i with balance x after some concatenations. ----- When are there an infinite number of answers ? This happens when balance[n] = 0 and at some point balance[i] = x This will ensure that every concatenation will result in balance[i] = x as the balance becomes 0 at the end each time ------ void solve() { int length, balance; cin >> length >> balance; string S; cin >> S; vector frequency(2, 0); for(int i = 0; i < length; i++) { frequency[S[i] - '0']++; } int whole_balance = frequency[0] - frequency[1]; int no_of_prefixes = (balance == 0 ? 1 : 0); frequency[0] = 0; frequency[1] = 0; for(int i = 0; i < length; i++) { frequency[S[i] - '0']++; int prefix_balance = frequency[0] - frequency[1]; if(whole_balance != 0 && ((balance - prefix_balance)%whole_balance == 0 && (balance - prefix_balance)/whole_balance >= 0)) { no_of_prefixes++; } if(whole_balance == 0 && prefix_balance == balance) { cout << "-1\n"; return; } } cout << no_of_prefixes << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Explanation/Obtain the String Explanation.txt ================================================ We will be greedy in constructing the string. 1. Initially we have matches 0 characters 2. We will then look for the earliest location of T[0] 3. Then, we will look for the earliest location in [0, n] in S for T[0]. Let this position be p. 4. Then, we will look for the earliest location in [p, n] in S for T[1] 5. If T[1] is not present in [p, n] but is in [0, p - 1], we will go back and start another subsequence. ----- void solve() { string S, T; cin >> S >> T; const int NO_OF_ALPHABETS = 26; vector > locations(NO_OF_ALPHABETS); for(int i = 0; i < S.size(); i++) { locations[S[i] - 'a'].push_back(i); } int operations = 1, last_matched = -1; for(int i = 0; i < T.size(); i++) { if(locations[T[i] - 'a'].size() == 0) { cout << "-1\n"; return; } auto it = upper_bound(locations[T[i] - 'a'].begin(), locations[T[i] - 'a'].end(), last_matched); //cout << "At "<< T[i] << "\n"; if(it == locations[T[i] - 'a'].end()) { operations++; last_matched = locations[T[i] - 'a'][0]; } else { last_matched = *it; } } cout << operations << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Explanation/Same GCDs Explanation.txt ================================================ 1. If gcd(a, m) = gcd(a + x, m), then x is a multiple of m 2. a = m = 0 (mod g). This means that x has to be = 0 (mod g) 3. We only have to be careful of the case when gcd(a + x, m) = q.g i.e. some multiple of g > 1 4. We can divide everything by g. Then, gcd(a' + x', m') = 1 5. Given that gcd(a', m') = 1 ----- 1. Now, we need to count the number of integers gcd(a' + x', m') = 1 2. gcd(a' + x', m') = gcd( (a' + x') (mod m'), m') 3. gcd(a' + x', m) = 1 only if gcd( (a' + x') (mod m'), m') = 1 4. This means we have to count the number of integers that are coprime to m'. As x only goes from [0, m), this means we only need to consider (m' - 1) integers smaller than m' 5. This is the Euler Totient of m' ----- #include #include using namespace std; long long gcd(long long x, long long y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } long long totient(long long n) { long long totient = 1; for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { while(n%i == 0) { n /= i; totient *= i; } totient /= i; totient *= (i - 1); } } if(n > 1) { totient *= 1*(n - 1); } return totient; } void solve() { long long a, m; cin >> a >> m; long long g = gcd(a, m); long long answer = totient(m/g); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Programs/Display the Number.cpp ================================================ #include #include using namespace std; void solve() { int n; scanf("%d", &n); int no_of_1s = 0, no_of_7s = 0; if(n%2 == 0) { no_of_1s = n/2; } else { no_of_1s = (n - 3)/2; no_of_7s = 1; } if(no_of_7s > 0) { printf("7"); } for(int i = 1; i <= no_of_1s; i++) { printf("1"); } printf("\n"); return; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Programs/Infinite Prefixes.cpp ================================================ #include #include using namespace std; void solve() { int length, balance; cin >> length >> balance; string S; cin >> S; vector frequency(2, 0); for(int i = 0; i < length; i++) { frequency[S[i] - '0']++; } int whole_balance = frequency[0] - frequency[1]; int no_of_prefixes = (balance == 0 ? 1 : 0); frequency[0] = 0; frequency[1] = 0; for(int i = 0; i < length; i++) { frequency[S[i] - '0']++; int prefix_balance = frequency[0] - frequency[1]; if(whole_balance != 0 && ((balance - prefix_balance)%whole_balance == 0 && (balance - prefix_balance)/whole_balance >= 0)) { no_of_prefixes++; } if(whole_balance == 0 && prefix_balance == balance) { cout << "-1\n"; return; } } cout << no_of_prefixes << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Programs/Obtain the String.cpp ================================================ #include #include #include #include #define all(v) (v).begin, (v).end() using namespace std; void solve() { string S, T; cin >> S >> T; const int NO_OF_ALPHABETS = 26; vector > locations(NO_OF_ALPHABETS); for(int i = 0; i < S.size(); i++) { locations[S[i] - 'a'].push_back(i); } int operations = 1, last_matched = -1; for(int i = 0; i < T.size(); i++) { if(locations[T[i] - 'a'].size() == 0) { cout << "-1\n"; return; } auto it = upper_bound(locations[T[i] - 'a'].begin(), locations[T[i] - 'a'].end(), last_matched); //cout << "At "<< T[i] << "\n"; if(it == locations[T[i] - 'a'].end()) { operations++; last_matched = locations[T[i] - 'a'][0]; } else { last_matched = *it; } } cout << operations << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 81/Programs/Same GCDs.cpp ================================================ #include #include using namespace std; long long gcd(long long x, long long y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } long long totient(long long n) { long long totient = 1; for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { while(n%i == 0) { n /= i; totient *= i; } totient /= i; totient *= (i - 1); } } if(n > 1) { totient *= 1*(n - 1); } return totient; } void solve() { long long a, m; cin >> a >> m; long long g = gcd(a, m); long long answer = totient(m/g); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Explanations/Erasing Zeroes Explanation.txt ================================================ We will count the number of 0s in between the leftmost 1 and the rightmost 1 ---- void solve() { string S; cin >> S; int left_one = -1, right_one = -1; for(int i = S.size() - 1; i >= 0; i--) { if(S[i] == '1') { left_one = i; } } for(int i = 0; i < S.size(); i++) { if(S[i] == '1') { right_one = i; } } int zeroes = 0; for(int i = left_one; i <= right_one; i++) { if(S[i] == '0') { zeroes++; } } cout << zeroes << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Explanations/National Project Explanation.txt ================================================ Let us notice that if we can finish it in x days, then we can also finish it in (x + 1) days If we cannot finish it in x days, then we cannot finish it in (x - 1) days This enables us to use binary search ! ------ For a given x, we will check if it is possible to finish ! int possible(long long x, long long n, long long g, long long b) { long long half = ceil(n, 2); long long no_of_cycles = x/(g + b); long long extra = x - no_of_cycles*(g + b); long long extra_good = 0, extra_bad = 0; if(extra > 0) { extra_good = min(g, extra); extra -= extra_good; } if(extra > 0) { extra_bad = min(b, extra); extra -= extra_bad; } long long total_good = no_of_cycles*g + extra_good; long long total_bad = no_of_cycles*b + extra_bad; if(total_good < half|| total_good + total_bad < n) { return false; } return true; } ----- We will do binary search over x and find the best possible x We will maintain the invariant that it is not possible in <= L days and always possible in >= R days When (R - L = 1), it is possible ----- void solve() { long long no_of_days, good_days, bad_days; cin >> no_of_days >> good_days >> bad_days; const long long oo = 1e18; long long left = 0, right = oo; while(right - left > 1) { long long mid = (left + right)/2; if(possible(mid, no_of_days, good_days, bad_days)) { right = mid; } else { left = mid; } } cout << right << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Explanations/Perfect Keyboard Explanation.txt ================================================ 1. Draw a graph The vertices are the alphabets and the edges are drawn between consecutive characters. We have to be careful about not adding the same edge twice. This is very important. for(int i = 1; i < password.size(); i++) { if(adjacency[password[i] - 'a'][password[i - 1] - 'a'] == false) { adjacency[password[i] - 'a'][password[i - 1] - 'a'] = true; adjacency[password[i - 1] - 'a'][password[i] - 'a'] = true; graph[password[i] - 'a'].push_back(password[i - 1] - 'a'); graph[password[i - 1] - 'a'].push_back(password[i] - 'a'); degree[password[i] - 'a']++; degree[password[i - 1] - 'a']++; } } ---- 2. If any vertex has degree > 2, it is not possible as any key can only have 2 neighbours for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(degree[alpha] > 2) { cout << "NO\n"; return; } } ----- 3. Now, we must look at each connected component of the graph seperately. We must find the component number of each vertex. We can do this by performing a series of DFS int component = 1; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(component_no[alpha] == 0) { dfs(alpha, -1, component++); } } ----- Here is the DFS itself void dfs(int v, int parent_v, int c) { //cout << "V = " << v << " C = " << c << "\n"; component_no[v] = c; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(child_v == parent_v || component_no[child_v] == c) { continue; } dfs(child_v, v, c); } } ----- 4. Every component will be printed together. So, first we will print characters of component 1, then characters of component 2, and so on. ----- 5. How to print characters of a given component ? There have to be 2 vertices in this component of degree 1 and every other vertex must have degree 2. We will start from one of the vertices of degree 1 and keep going till we reach the vertex of degree 2 If the component is of size 1, then we can just print it Otherwise, we will look for the first border and then DFS till we reach the second border for(int c = 1; c < component; c++) { vector this_component; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(component_no[alpha] == c) { this_component.push_back(alpha); } } if(this_component.size() == 1) { keyboard += (char)('a' + this_component[0]); used[this_component[0]] = true; continue; } int border_1 = -1, border_2 = -1; for(int i = 0; i < this_component.size(); i++) { if(degree[this_component[i]] == 1) { if(border_1 == -1) border_1 = this_component[i]; else border_2 = this_component[i]; } } if(border_1 == -1 || border_2 == -1) { cout << "NO\n"; return; } keyboard += (char)('a' + border_1); used[border_1] = true; while(keyboard.back() - 'a' != border_2) { for(int i = 0; i < graph[keyboard.back() - 'a'].size(); i++) { if(!used[graph[keyboard.back() - 'a'][i]]) { int next = graph[keyboard.back() - 'a'][i]; keyboard += (char)('a' + next); used[next] = true; break; } } } } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Programs/Erasing Zeroes.cpp ================================================ #include using namespace std; void solve() { string S; cin >> S; int left_one = -1, right_one = -1; for(int i = S.size() - 1; i >= 0; i--) { if(S[i] == '1') { left_one = i; } } for(int i = 0; i < S.size(); i++) { if(S[i] == '1') { right_one = i; } } int zeroes = 0; for(int i = left_one; i <= right_one; i++) { if(S[i] == '0') { zeroes++; } } cout << zeroes << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Programs/Fill the Bag.cpp ================================================ #include #include using namespace std; int is_bit_set(long long n, int bit) { return ( (n&(1LL << bit)) != 0); } void solve() { long long n, no_of_boxes; cin >> n >> no_of_boxes; const int MAX_BITS = 61; long long sum = 0; vector frequency(MAX_BITS, 0); for(int i = 1; i <= no_of_boxes; i++) { long long box; cin >> box; for(int bit = 0; bit < MAX_BITS; bit++) { if( (1LL << bit) == box) { frequency[bit]++; } } sum += box; } if(sum < n) { cout << "-1\n"; return; } int minimum_divisions = 0; for(int bit = 0; bit < MAX_BITS; bit++) { if(bit >= 1) frequency[bit] += frequency[bit - 1]/2; if(is_bit_set(n, bit) && frequency[bit] == 0) { int source; for(source = bit; source < MAX_BITS; source++) { if(frequency[source] >= 1) { break; } } //cout << "Source = " << source << " Bit = " << bit << "\n"; for(int i = source; i > bit; i--) { frequency[i]--; frequency[i - 1] += 2; minimum_divisions++; } } if(is_bit_set(n, bit)) { frequency[bit]--; } } cout << minimum_divisions << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Programs/National Project.cpp ================================================ #include using namespace std; long long ceil(long long n, long long d) { return (n/d + (n%d != 0)); } int possible(long long x, long long n, long long g, long long b) { long long half = ceil(n, 2); long long no_of_cycles = x/(g + b); long long extra = x - no_of_cycles*(g + b); long long extra_good = 0, extra_bad = 0; if(extra > 0) { extra_good = min(g, extra); extra -= extra_good; } if(extra > 0) { extra_bad = min(b, extra); extra -= extra_bad; } long long total_good = no_of_cycles*g + extra_good; long long total_bad = no_of_cycles*b + extra_bad; if(total_good < half|| total_good + total_bad < n) { return false; } return true; } void solve() { long long no_of_days, good_days, bad_days; cin >> no_of_days >> good_days >> bad_days; const long long oo = 1e18; long long left = 0, right = oo; while(right - left > 1) { long long mid = (left + right)/2; if(possible(mid, no_of_days, good_days, bad_days)) { right = mid; } else { left = mid; } } cout << right << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 82/Programs/Perfect Keyboard.cpp ================================================ #include #include using namespace std; const int NO_OF_ALPHABETS = 26; vector degree(NO_OF_ALPHABETS, 0); vector graph[NO_OF_ALPHABETS]; vector component_no(NO_OF_ALPHABETS, 0); void dfs(int v, int parent_v, int c) { //cout << "V = " << v << " C = " << c << "\n"; component_no[v] = c; for(int i = 0; i < graph[v].size(); i++) { int child_v = graph[v][i]; if(child_v == parent_v || component_no[child_v] == c) { continue; } dfs(child_v, v, c); } } void solve() { string password; cin >> password; const int NO_OF_ALPHABETS = 26; vector > adjacency(NO_OF_ALPHABETS, vector (NO_OF_ALPHABETS, false)); for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { degree[alpha] = 0; graph[alpha].clear(); component_no[alpha] = 0; } for(int i = 1; i < password.size(); i++) { if(adjacency[password[i] - 'a'][password[i - 1] - 'a'] == false) { adjacency[password[i] - 'a'][password[i - 1] - 'a'] = true; adjacency[password[i - 1] - 'a'][password[i] - 'a'] = true; graph[password[i] - 'a'].push_back(password[i - 1] - 'a'); graph[password[i - 1] - 'a'].push_back(password[i] - 'a'); degree[password[i] - 'a']++; degree[password[i - 1] - 'a']++; } } for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(degree[alpha] > 2) { cout << "NO\n"; return; } } int component = 1; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(component_no[alpha] == 0) { dfs(alpha, -1, component++); } } string keyboard; vector components; vector used(NO_OF_ALPHABETS, false); for(int c = 1; c < component; c++) { vector this_component; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(component_no[alpha] == c) { this_component.push_back(alpha); } } if(this_component.size() == 1) { keyboard += (char)('a' + this_component[0]); used[this_component[0]] = true; continue; } int border_1 = -1, border_2 = -1; for(int i = 0; i < this_component.size(); i++) { if(degree[this_component[i]] == 1) { if(border_1 == -1) border_1 = this_component[i]; else border_2 = this_component[i]; } } if(border_1 == -1 || border_2 == -1) { cout << "NO\n"; return; } keyboard += (char)('a' + border_1); used[border_1] = true; while(keyboard.back() - 'a' != border_2) { for(int i = 0; i < graph[keyboard.back() - 'a'].size(); i++) { if(!used[graph[keyboard.back() - 'a'][i]]) { int next = graph[keyboard.back() - 'a'][i]; keyboard += (char)('a' + next); used[next] = true; break; } } } } cout << "YES\n"; cout << keyboard << "\n"; return; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Explanations/Adding Powers Explanation.txt ================================================ We will precompute all the powers of k we need Then, we will go through each element of the array. We will write it in base K. If any digit is > 1, then it is not possible We will keep track of all the powers we have used so far and ensure there is no repetition ----- void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector power; power.push_back(1); while(power.back() <= 1e16/k) { power.push_back(power.back()*k); } int possible = true; map used; for(int i = 1; i <= no_of_elements; i++) { long long x = A[i]; for(int p = power.size() - 1; p >= 0 && x > 0; p--) { //cout << "X = " << x << " P = " << power[p] << "\n"; if(x < power[p]) { continue; } if(used[p]) { possible = false; break; } x -= power[p]; if(x >= power[p]) { possible = false; break; } used[p] = true; } } cout << (possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Explanations/Array Shrinking Explanation.txt ================================================ Let final(L, R) be the final element in [L, R] if it is possible to reduce [L, R] to a single element and - 1 otherwise. We can build this recursively. It is possible to reduce [L, R] to a single element if there exists an i such that [L, i] is reducible and [i + 1, R] is reducible and final[L, i] = final[i + 1, R] ----- We will build up final(L, R) for all (L, R) pairs in O(n^3) time Now let Answer(i) be the minimum number of parts we can divide the first i elements into A segment [L, R] is said to be a part if it can be reduced to 1 number f(i) = min(1 + f(j - 1)), for all j such that [j, i] is reducible to 1 number ----- The answer is f(n) ------ int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int NOT_REDUCIBLE = -1, oo = 1e9; vector > final_element(no_of_elements + 1, vector (no_of_elements + 1)); for(int length = 1; length <= no_of_elements; length++) { for(int left = 1, right = left + length - 1; right <= no_of_elements; left++, right++) { final_element[left][right] = NOT_REDUCIBLE; if(length == 1) { final_element[left][right] = A[left]; continue; } for(int i = left; i < right; i++) { if(final_element[left][i] != NOT_REDUCIBLE && final_element[left][i] == final_element[i + 1][right]) { final_element[left][right] = final_element[left][i] + 1; } } } } vector minimum_parts(no_of_elements + 1, oo); minimum_parts[0] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int j = 1; j <= i; j++) { if(final_element[j][i] == NOT_REDUCIBLE) { continue; } minimum_parts[i] = min(minimum_parts[i], minimum_parts[j - 1] + 1); } } cout << minimum_parts[no_of_elements] << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Explanations/Bogosort Explanation.txt ================================================ We will sort A in descending order For any (i < j), (A[i] >= A[j]) So, A[i] - i != A[j] - j ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); reverse(all(A)); for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Explanations/Count the Arrays Explanation.txt ================================================ First, of all we should choose (n - 1) distinct integers from m integers. This can be done in C(m, n - 1) Secondly, we should choose one element which occurs 2 times. This cannot be the maximum integer but can be any of the other integers. So there are (n - 2) ways of doing this Now, each of the integers, except the maximum and the 2 duplicates can either coming in the ascending part or the descending part. So, there are 2^{n - 3} ways of doing this 1. We select integers -> C(m, n - 1) 2. We choose the duplicates -> (n - 2) 3. We choose which side each of the (n - 3) integers are -> 2^{n - 3} ----- int main() { precompute_factorials(); long long no_of_elements, m; cin >> no_of_elements >> m; if(no_of_elements == 2) { cout << "0\n"; return 0; } long long answer = (choose(m, no_of_elements - 1)*(no_of_elements - 2))%MOD; answer *= power(2, no_of_elements - 3); answer %= MOD; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Explanations/Two Regular Polygons Explanation.txt ================================================ The inscribed polygon must also be a regular polygon so that means it's vertices must be equally spaced This means that m must evenly divide n ----- void solve() { int original_vertices, new_vertices; cin >> original_vertices >> new_vertices; cout << (original_vertices%new_vertices == 0 ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Programs/Adding Powers.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector power; power.push_back(1); while(power.back() <= 1e16/k) { power.push_back(power.back()*k); } int possible = true; map used; for(int i = 1; i <= no_of_elements; i++) { long long x = A[i]; for(int p = power.size() - 1; p >= 0 && x > 0; p--) { //cout << "X = " << x << " P = " << power[p] << "\n"; if(x < power[p]) { continue; } if(used[p]) { possible = false; break; } x -= power[p]; if(x >= power[p]) { possible = false; break; } used[p] = true; } } cout << (possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Programs/Array Shrinking.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int NOT_REDUCIBLE = -1, oo = 1e9; vector > final_element(no_of_elements + 1, vector (no_of_elements + 1)); for(int length = 1; length <= no_of_elements; length++) { for(int left = 1, right = left + length - 1; right <= no_of_elements; left++, right++) { final_element[left][right] = NOT_REDUCIBLE; if(length == 1) { final_element[left][right] = A[left]; continue; } for(int i = left; i < right; i++) { if(final_element[left][i] != NOT_REDUCIBLE && final_element[left][i] == final_element[i + 1][right]) { final_element[left][right] = final_element[left][i] + 1; } } } } vector minimum_parts(no_of_elements + 1, oo); minimum_parts[0] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int j = 1; j <= i; j++) { if(final_element[j][i] == NOT_REDUCIBLE) { continue; } minimum_parts[i] = min(minimum_parts[i], minimum_parts[j - 1] + 1); } } cout << minimum_parts[no_of_elements] << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Programs/Bogosort.cpp ================================================ #include #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); reverse(all(A)); for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Programs/Count the Arrays.cpp ================================================ #include #include using namespace std; const int MOD = 998244353, MAX_N = 5e5 + 5; vector factorials(MAX_N + 1, 0), inverse_factorials(MAX_N + 1, 0); long long power(long long x, long long p) { long long answer = 1; while(p) { if(p%2 == 1) { answer = (answer*x)%MOD; } x = (x*x)%MOD; p = p/2; } return answer; } long long inverse(long long n) { return power(n, MOD - 2); } void precompute_factorials() { factorials[0] = 1; for(int i = 1; i < MAX_N; i++) { factorials[i] = (factorials[i - 1]*i)%MOD; } //i*(i - 1)! = i! inverse_factorials[MAX_N - 1] = inverse(factorials[MAX_N - 1]); for(int i = MAX_N - 2; i >= 0; i--) { inverse_factorials[i] = ((i + 1)*inverse_factorials[i + 1])%MOD; } } long long choose(long long n, long long r) { long long numerator = factorials[n]; long long inverse_denominator = (inverse_factorials[r]*inverse_factorials[n - r])%MOD; return (numerator*inverse_denominator)%MOD; } int main() { precompute_factorials(); long long no_of_elements, m; cin >> no_of_elements >> m; if(no_of_elements == 2) { cout << "0\n"; return 0; } long long answer = (choose(m, no_of_elements - 1)*(no_of_elements - 2))%MOD; answer *= power(2, no_of_elements - 3); answer %= MOD; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 83/Programs/Two Regular Polygons.cpp ================================================ #include using namespace std; void solve() { int original_vertices, new_vertices; cin >> original_vertices >> new_vertices; cout << (original_vertices%new_vertices == 0 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 84/Explanations/Count the Blocks Explanation.txt ================================================ Let us suppose we are dealing with blocks of length i 1. How many ways are there of making this particular block ? 10 2. How many ways are there to choose it's neighbour ? The neighbour must be a different digit. If i = n, then there is no neighbour Otherwise, if the block is at the beginning or the end, there is 1 neighbour If the block is in the middle, there are 2 neighbours We will deal with both cases separately. Each neighbour can take on any of 9 choices 3. Where are the positions where we can place the block ? If the block is in the beginning, it can be placed in 2 ways. If the block is in the middle, then it can be placed in (n - i - 1) ways. It can't be placed in any of the last (n - i) places as there isn't enough room It can't be placed in the beginning too. That's why it is (n - i - 1) ------ The remaining digits can be filled in any order apart from the block and it's neighbour ------ i = n, then 10 ways End = 2.10.9.10^(n - i - 1) Middle = (n - i - 2).10.9^2.10^(n - i - 2) ---- Please note that we do not have to worry about overcounting because if a block occurs 2 times in the same number, then the block should be counted twice ----- int main() { int length; cin >> length; const int MOD = 998244353; for(int i = 1; i <= length; i++) { if(i == length) { cout << "10\n"; break; } long long no_of_spots = 2, ways_for_block = 10, neighbour = 9; long long remaining = power(10, length - i - 1, MOD); long long corners = (no_of_spots*ways_for_block)*neighbour; corners = (corners*remaining)%MOD; no_of_spots = length - i - 1, ways_for_block = 10, neighbour = 9*9; remaining = power(10, length - i - 2, MOD); long long middle = (no_of_spots*ways_for_block)*neighbour; middle = (middle*remaining)%MOD; long long blocks_here = (corners + middle)%MOD; cout << blocks_here << " "; } return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 84/Explanations/Sum of Odd Integers Explanation.txt ================================================ The minimum sum we can get is the sum of the first k odd integers n has to be >= that After that, we can increase the last odd integer in steps of 2 as much as we want. The sum of the first k odd integers and the total sum have to have the same parity. ----- #include using namespace std; void solve() { long long n, no_of_summands; cin >> n >> no_of_summands; //k(k + 1)/2 long long min_sum = (no_of_summands/2)*(2*no_of_summands - 1 + 1) + (no_of_summands%2)*no_of_summands; //cout << "S = " << min_sum << "\n"; cout << (min_sum <= n && min_sum%2 == n%2 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 84/Programs/Count the Blocks.cpp ================================================ #include using namespace std; long long power(long long x, long long p, long long mod) { long long answer = 1; while(p) { if(p%2) { answer = (answer*x)%mod; } x = (x*x)%mod; p = p/2; } return answer; } int main() { int length; cin >> length; const int MOD = 998244353; for(int i = 1; i <= length; i++) { if(i == length) { cout << "10\n"; break; } long long no_of_spots = 2, ways_for_block = 10, neighbour = 9; long long remaining = power(10, length - i - 1, MOD); long long corners = (no_of_spots*ways_for_block)*neighbour; corners = (corners*remaining)%MOD; no_of_spots = length - i - 1, ways_for_block = 10, neighbour = 9*9; remaining = power(10, length - i - 2, MOD); long long middle = (no_of_spots*ways_for_block)*neighbour; middle = (middle*remaining)%MOD; long long blocks_here = (corners + middle)%MOD; cout << blocks_here << " "; } return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 84/Programs/Sum of Odd Integers.cpp ================================================ #include using namespace std; void solve() { long long n, no_of_summands; cin >> n >> no_of_summands; //k(k + 1)/2 long long min_sum = (no_of_summands/2)*(2*no_of_summands - 1 + 1) + (no_of_summands%2)*no_of_summands; //cout << "S = " << min_sum << "\n"; cout << (min_sum <= n && min_sum%2 == n%2 ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Explanations/Circle of Monsters Explanation.txt ================================================ Observation - For any given monster, if it's neighbour is killed before it, the number of bullets can only be reduced. It cannot increase. ----- Step 1 - We will count the total cost when every monster has his neighbour killed first long long total = 0; for(int i = 1; i <= no_of_monsters; i++) { if(i == 1) { total += (B[no_of_monsters] >= A[1] ? 0 : A[1] - B[no_of_monsters]); continue; } total += (B[i - 1] >= A[i] ? 0 : A[i] - B[i - 1]); } ----- Step 2 - Only 1 element should be killed without it's neighbour being killed first There is only 1 element at most which should be killed 'alone' If the i-th element is killed first, then we will be spending A[i] on it We have counted that we will be spending (B[i - 1] - A[i]) bullets on A[i] If i-th element is first, the total increases by [A[i] - (B[i - 1] - A[i])] We will choose the element which causes the total to increase the least ----- long long effective_hit = max(A[1] - B[no_of_monsters], 0LL); long long best_first = A[1] - effective_hit; for(int i = 2; i <= no_of_monsters; i++) { effective_hit = max(A[i] - B[i - 1], 0LL); best_first = min(best_first, A[i] - effective_hit); } total += best_first; ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Explanations/Divisor Paths Explanation.txt ================================================ Claim - The optimal path from x to y is x -> gcd(x, y) -> y Every edge corresponds to 2 things - Multiplying by a prime or dividing by a prime To go from x to y, we will have to remove every factor that x has and y does not And then add every factor that y has and x does not Suppose we divide by some prime p which both x and y have, we have to multiply it again This adds 2p to our total path length Suppose we multiply by some prime that y does not have, we have to later divide by p too This also adds 2p to our total path length. This clearly shows that it is never optimal to add or remove any extra factors. We will start from x and go to gcd(x, y) and go from there to y ----- Now, let us see how to count the number of paths from X to G Let us look at each prime factor seperately Let us suppose we have to multiply G by p1^a1 p2^a2 ... pk^ak in order to get X ---- We have to make a total of (a1 + a2 + ... + ak) steps This can be done in (a1 + a2 + ... + ak)! ways But, we can interchange any two steps of multiplying by the same prime and get the same path So, we have to divide by (a1)! (a2)! ... (ak)! ----- We will precompute the factorials and inverse factorials beforehand along with the prime factors of D ---- #include #include using namespace std; const int MOD = 998244353, MAX_N = 1e6 + 5; vector primes, factorial(MAX_N), inverse_factorial(MAX_N); long long gcd(long long x, long long y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } long long power_mod(long long x, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } void factorise(long long d) { for(long long i = 2; i*i <= d; i++) { if(d%i == 0) { primes.push_back(i); while(d%i == 0) { d /= i; } } } if(d > 1) { primes.push_back(d); } } void precompute_factorial() { factorial[0] = 1; for(int i = 1; i < MAX_N; i++) { factorial[i] = (i*factorial[i - 1])%MOD; } //i*(i - 1)! = i! => (i - 1)!^ = i!^i inverse_factorial[MAX_N - 1] = power_mod(factorial[MAX_N - 1], MOD - 2); for(int i = MAX_N - 2; i >= 0; i--) { inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } } //Here y is a divisor of x, by convention long long get_count(long long x, long long y) { if(x%y != 0) { return -1; } vector path; for(int i = 0; i < primes.size(); i++) { int x_exponent = 0, y_exponent = 0; if(x%primes[i] != 0) { continue; } while(y%primes[i] == 0) { y /= primes[i]; y_exponent++; } while(x%primes[i] == 0) { x /= primes[i]; x_exponent++; } path.push_back(x_exponent - y_exponent); } int total_steps = 0; for(int i = 0; i < path.size(); i++) { total_steps += path[i]; } long long answer = factorial[total_steps]; for(int i = 0; i < path.size(); i++) { answer = (answer*inverse_factorial[path[i]])%MOD; } return answer; } int main() { precompute_factorial(); long long d; int no_of_queries; cin >> d >> no_of_queries; factorise(d); while(no_of_queries--) { long long x, y; cin >> x >> y; long long path_1 = get_count(x, gcd(x, y)); long long path_2 = get_count(y, gcd(x, y)); long long answer = (path_1*path_2)%MOD; cout << answer << "\n"; } return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Explanations/Level Statistics Explanation.txt ================================================ We just need to simulate and check the conditions P[i - 1] <= P[i] and C[i - 1] <= C[i] and (C[i] - C[i - 1] <= P[i] - P[i - 1]) ----- void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); vector C(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i] >> C[i]; } int possible = true; for(int i = 1; i <= no_of_elements; i++) { if(P[i - 1] > P[i] || C[i - 1] > C[i]) { possible = false; } if(C[i] - C[i - 1] > P[i] - P[i - 1]) { possible = false; } } cout << (possible ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Explanations/Middle Class Explanation.txt ================================================ Let us sort the elements in descending order A[1] >= A[2] >= A[3] >= .... >= A[N] If we apply the operation on [1, i], then A[1] = A[2] = ... = A[i] = Sum/i This means, that it is possible to make the first i people >= x If Sum[1, i] >= i*x We will check the length of the maximum such prefix we can make >= x ----- This is the optimal way. If we replace any of the elements by a smaller element, the segment average can only decrease ----- void solve() { long long no_of_elements, x; cin >> no_of_elements >> x; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); long long sum = 0; int answer = 0; for(int i = no_of_elements; i >= 1; i--) { sum += A[i]; if(sum < (answer + 1)*x) { break; } answer++; } cout << answer << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Explanations/Minimum Euler Cycle Explanation.txt ================================================ For n = 7, the optimal strategy looks like this 1 2 1 3 1 4 1 5 1 6 1 7 2 3 2 4 2 5 2 6 2 7 3 4 3 5 3 6 3 7 4 5 4 6 4 7 5 6 5 7 6 7 1 Let us call each of these steps a 'segment' Segment 1 - 1 2 1 3 1 4 1 5 1 6 1 7 Segment 2 - 2 3 2 4 2 5 2 6 2 7 Segment 3 - 3 4 3 5 3 6 3 7 Segment 4 - 4 5 4 6 4 7 Segment 5 - 5 6 5 7 Segment 6 - 6 7 Segment 7 - 1 Apart from the last segment, segment i has 2(7 - i) elements ----- We can utilise this pattern to print all the integers from i = L to i = R First, we will find out which 'segment' L is in The point inside the segment where L is will be called the in_point. For convenience, in_point will always point to the even position (The odd positions in a segment will always be the segment number) ----- void solve() { int n; long long left, right; scanf("%d %I64d %I64d",&n, &left, &right); long long segment = 0, in_point = 0; for(long long i = 1, sum = 0; i <= n; i++) { long long new_sum = sum + 2*(n - i); if(i == n) { new_sum++; } if(new_sum >= left) { segment = i; in_point = (left - sum)/2 + i + (left - sum)%2; break; } sum = new_sum; } for(long long i = left; i <= right; ) { if(segment == n) { printf("1 "); break; } if(i%2 == 0) { printf("%I64d ", in_point); in_point++; i++; } else { printf("%I64d ", segment); i++; if(i > right) { break; } printf("%I64d ", in_point); in_point++; i++; } if(in_point == n + 1) { segment++; in_point = segment + 1; } } printf("\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Programs/Circle of Monsters.cpp ================================================ #include #include using namespace std; void solve() { int no_of_monsters; scanf("%d", &no_of_monsters); vector A(no_of_monsters + 1), B(no_of_monsters + 1); for(int i = 1; i <= no_of_monsters; i++) { scanf("%I64d %I64d", &A[i], &B[i]); } long long total = 0; for(int i = 1; i <= no_of_monsters; i++) { if(i == 1) { total += (B[no_of_monsters] >= A[1] ? 0 : A[1] - B[no_of_monsters]); continue; } total += (B[i - 1] >= A[i] ? 0 : A[i] - B[i - 1]); } long long effective_hit = max(A[1] - B[no_of_monsters], 0LL); long long best_first = A[1] - effective_hit; for(int i = 2; i <= no_of_monsters; i++) { effective_hit = max(A[i] - B[i - 1], 0LL); best_first = min(best_first, A[i] - effective_hit); } total += best_first; printf("%I64d\n", total); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Programs/Divisor Paths.cpp ================================================ #include #include using namespace std; const int MOD = 998244353, MAX_N = 1e6 + 5; vector primes, factorial(MAX_N), inverse_factorial(MAX_N); long long gcd(long long x, long long y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } long long power_mod(long long x, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } void factorise(long long d) { for(long long i = 2; i*i <= d; i++) { if(d%i == 0) { primes.push_back(i); while(d%i == 0) { d /= i; } } } if(d > 1) { primes.push_back(d); } } void precompute_factorial() { factorial[0] = 1; for(int i = 1; i < MAX_N; i++) { factorial[i] = (i*factorial[i - 1])%MOD; } //i*(i - 1)! = i! => (i - 1)!^ = i!^i inverse_factorial[MAX_N - 1] = power_mod(factorial[MAX_N - 1], MOD - 2); for(int i = MAX_N - 2; i >= 0; i--) { inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } } //Here y is a divisor of x, by convention long long get_count(long long x, long long y) { if(x%y != 0) { return -1; } vector path; for(int i = 0; i < primes.size(); i++) { int x_exponent = 0, y_exponent = 0; if(x%primes[i] != 0) { continue; } while(y%primes[i] == 0) { y /= primes[i]; y_exponent++; } while(x%primes[i] == 0) { x /= primes[i]; x_exponent++; } path.push_back(x_exponent - y_exponent); } int total_steps = 0; for(int i = 0; i < path.size(); i++) { total_steps += path[i]; } long long answer = factorial[total_steps]; for(int i = 0; i < path.size(); i++) { answer = (answer*inverse_factorial[path[i]])%MOD; } return answer; } int main() { precompute_factorial(); long long d; int no_of_queries; cin >> d >> no_of_queries; factorise(d); while(no_of_queries--) { long long x, y; cin >> x >> y; long long path_1 = get_count(x, gcd(x, y)); long long path_2 = get_count(y, gcd(x, y)); long long answer = (path_1*path_2)%MOD; cout << answer << "\n"; } return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Programs/Level Statistics.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); vector C(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i] >> C[i]; } int possible = true; for(int i = 1; i <= no_of_elements; i++) { if(P[i - 1] > P[i] || C[i - 1] > C[i]) { possible = false; } if(C[i] - C[i - 1] > P[i] - P[i - 1]) { possible = false; } } cout << (possible ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Programs/Middle Class.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { long long no_of_elements, x; cin >> no_of_elements >> x; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); long long sum = 0; int answer = 0; for(int i = no_of_elements; i >= 1; i--) { sum += A[i]; if(sum < (answer + 1)*x) { break; } answer++; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 85/Programs/Minimum Euler Cycle.cpp ================================================ #include using namespace std; void solve() { int n; long long left, right; scanf("%d %I64d %I64d",&n, &left, &right); long long segment = 0, in_point = 0; for(long long i = 1, sum = 0; i <= n; i++) { long long new_sum = sum + 2*(n - i); if(i == n) { new_sum++; } if(new_sum >= left) { segment = i; in_point = (left - sum)/2 + i + (left - sum)%2; break; } sum = new_sum; } for(long long i = left; i <= right; ) { if(segment == n) { printf("1 "); break; } if(i%2 == 0) { printf("%I64d ", in_point); in_point++; i++; } else { printf("%I64d ", segment); i++; if(i > right) { break; } printf("%I64d ", in_point); in_point++; i++; } if(in_point == n + 1) { segment++; in_point = segment + 1; } } printf("\n"); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) { solve(); } return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 86/Explanations/Binary Period Explanation.txt ================================================ If the string consists of only 0s or only 1s, then the period is 1 and we can print S as it is Otherwise, we can always achieve a period of 2. It is always possible to make the string 0101010101 or 101010101 Whenever we are about to add S[i], we will check if S[i] = S[i - 1]. If yes, then we will put in the other character in between. If (S[i] != S[i - 1]), then we will add S[i] as it is. This ensures that S is a subsequence of T and that T has period 2 T cannot have period 1 so period 2 is the minimum ----- void solve() { string S; cin >> S; if(is_periodic(S, 1)) { cout << S << "\n"; return; } string answer; for(int i = 0; i < S.size(); i++) { if(answer.size() == 0 || S[i] != answer.back()) { answer += S[i]; } else { answer += other(S[i]); answer += S[i]; } } cout << answer << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 86/Explanations/Road to Zero Explanation.txt ================================================ If the cost for making 2 single hits is less than 1 double hit, then we will use all single hits Otherwise, we will make as many double hits as we can and then use single hits. ----- #include using namespace std; void solve() { long long x, y, single, both; cin >> x >> y >> single >> both; long long total = 0; if(2*single <= both) { total = (x + y)*single; } else { total += min(x, y)*both; total += (max(x, y) - min(x, y))*single; } cout << total << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 86/Explanations/Yet Another Counting Problem Explanation.txt ================================================ Claim - Let us write 1 if an integer satisfies the property (x mod a) mod b != (x mod b) mod a And write a 0 otherwise. This pattern will be cyclic about the LCM(A, B) ----- For example, if A = 4, B = 6 0 0 0 0 0 1 1 1 1 1 1 0 This is the pattern for [1, 12] and this pattern continually repeats ----- Proof - x mod a = (x mod LCM) mod a x mod b = (x mod LCM) mod b So, (x mod a) mod b = ( (x mod LCM) mod a ) mod b and (x mod b) mod a = ( (x mod LCM) mod b ) mod a Whether (x mod a) mod b = (x mod b) mod a is true or not, it remains the same if we replace x by (x mod LCM) ----- So, it is clear that the patter in cyclic over LCM ----- Now, to answer each query, We will find the Count(R) - Count(L - 1) How to find Count(x) ? Where Count(x) is the number of 1's till x The pattern is cyclic about LCM so we will find out the number of 'complete cycles' till x This is equal to (X/LCM) Every complete cycle has Count(LCM) ones And then we will have Count(X mod LCM) ones So, all we have to do is precompute the number of 1s in [1, LCM] and then (X/LCM) C[LCM] + C[LCM mod X] ----- long long gcd(long long x, long long y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } long long get_count(vector &sum, long long lcm, long long N) { long long full_cycles = N/lcm; return full_cycles*sum[lcm] + sum[N%lcm]; } void solve() { int a, b, no_of_queries; cin >> a >> b >> no_of_queries; if(a > b) { swap(a, b); } long long lcm = (a*b)/gcd(a, b); vector good_integers_sum(lcm + 1, 0); for(int i = 1; i <= lcm; i++) { good_integers_sum[i] = good_integers_sum[i - 1] + ( (i%a)%b != (i%b)%a ); } while(no_of_queries--) { long long left, right; cin >> left >> right; long long answer = get_count(good_integers_sum, lcm, right) - get_count(good_integers_sum, lcm, left - 1); cout << answer << " "; } cout << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 86/Programs/Binary Period.cpp ================================================ #include #include using namespace std; int is_periodic(string S, int period) { for(int i = 0; i < S.size(); i++) { //cout << "Comparing " << S[i] << " and " << S[i%period] << "\n"; if(S[i] != S[i%period]) { return false; } } return true; } char other(char ch) { return (ch == '0' ? '1' : '0'); } void solve() { string S; cin >> S; if(is_periodic(S, 1)) { cout << S << "\n"; return; } string answer; for(int i = 0; i < S.size(); i++) { if(answer.size() == 0 || S[i] != answer.back()) { answer += S[i]; } else { answer += other(S[i]); answer += S[i]; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 86/Programs/Road to Zero.cpp ================================================ #include using namespace std; void solve() { long long x, y, single, both; cin >> x >> y >> single >> both; long long total = 0; if(2*single <= both) { total = (x + y)*single; } else { total += min(x, y)*both; total += (max(x, y) - min(x, y))*single; } cout << total << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 86/Programs/Yet Another Counting Problem.cpp ================================================ #include #include using namespace std; long long gcd(long long x, long long y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } long long get_count(vector &sum, long long lcm, long long N) { long long full_cycles = N/lcm; return full_cycles*sum[lcm] + sum[N%lcm]; } void solve() { int a, b, no_of_queries; cin >> a >> b >> no_of_queries; if(a > b) { swap(a, b); } long long lcm = (a*b)/gcd(a, b); vector good_integers_sum(lcm + 1, 0); for(int i = 1; i <= lcm; i++) { good_integers_sum[i] = good_integers_sum[i - 1] + ( (i%a)%b != (i%b)%a ); } while(no_of_queries--) { long long left, right; cin >> left >> right; long long answer = get_count(good_integers_sum, lcm, right) - get_count(good_integers_sum, lcm, left - 1); cout << answer << " "; } cout << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Explanations/01 Game Explanation.txt ================================================ We will either delete all the 1s or all the 0s Each deletion will remove 1 of each. So the number of deletions is equal to the number of 1s or 0s, whichever is minimum We just have to check the parity of the total number of moves to determine the winner. ----- void solve() { string S; cin >> S; int zeroes = 0, ones = 0; for(int i = 0; i < S.size(); i++) { if(S[i] == '0') { zeroes++; } else { ones++; } } int no_of_moves = min(zeroes, ones); cout << (no_of_moves%2 == 1 ? "DA\n" : "NET\n"); } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Explanations/Donut Shops Explanation.txt ================================================ If the cost of 1 donut is less than the cost of a box, then the answer is 1 Otherwise, it is impossible to buy donuts to be cheaper. As for the second shop, we will try to buy a box. If it is cheaper, then that is the answer. Otherwise, it is not possible ----- void solve() { long long cost, box_size, box_cost; cin >> cost >> box_size >> box_cost; int answer_1 = (cost < box_cost ? 1 : -1); int answer_2 = (cost*box_size > box_cost ? box_size : -1); cout << answer_1 << " " << answer_2 << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Explanations/Maximum Sum on Even Positions Explanation.txt ================================================ We can extend the idea of Kandane's algorithm. We will keep track of the sum of the even positions and the amount the sum will increase by If the segment we flip ends at i, what does the even position sum change by ? If i is even, the sum changes by (A[i - 1] - A[i] + max(0, changes[i - 2])) If i is odd, the sum changes by (-A[i] + A[i - 1] + max(0, changes[i - 2])) ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } long long sum = 0; for(int i = 0; i < no_of_elements; i += 2) { sum += A[i]; } vector max_changes_here(no_of_elements + 1); for(int i = 1; i < no_of_elements; i++) { if(i == 1) { max_changes_here[i] = A[i] - A[i - 1]; continue; } if(i%2 == 1) { max_changes_here[i] = max(A[i] - A[i - 1], A[i] - A[i - 1] + max_changes_here[i - 2]); } else { max_changes_here[i] = max(-A[i] + A[i - 1], -A[i] + A[i - 1] + max_changes_here[i - 2]); } } long long max_changes = 0; for(int i = 0; i < no_of_elements; i++) { max_changes = max(max_changes, max_changes_here[i]); } sum += max_changes; cout << sum << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Explanations/Pluses and Minuses Explanation.txt ================================================ If we perform i iterations in the second loop, res will increase by i each time We need to know the initial balance necessary to go through the array without the sum being 0 If the balance goes below 0 at some point, we update the initial balance and try again ----- void solve() { string S; cin >> S; long long res = 0; for(long long i = 0, balance = 0, initial_balance = 0; i < S.size(); i++) { if(S[i] == '+') { balance++; } else { balance--; } if(initial_balance + balance < 0) { int no_of_retries = abs(initial_balance + balance); initial_balance += no_of_retries; res += no_of_retries*(i + 1); } } res += S.size(); cout << res << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Programs/01 Game.cpp ================================================ #include using namespace std; void solve() { string S; cin >> S; int zeroes = 0, ones = 0; for(int i = 0; i < S.size(); i++) { if(S[i] == '0') { zeroes++; } else { ones++; } } int no_of_moves = min(zeroes, ones); cout << (no_of_moves%2 == 1 ? "DA\n" : "NET\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Programs/Donut Shops.cpp ================================================ #include using namespace std; void solve() { long long cost, box_size, box_cost; cin >> cost >> box_size >> box_cost; int answer_1 = (cost < box_cost ? 1 : -1); int answer_2 = (cost*box_size > box_cost ? box_size : -1); cout << answer_1 << " " << answer_2 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Programs/Maximum Sum on Even Positions.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } long long sum = 0; for(int i = 0; i < no_of_elements; i += 2) { sum += A[i]; } vector max_changes_here(no_of_elements + 1); for(int i = 1; i < no_of_elements; i++) { if(i == 1) { max_changes_here[i] = A[i] - A[i - 1]; continue; } if(i%2 == 1) { max_changes_here[i] = max(A[i] - A[i - 1], A[i] - A[i - 1] + max_changes_here[i - 2]); } else { max_changes_here[i] = max(-A[i] + A[i - 1], -A[i] + A[i - 1] + max_changes_here[i - 2]); } } long long max_changes = 0; for(int i = 0; i < no_of_elements; i++) { max_changes = max(max_changes, max_changes_here[i]); } sum += max_changes; cout << sum << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 90/Programs/Pluses and Minuses.cpp ================================================ #include #include using namespace std; void solve() { string S; cin >> S; long long res = 0; for(long long i = 0, balance = 0, initial_balance = 0; i < S.size(); i++) { if(S[i] == '+') { balance++; } else { balance--; } if(initial_balance + balance < 0) { int no_of_retries = abs(initial_balance + balance); initial_balance += no_of_retries; res += no_of_retries*(i + 1); } } res += S.size(); cout << res << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 92/Explanations/Good String Explanation.txt ================================================ t2 t3 t4 ... tn t1 tn t1 t2 ... t(n - 2) t(n - 1) t2 = tn = t4 = t6 = ... t1 = t3 = t4 = t7 = t9 = ... The even characters are the same The odd characters are the same There can be at most two characters We will check both possibilities - 1. When there is only one digit This is the digit with the highest frequency 2. When there are two digits (x, y) We will find the longest alternating subsequence of (x, y) for all 100 pairs This will cause 10^7 iterations When it is alternating, the length of the subsequence has to be even ----- int get_length(int x, int y, string &S) { int length = 0; for(int i = 0; i < S.size(); i++) { if(length%2 == 0) { if(S[i] == '0' + x) { length++; } } else { if(S[i] == '0' + y) { length++; } } } if(length%2 == 1) { length--; } return length; } void solve() { string S; cin >> S; const int NO_OF_DIGITS = 10; vector frequency(NO_OF_DIGITS, 0); for(int i = 0; i < S.size(); i++) { frequency[S[i] - '0']++; } sort(frequency.begin(), frequency.end()); reverse(frequency.begin(), frequency.end()); int maximum_length = frequency[0]; for(int i = 0; i < NO_OF_DIGITS; i++) { for(int j = 0; j < NO_OF_DIGITS; j++) { maximum_length = max(maximum_length, get_length(i, j, S)); } } int minimum_deletions = S.size() - maximum_length; cout << minimum_deletions << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 92/Programs/Good String.cpp ================================================ #include #include #include using namespace std; int get_length(int x, int y, string &S) { int length = 0; for(int i = 0; i < S.size(); i++) { if(length%2 == 0) { if(S[i] == '0' + x) { length++; } } else { if(S[i] == '0' + y) { length++; } } } if(length%2 == 1) { length--; } return length; } void solve() { string S; cin >> S; const int NO_OF_DIGITS = 10; vector frequency(NO_OF_DIGITS, 0); for(int i = 0; i < S.size(); i++) { frequency[S[i] - '0']++; } sort(frequency.begin(), frequency.end()); reverse(frequency.begin(), frequency.end()); int maximum_length = frequency[0]; for(int i = 0; i < NO_OF_DIGITS; i++) { for(int j = 0; j < NO_OF_DIGITS; j++) { maximum_length = max(maximum_length, get_length(i, j, S)); } } int minimum_deletions = S.size() - maximum_length; cout << minimum_deletions << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Explanations/Bad Triangle Explanation.txt ================================================ If there is a solution, then (A[1], A[2], A[n]) is also a solution. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } if(A[1] + A[2] <= A[no_of_elements]) { cout << "1 2 " << no_of_elements << "\n"; return ; } cout << "-1\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Explanations/Colored Rectangles Explanation.txt ================================================ Let us maintain a DP. Let f(i, j, k) be the maximum among the first i reds, first j greens and first k blues Let us sort the Reds, Greens and Blues before this. To determine, f(i, j, k), we will consider all 3 values - 1. R[i]G[j] + f(i - 1, j - 1, k) 2. G[j]B[k] + f(i, j - 1, k - 1) 3. B[k]R[i] + f(i - 1, j, k - 1) We also have to handle the base case of 0s carefully ----- int main() { int red, green, blue; cin >> red >> green >> blue; vector R(red + 1); for(int i = 1; i <= red; i++) { cin >> R[i]; } sort(all(R)); vector G(green + 1); for(int i = 1; i <= green; i++) { cin >> G[i]; } sort(all(G)); vector B(blue + 1); for(int i = 1; i <= blue; i++) { cin >> B[i]; } sort(all(B)); for(int i = 0; i <= red; i++) { for(int j = 0; j <= green; j++) { for(int k = 0; k <= blue; k++) { if( (i == 0 && j == 0 && k == 0) || (any_two_zero(i, j, k)) ) { max_till[i][j][k] = 0; continue; } if(i == 0) { max_till[i][j][k] = G[j]*B[k] + max_till[i][j - 1][k - 1]; continue; } if(j == 0) { max_till[i][j][k] = B[k]*R[i] + max_till[i - 1][j][k - 1]; continue; } if(k == 0) { //cout << "R = " << R[i] << " and B = " << B[j] << "\n"; max_till[i][j][k] = R[i]*G[j] + max_till[i - 1][j - 1][k]; //cout << "F(" << i << "," << j << "," << k << ") = " << max_till[i][j][k] << "\n"; continue; } max_till[i][j][k] = R[i]*G[j] + max_till[i - 1][j - 1][k]; max_till[i][j][k] = max(max_till[i][j][k], G[j]*B[k] + max_till[i][j - 1][k - 1]); max_till[i][j][k] = max(max_till[i][j][k], B[k]*R[i] + max_till[i - 1][j][k - 1]); //cout << "F(" << i << "," << j << "," << k << ") = " << max_till[i][j][k] << "\n"; } } } cout << max_till[red][green][blue] << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Explanations/Good Subarrays Explanation.txt ================================================ Sum[R] - Sum[L - 1] = R - (L - 1) Sum[R] - R = Sum[L - 1] - (L - 1) ----- Let us define a quantity called f(i) f(i) = Sum[i] - i We have to count the number of pairs (i, j) in F where the values are the same. This can be done with a simple frequency map ----- void solve() { int no_of_elements; cin >> no_of_elements; string S; cin >> S; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { A[i] = S[i - 1] - '0'; } vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; } long long no_of_pairs = 0; map frequency; frequency[0] = 1; for(int i = 1; i <= no_of_elements; i++) { long long value_here = sum_till[i] - i; no_of_pairs += frequency[value_here]; frequency[value_here]++; } cout << no_of_pairs << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Explanations/Substring Removal Game Explanation.txt ================================================ Let us store the lengths of all the segments of contiguous characters The players take the greatest length available at each move ----- void solve() { string S; cin >> S; int current_length = 0; vector lengths; for(int i = 0; i < S.size(); i++) { if(S[i] == '1') { current_length++; if(i + 1 == S.size()) { lengths.push_back(current_length); } } else { if(current_length > 0) { lengths.push_back(current_length); current_length = 0; } } } sort(lengths.begin(), lengths.end()); reverse(lengths.begin(), lengths.end()); int total = 0; for(int i = 0; i < lengths.size(); i += 2) { total += lengths[i]; } cout << total << "\n"; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Programs/Bad Triangle.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } if(A[1] + A[2] <= A[no_of_elements]) { cout << "1 2 " << no_of_elements << "\n"; return ; } cout << "-1\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Programs/Colored Rectangles.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 222; long long max_till[MAX_N][MAX_N][MAX_N]; int any_two_zero(int r, int g, int b) { int zeroes = (r == 0) + (g == 0) + (b == 0); return (zeroes >= 2); } int main() { int red, green, blue; cin >> red >> green >> blue; vector R(red + 1); for(int i = 1; i <= red; i++) { cin >> R[i]; } sort(all(R)); vector G(green + 1); for(int i = 1; i <= green; i++) { cin >> G[i]; } sort(all(G)); vector B(blue + 1); for(int i = 1; i <= blue; i++) { cin >> B[i]; } sort(all(B)); for(int i = 0; i <= red; i++) { for(int j = 0; j <= green; j++) { for(int k = 0; k <= blue; k++) { if( (i == 0 && j == 0 && k == 0) || (any_two_zero(i, j, k)) ) { max_till[i][j][k] = 0; continue; } if(i == 0) { max_till[i][j][k] = G[j]*B[k] + max_till[i][j - 1][k - 1]; continue; } if(j == 0) { max_till[i][j][k] = B[k]*R[i] + max_till[i - 1][j][k - 1]; continue; } if(k == 0) { //cout << "R = " << R[i] << " and B = " << B[j] << "\n"; max_till[i][j][k] = R[i]*G[j] + max_till[i - 1][j - 1][k]; //cout << "F(" << i << "," << j << "," << k << ") = " << max_till[i][j][k] << "\n"; continue; } max_till[i][j][k] = R[i]*G[j] + max_till[i - 1][j - 1][k]; max_till[i][j][k] = max(max_till[i][j][k], G[j]*B[k] + max_till[i][j - 1][k - 1]); max_till[i][j][k] = max(max_till[i][j][k], B[k]*R[i] + max_till[i - 1][j][k - 1]); //cout << "F(" << i << "," << j << "," << k << ") = " << max_till[i][j][k] << "\n"; } } } cout << max_till[red][green][blue] << "\n"; return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Programs/Good Subarrays.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; string S; cin >> S; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { A[i] = S[i - 1] - '0'; } vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; } long long no_of_pairs = 0; map frequency; frequency[0] = 1; for(int i = 1; i <= no_of_elements; i++) { long long value_here = sum_till[i] - i; no_of_pairs += frequency[value_here]; frequency[value_here]++; } cout << no_of_pairs << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Educational Rounds/Educational Round 93/Programs/Substring Removal Game.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { string S; cin >> S; int current_length = 0; vector lengths; for(int i = 0; i < S.size(); i++) { if(S[i] == '1') { current_length++; if(i + 1 == S.size()) { lengths.push_back(current_length); } } else { if(current_length > 0) { lengths.push_back(current_length); current_length = 0; } } } sort(lengths.begin(), lengths.end()); reverse(lengths.begin(), lengths.end()); int total = 0; for(int i = 0; i < lengths.size(); i += 2) { total += lengths[i]; } cout << total << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Good Bye 2019/Explanations/Card Game Explanation.txt ================================================ We just need to check which array has the greater maximum. void solve() { int no_of_elements, a_cards, b_cards; cin >> no_of_elements >> a_cards >> b_cards; int a_max = 0; for(int i = 1; i <= a_cards; i++) { int x; cin >> x; a_max = max(a_max, x); } int b_max = 0; for(int i = 1; i <= b_cards; i++) { int x; cin >> x; b_max = max(b_max, x); } cout << (a_max > b_max ? "YES\n" : "NO\n"); } ================================================ FILE: 2020/Good Bye 2019/Explanations/Interesting Subarray Explanation ================================================ Fact - If there is an interesting subarray, then there is an interesting subarray of length 2. Proof - Let us suppose that there are 2 consecutive elements A[i], A[i + 1] such that |A[i] - A[i + 1]| >= 2 This satisfies our condition and there is at least one interesting subarray. ------ Now, let us suppose that there is no such subarray of length 2 in the array. This means that for every pair (i, i + 1), the difference is atmost 1. |A[i] - A[i + 1]| >= 1 For any given subarray of length k, the difference in between the smallest and largest element < k So, there can be no interesting subarray in the array. ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i < no_of_elements; i++) { if(abs(A[i + 1] - A[i]) >= 2) { cout << "YES\n"; cout << i << " " << i + 1 << "\n"; return; } } cout << "NO\n"; } ================================================ FILE: 2020/Good Bye 2019/Explanations/Make Good Explanation.txt ================================================ Let us look at the sum of the first N integers. S = A1 + A2 + ... + An XOR = A1^A2^...^An As an attempt, let us try to make XOR = 0. Let us append a new element to the sequence, A(n + 1) = X S = S + X X = X^X = 0 As we know, 0^x = x Now, let us append another element to the sequence, A(n + 2) = S + X S = S + X + (S + X) = 2(S + X) X = 0^(S + X) = (S + X) This fulfils the objective. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long sum = 0, array_xor = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; array_xor ^= A[i]; } if(array_xor == 0) { cout << "1\n"; cout << sum + array_xor << "\n"; return; } else { cout << "2\n"; cout << array_xor << " " << sum + array_xor << "\n"; return; } } ================================================ FILE: 2020/Good Bye 2019/Programs/Card Game.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, a_cards, b_cards; cin >> no_of_elements >> a_cards >> b_cards; int a_max = 0; for(int i = 1; i <= a_cards; i++) { int x; cin >> x; a_max = max(a_max, x); } int b_max = 0; for(int i = 1; i <= b_cards; i++) { int x; cin >> x; b_max = max(b_max, x); } cout << (a_max > b_max ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Good Bye 2019/Programs/Interesting Subarray.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i < no_of_elements; i++) { if(abs(A[i + 1] - A[i]) >= 2) { cout << "YES\n"; cout << i << " " << i + 1 << "\n"; return; } } cout << "NO\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Good Bye 2019/Programs/Make Good.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long sum = 0, array_xor = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; array_xor ^= A[i]; } if(array_xor == 0) { cout << "1\n"; cout << sum + array_xor << "\n"; return; } else { cout << "2\n"; cout << array_xor << " " << sum + array_xor << "\n"; return; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Hello 2020/Explanations/New Year and Ascent Sequences Explanation.txt ================================================ Let us call a sequence an A sequence if there is an ascent in the sequence. Let us call a sequence a D sequence if there is no ascent and it is in descending order. ----- Now, there are 4 types of pairs - 1. A-A 2. A-D 3. D-A 4. D-D Let us count each type of pairs individually. ---- Let there be a A-sequences and d D-sequences ---- If a sequence has an ascent, then it can be appended with itself and it will be a good sequence. It can also be appended to any other A-sequence and it will be good. If there are a A-sequences, then the number of A-A pairs is a + a(a - 1) --- A-D pairs This count is a.d ---- D-A pairs This count is d.a ---- All A-D and D-A pairs are good since there is guaranteed to be at least one asecnt in each pair. ---- Now, let us suppose we only have D-sequences. For every sequence, let us have the maximum and minimum element. If the minimum element of sequence i, is m, then sequence i forms a good pair with any sequence who's maximum element is > m. We will keep track of the frequency of each maximum and the suffix sum of the frequency. This way, we can get maximum_suffix_frequency[m + 1] can be gotten in O(1) time. Please refer my code for further clarification. ----- int main() { int no_of_sequences; cin >> no_of_sequences; const int oo = 1e6; vector minimum, maximum; long long ascent_sequences = 0, non_ascent_sequences = 0; for(int i = 1; i <= no_of_sequences; i++) { int length; cin >> length; vector A(length + 1); for(int j = 1; j <= length; j++) { cin >> A[j]; } int has_ascent = false; for(int j = 2; j <= length; j++) { if(A[j - 1] < A[j]) { has_ascent = true; break; } } if(has_ascent) { ascent_sequences++; } else { non_ascent_sequences++; maximum.push_back(A[1]); minimum.push_back(A[length]); } } vector maximum_frequency(oo + 5, 0); for(int i = 0; i < non_ascent_sequences; i++) { maximum_frequency[maximum[i]]++; } vector maximum_suffix_sum(oo + 5, 0); for(int i = oo; i >= 0; i--) { maximum_suffix_sum[i] = maximum_frequency[i] + maximum_suffix_sum[i + 1]; } long long no_of_pairs = ascent_sequences + ascent_sequences*(ascent_sequences - 1) + 2*ascent_sequences*non_ascent_sequences; for(int i = 0; i < non_ascent_sequences; i++) { no_of_pairs += maximum_suffix_sum[minimum[i] + 1]; } cout << no_of_pairs << "\n"; return 0; } ================================================ FILE: 2020/Hello 2020/Explanations/New Year and Conferences Explanation.txt ================================================ We can actually interpret this as a question about rectangles. Interpret the output as (x1, x2), (y1, y2). The question is now to check if there are 2 rectangles who's X intersects but Y does not. We will sort the rectangles by X. We will go through the rectangles in sorted order. We will look at the current Y. We have to check that the Y intersects with all the corresponding Y's that the X intersects with. We can do this by 1. Maintaining a set of all Y's which the current X intersects with. 2. Check if y1 >= smallest Y in the set 3. Check if y2 <= largest Y in the set 4. Also when we are at y2, we will remove it from the set 5. When we are at y1, we will insert y into the set ----- We will once check if any two rectangles have intersecting X's and not intersecting Y's Then, we will check if we have intersecting Y's and not intersecting X's ----- int same_intersections(vector start_a, vector end_a, vector start_b, vector end_b) { multiset starts, ends; vector events; for(int i = 0; i < start_a.size(); i++) { events.push_back(event(start_a[i], start_b[i], end_b[i], true)); events.push_back(event(end_a[i] + 1, start_b[i], end_b[i], false)); } sort(all(events)); for(int i = 0; i < events.size(); i++) { if(events[i].is_entry) { if(!starts.empty()) { int last_start = *starts.rbegin(); int earliest_end = *ends.begin(); if(earliest_end < events[i].start || last_start > events[i].end) { return false; } } starts.insert(events[i].start); ends.insert(events[i].end); } else { starts.erase(starts.find(events[i].start)); ends.erase(ends.find(events[i].end)); } } return true; } int main() { int no_of_lectures; cin >> no_of_lectures; vector start_a(no_of_lectures), start_b(no_of_lectures), end_a(no_of_lectures), end_b(no_of_lectures); for(int i = 0; i < no_of_lectures; i++) { cin >> start_a[i] >> end_a[i] >> start_b[i] >> end_b[i]; } cout << (same_intersections(start_a, end_a, start_b, end_b) && same_intersections(start_b, end_b, start_a, end_a) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: 2020/Hello 2020/Explanations/New Year and Naming Explanation ================================================ For each query, we just have to print S[y%n] + S[y%m] concatenated. ----- int main() { int S_strings, T_strings; cin >> S_strings >> T_strings; vector S(S_strings); for(int i = 0; i < S_strings; i++) { cin >> S[i]; } vector T(T_strings); for(int i = 0; i < T_strings; i++) { cin >> T[i]; } int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { int year; cin >> year; cout << S[(year - 1)%S_strings] << T[(year - 1)%T_strings] << "\n"; } return 0; } ================================================ FILE: 2020/Hello 2020/Explanations/New Year and Permutation Explanation.txt ================================================ Let us look at a segment of length L. It can be rearranged in L! ways. The entire segment can be made (N - L + 1)! ways. Of course, there are (N - L + 1) segments of length L. Let us count the number of framed sequences of length 1, 2, 3 and so on. We will use the above reasoning. ------ int main() { long long n, mod; cin >> n >> mod; vector factorial(n + 1); factorial[0] = 1; for(int i = 1; i <= n; i++) { factorial[i] = (factorial[i - 1]*i)%mod; } long long sum = 0; for(int length = 1; length <= n; length++) { long long no_of_segments = n - length + 1; long long ways_for_one_segment = (factorial[n - length + 1]*factorial[length])%mod; sum += (no_of_segments*ways_for_one_segment)%mod; } cout << sum%mod << "\n"; return 0; } ================================================ FILE: 2020/Hello 2020/Programs/New Year and Ascent Sequences.cpp ================================================ #include #include using namespace std; int main() { int no_of_sequences; cin >> no_of_sequences; const int oo = 1e6; vector minimum, maximum; long long ascent_sequences = 0, non_ascent_sequences = 0; for(int i = 1; i <= no_of_sequences; i++) { int length; cin >> length; vector A(length + 1); for(int j = 1; j <= length; j++) { cin >> A[j]; } int has_ascent = false; for(int j = 2; j <= length; j++) { if(A[j - 1] < A[j]) { has_ascent = true; break; } } if(has_ascent) { ascent_sequences++; } else { non_ascent_sequences++; maximum.push_back(A[1]); minimum.push_back(A[length]); } } vector maximum_frequency(oo + 5, 0); for(int i = 0; i < non_ascent_sequences; i++) { maximum_frequency[maximum[i]]++; } vector maximum_suffix_sum(oo + 5, 0); for(int i = oo; i >= 0; i--) { maximum_suffix_sum[i] = maximum_frequency[i] + maximum_suffix_sum[i + 1]; } long long no_of_pairs = ascent_sequences + ascent_sequences*(ascent_sequences - 1) + 2*ascent_sequences*non_ascent_sequences; for(int i = 0; i < non_ascent_sequences; i++) { no_of_pairs += maximum_suffix_sum[minimum[i] + 1]; } cout << no_of_pairs << "\n"; return 0; } ================================================ FILE: 2020/Hello 2020/Programs/New Year and Conferences.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct event { int time, start, end, is_entry; event(){} event(int T, int S, int E, int is_E) { time = T; start = S; end = E; is_entry = is_E; } int operator <(const event &E) { if(time == E.time) { return (is_entry < E.is_entry); } return (time < E.time); } }; int same_intersections(vector start_a, vector end_a, vector start_b, vector end_b) { multiset starts, ends; vector events; for(int i = 0; i < start_a.size(); i++) { events.push_back(event(start_a[i], start_b[i], end_b[i], true)); events.push_back(event(end_a[i] + 1, start_b[i], end_b[i], false)); } sort(all(events)); for(int i = 0; i < events.size(); i++) { if(events[i].is_entry) { if(!starts.empty()) { int last_start = *starts.rbegin(); int earliest_end = *ends.begin(); if(earliest_end < events[i].start || last_start > events[i].end) { return false; } starts.insert(events[i].start); ends.insert(events[i].end); } } else { starts.erase(starts.find(events[i].start)); ends.erase(ends.find(events[i].end)); } } return true; } int main() { int no_of_lectures; cin >> no_of_lectures; vector start_a(no_of_lectures), start_b(no_of_lectures), end_a(no_of_lectures), end_b(no_of_lectures); for(int i = 0; i < no_of_lectures; i++) { cin >> start_a[i] >> end_a[i] >> start_b[i] >> end_b[i]; } cout << (same_intersections(start_a, end_a, start_b, end_b) && same_intersections(start_b, end_b, start_a, end_a) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: 2020/Hello 2020/Programs/New Year and Naming.cpp ================================================ #include #include using namespace std; int main() { int S_strings, T_strings; cin >> S_strings >> T_strings; vector S(S_strings); for(int i = 0; i < S_strings; i++) { cin >> S[i]; } vector T(T_strings); for(int i = 0; i < T_strings; i++) { cin >> T[i]; } int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { int year; cin >> year; cout << S[(year - 1)%S_strings] << T[(year - 1)%T_strings] << "\n"; } return 0; } ================================================ FILE: 2020/Hello 2020/Programs/New Year and Permutation.cpp ================================================ #include #include using namespace std; int main() { long long n, mod; cin >> n >> mod; vector factorial(n + 1); factorial[0] = 1; for(int i = 1; i <= n; i++) { factorial[i] = (factorial[i - 1]*i)%mod; } long long sum = 0; for(int length = 1; length <= n; length++) { long long no_of_segments = n - length + 1; long long ways_for_one_segment = (factorial[n - length + 1]*factorial[length])%mod; sum += (no_of_segments*ways_for_one_segment)%mod; } cout << sum%mod << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Alternative Thinking Explanation.txt ================================================ It is possible to increase the length of the alternating sequence by at most 2. Suppose we have consecutive 1's or consecutive 0's. If we have a substring 00 in our string, we will flip it to either 10 or 01 It increases the number of sequences by 2. If 00 is at the end or beginning of the string, we increase the number of alternate sequences by 1. If it is in the middle, we increase it by 2. ----- We can prove this is optimal by considering the impact of the flip on the compressed string where each equal substring is compressed to a single character. Flipping [L, R] is the same as 1. Flipping [1, R] 2. Flipping [1, L - 1] ------ The number of alternating sequences in the prefix will remain the same since it is flipped twice. The suffix is not flipped at all. The only way we can increase the number of characters in our compressed string is by flipping a part of a segment. If the segment is first or last, we increase by 1 If the segment is in the middle, we increase by 2. If there is no segment of length > 1, we cannot increase the length of the longest alternating subsequence. ----- int main() { int length; string S; cin >> length >> S; int alternating_subsequence = 0; for(int i = 0; i < length; i++) { if(i == 0 || S[i] != S[i - 1]) { alternating_subsequence++; } } int answer = min(alternating_subsequence + 2, length); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Ant Colony Explanation.txt ================================================ The number of free ants = Number of ants which divide every element in the range. This is equal to the frequency of the GCD of the segment. The only problem with this is about how we will combine 2 segments. Suppose, we are combining L and R. If gcd(L.gcd, R.gcd) = L.gcd, Then we can take the frequency of L. Otherwise we can take the frequency of R. What if gcd(L.gcd, R.gcd) < min(L.gcd, R.gcd) Then, we can take it as 0 for this segment. ----- The GCD is always the minimum element of the segment. So, if gcd(A, B) < gcd(A) and gcd(B), Then, it means that gcd(A, B) is not present in either A or B and the frequency is 0 ------ We will create a segment tree that keeps track of the GCD and the GCD Frequency for each segments While answering a query, we will notice that GCD_Frequency elements will be free and have to give the count of the remaining elements. ------ Here is the merge function struct node { int gcd, gcd_frequency; node(){} node(int G, int F) { gcd = G; gcd_frequency = F; } }; node merge(node &A, node &B) { node C; C.gcd = gcd(A.gcd, B.gcd); if(A.gcd == B.gcd) { C.gcd_frequency = A.gcd_frequency + B.gcd_frequency; } else if(C.gcd < min(A.gcd, B.gcd)) { C.gcd_frequency = 0; } else if(C.gcd == A.gcd) { C.gcd_frequency = A.gcd_frequency; } else if(C.gcd == B.gcd) { C.gcd_frequency = B.gcd_frequency; } return C; } ------ Here is the build function void build(int n, int left, int right) { if(left == right) { tree[n] = node(A[left], 1); return; } int mid = (left + right)/2; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); tree[n] = merge(tree[LEFT(n)], tree[RIGHT(n)]); } ------ Here is the Query Function node query(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || right < left) { return node(0, 0); } if(query_left <= left && right <= query_right) { return tree[n]; } int mid = (left + right)/2; node left_answer = query(LEFT(n), left, mid, query_left, query_right); node right_answer = query(RIGHT(n), mid + 1, right, query_left, query_right); //cout << " At " << left << "," << right << " LEFT answer(" << left << "," << mid <<") = " << left_answer.gcd << " RIGHT answer(" << mid + 1 << "," << right << ") = " << right_answer.gcd << "\n"; return merge(left_answer, right_answer); } ------ Here is how we will answer each query int main() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } build(1, 1, no_of_elements); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { int left, right; cin >> left >> right; node answer = query(1, 1, no_of_elements, left, right); int free = answer.gcd_frequency; int remaining = right - (left - 1) - free; cout << remaining << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Explanations/Anton and Chess Explanation.txt ================================================ The king will be in check if the closest piece in a straight line is a rook or queen or the closest piece in the diagonal is a bishop or queen. ----- Let us store a sorted list of all pieces on 1. The row - Same x 2. The column - Same y 3. The diagonal - Same (x + y) 4. The antidiagonal - Same (x - y) We will order the pieces on the diagonal by the anti-diagonal value and the pieces on the diagonal by the anti-diagonal value. ----- It is quite easy to extend this solution to knights. Knights can jump over other pieces so the blocking limitation does not apply. We only need to check if there is a knight at a knight's distance from the king. ----- In each vector, we will binary search for the closest pieces to the king and see if it is the correct attacker. ----- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int check(int x, vector > &A, char attacker_1, char queen = 'Q') { pair king = make_pair(x, 'K'); int next = upper_bound(all(A), king) - A.begin(); if(next < A.size() && (A[next].second == attacker_1 || A[next].second == queen)) { return true; } int before = next - 1; if(before >= 0 && (A[before].second == attacker_1 || A[before].second == queen)) { return true; } return false; } int main() { int no_of_black_pieces; cin >> no_of_black_pieces; long long king_x, king_y; cin >> king_x >> king_y; long long king_diagonal = king_x - king_y; long long king_antidiagonal = king_x + king_y; vector > row, column, diagonal, anti_diagonal; for(int i = 1; i <= no_of_black_pieces; i++) { char piece; long long x, y; cin >> piece >> x >> y; if(x == king_x) { row.push_back(make_pair(y, piece)); } if(y == king_y) { column.push_back(make_pair(x, piece)); } if(x - y == king_diagonal) { diagonal.push_back(make_pair(x + y, piece)); } if(x + y == king_antidiagonal) { anti_diagonal.push_back(make_pair(x - y, piece)); } } sort(all(row)); sort(all(column)); sort(all(diagonal)); sort(all(anti_diagonal)); int in_check = false; in_check = (check(king_y, row, 'R') || check(king_x, column, 'R') || check(king_antidiagonal, diagonal, 'B') || check(king_diagonal, anti_diagonal,'B') ); cout << (in_check ? "YES" : "NO") << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Anton and Ira Explanation.txt ================================================ Let us suppose the question was asking us to sort P. The question is actually equivalent to it. We just have to relabel each integer in S so that S = {1, 2, 3, ... , N} ----- We will first place N in it's position and then N - 1 and so on. Suppose N is in position i, A[i] = N There will be at least one integer to the left of A[i] that is <= i There is at least one integer in j in [i + 1, N] that is A[j] <= i When we encounter such an A[j], we will swap (A[i], A[j]) This way both A[i] and A[j] move close to their destinations mutually. How do we prove there is always such an integer ? There are (N - i) integers > i And N is not in [i + 1, N] Since the number of positions is more than the number of integers, there will be at least 1 integer A[j] such that A[j] <= i by the Pigeonhole Principle The number of swaps will be |Position[i] - i| summed over all i. Clearly this is the optimal value. ----- int main() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1), S(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } for(int i = 1; i <= no_of_elements; i++) { cin >> S[i]; } vector label(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { label[S[i]] = i; } for(int i = 1; i <= no_of_elements; i++) { P[i] = label[P[i]]; } long long cost = 0; vector > swaps; for(int current = no_of_elements, i; current >= 1; current--) { for(i = 1; i <= no_of_elements; i++) { if(P[i] == current) { break; } } //cout << "Current = " << current << " i = " << i << " \n"; for(int j = i + 1; j <= current; j++) { if(P[j] <= i) { //cout << "j = " << j << "\n"; swap(P[i], P[j]); swaps.push_back(make_pair(i, j)); cost += (j - i); i = j; } } } cout << cost << " " << swaps.size() << "\n"; for(int i = 0; i < swaps.size(); i++) { cout << swaps[i].first << " " << swaps[i].second << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Explanations/Ants in Leaves Explanation.txt ================================================ Unlike most tree/graph problems, the solution to this problem can't be recursively broken down to it's children directly. The reason is that the problem is not symmetric for the root and it's children. In the root, we allow multiple ants to climb up. But every other vertex only allows 1 ant to climb up at a time. So, we will solve the problem for each child of the root independently. It takes 1 more move to move from the child to the root. So answer = max(child) + 1 ----- Now, how do we solve it for the child of the root ? Each leaf will at least take as much time as it's depth. Let us sort the leaves by their depth. time[i] = max(depth[i], time[i - 1] + 1) It will either take the time as much as it's depth or 1 more than the previous leaf. ----- vector depths; void dfs(int v, int parent_v, int depth) { if(tree[v].size() == 1) { depths.push_back(depth); } for(int child_v : tree[v]) { if(child_v == parent_v) { continue; } dfs(child_v, v, depth + 1); } } int get_answer(int v) { dfs(v, 1, 0); sort(all(depths)); vector visit_order(depths.size()); for(int i = 0; i < visit_order.size(); i++) { visit_order[i] = depths[i]; if(i > 0) { visit_order[i] = max(visit_order[i - 1] + 1, visit_order[i]); } } depths.clear(); //cout << " Answer here = " << visit_order.back() << "\n"; return visit_order.back(); } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1, no_of_edges = no_of_vertices - 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } int answer = 0; for(int child : tree[1]) { answer = max(answer, get_answer(child) + 1); //cout << child << " "; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Army Creation Explanation.txt ================================================ In each range [L, R], let us count only the first K occurrences of each distinct element. In order to do this, we need to do something creative. For each index i, let K[i] denote the K-th previous occurrence of A[i]. Instead of counting at most K occurrences of each index, we will count an index i if and only if K[i] < L If K[i] < L, we can be sure that A[i] is one of the first k occurrences of A[i] in [L, R] ----- Let us build an auxiliary array K K[i] will contain the index of the K-th previous index of A[i]. When we are given a query [L, R] ------ 1. Build a Merge Sort Tree on K 2. For each query, count the number of elements in the range who's value < K Each such value is one of the first K values in [L, R] Instead of generating the vector each time, we will binary search each node and count the number of integers < x We can do this by finding the first integer >= x Since the vectors are 0-indexed, this returns the number of integers < x ----- #include #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 1e5 +5; int k_th_ancestor[MAX_N]; vector indices[MAX_N]; vector tree[3*MAX_N]; vector merge(vector &L, vector &R) { vector answer; for(int l = 0, r = 0; l < L.size() || r < R.size(); ) { if(l == L.size()) { answer.push_back(R[r++]); continue; } if(r == R.size()) { answer.push_back(L[l++]); continue; } if(L[l] <= R[r]) { answer.push_back(L[l++]); } else { answer.push_back(R[r++]); } } return answer; } void build(int n, int left, int right) { if(left == right) { tree[n].push_back(k_th_ancestor[left]); /*cout << "n = " << n <<"[" << left <<"," << right << "]\n" << endl; for(int i = 0; i < tree[n].size(); i++) { cout << tree[n][i] << " "; } cout << "\n";*/ return; } int mid = (left + right)/2; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); tree[n] = merge(tree[LEFT(n)], tree[RIGHT(n)]); /*cout << "n = " << n <<"[" << left <<"," << right << "]\n" << endl; for(int i = 0; i < tree[n].size(); i++) { cout << tree[n][i] << " "; } cout << "\n";*/ } int query(int n, int left, int right, int query_left, int query_right, int x) { if(query_right < left || right < query_left) { return 0; } if(query_left <= left && right <= query_right) { return (upper_bound(all(tree[n]), x - 1) - tree[n].begin()); } int mid = (left + right)/2; return (query(LEFT(n), left, mid, query_left, query_right, x) + query(RIGHT(n), mid + 1, right, query_left, query_right, x)); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; indices[A[i]].push_back(i); if(indices[A[i]].size() > k) { int k_th_step = indices[A[i]].size() - 1 - k; k_th_ancestor[i] = indices[A[i]][k_th_step]; //cout << " K-th " << i << " = " << k_th_ancestor[i] << "\n"; } else { k_th_ancestor[i] = 0; } } build(1, 1, no_of_elements); int no_of_queries; cin >> no_of_queries; int answer = 0; for(int i = 1; i <= no_of_queries; i++) { int x, y; cin >> x >> y; int left = ((x + answer)%no_of_elements) + 1; int right = ((y + answer)%no_of_elements) + 1; if(left > right) { swap(left, right); } // cout << "L = " << left << " R = " << right << "\n"; //vector range = query(1, 1, no_of_elements, left, right); /*cout << "Size = " << range.size() << "\n"; for(int i = 0; i < range.size(); i++) { cout << range[i] << " "; } cout << "\n";*/ answer = query(1, 1, no_of_elements, left, right, left); cout << answer << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Explanations/Bargain Explanation.txt ================================================ Whenever we are asked to compute a sum, we must try to break it down and count the individual contribution of each term. In this case, every cost consists of some prefix of the string concatenated with some suffix of the string. Let us count the contribution of each digit when it is 1. Part of the prefix 2. Part of the suffix. ----- If a digit is part of the suffix, then it means there is no digit to it's right that is deleted. So, if it is the s-th digit from the right, it's value will be 10^s S[s] How many strings have this digit in it's suffix ? We can remove p(p - 1)/2 + p strings from the prefix, where p = length of string before S[s] So, the total suffix cost of S[s] = p(p + 1)/2 10^s S[s] ----- Now, let us count the prefix cost of S[i]. This means that no character to it's left is deleted. This is a little more tricky. Suppose S[i] is the 5th character from the right. ================================================ FILE: 2020/Practice/Explanations/Concatenated Multiples Explanation.txt ================================================ What is the value of concatenating A[i] with A[j] ? 10^{length(A[j])} + A[i] Let f(t, m) be the frequency of remainder m (mod K) if an integer is multiplied by 10^t We will iterate from i = 1 to N and add f(length(A[j]), -A[i]) to the answer for each integer. We are not allowed to concatenate an integer with itself so we have to be careful about that. ----- int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_DIGITS = 11; map frequency_mod[MAX_DIGITS]; long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { for(long long t = 10, d = 1; d < MAX_DIGITS; d++, t = (t*10)%k) { frequency_mod[d][ (A[i]*t)%k ]++; //cout << "D = " << d << " M = " << (A[i]*t)%k << " = " << frequency_mod[d][ (A[i]*t)%k ] << "\n"; } } for(int i = 1; i <= no_of_elements; i++) { long long first_part_mod = (0 - A[i]%k + k)%k; //cout << "Need d = " << no_of_digits(A[i]) << " with M = " << first_part_mod << "\n"; answer += frequency_mod[no_of_digits(A[i])][first_part_mod]; //cout << "Answer = " << answer << "\n"; long long t = 1; for(long long d = 1; d <= no_of_digits(A[i]) ;d++) { t = (t*10)%k; } if( (t*A[i] + A[i])%k == 0 ) { //cout << "Self!\n"; answer--; } //cout << "Answer = " << answer << "\n"; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Count Pairs Explanation.txt ================================================ We need 1 flash of creativity for this problem. (A + B)(A^2 + B^2) = k (mod P), We need to somehow write LHS = RHS, where both are a function of A and B So that, we can utilise the symmetry We can multiply both sides by (A - B) ! (A^4 - B^4) = k(A - B) (mod P) A^4 - kA = B^4 - kB (mod P), There we have it ! ----- We have now found out the effective value of each array element. We will track the frequencies of each element and count the number of pairs of each. ----- #include #include #include using namespace std; long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { int no_of_elements, p, k; cin >> no_of_elements >> p >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map value_frequency; for(int i = 1; i <= no_of_elements; i++) { long long value = (A[i]*A[i])%p; value = (value*A[i])%p; value = (value*A[i])%p; value = (value - k*A[i])%p; value = (value + p)%p; value_frequency[value]++; } long long no_of_pairs = 0; for(auto it = value_frequency.begin(); it != value_frequency.end(); it++) { no_of_pairs += choose_2(it->second); } cout << no_of_pairs << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Cram Time Explanation.txt ================================================ It is always optimal to use consecutive integers. Let x be the larget integer such that x(x + 1)/2 <= (a + b), we will show that it is always possible to attain x. We will fill up i = x down to 1 in descending order in a. When a = a' < i, we will put a' in a, so that a = 0 is completely filled. Since a is completely filled and x(x + 1)/2 <= (a + b), we can put all the remaining integers in b ----- Please note that filling it in ascending order will not work. It might leave gaps. For example suppose we are at i and have already placed all integers < i. a = a' < i Now, we cannot put i in a and since we have already filled all the smaller integers, we can never fill a. This leaves a gap. So, we have to fill it in descending order. We have to ensure that at least one of the days is completely packed. ----- #include #include using namespace std; void display(vector &A) { cout << A.size() << "\n"; for(int i = 0; i < A.size(); i++) { cout << A[i] << " "; } cout << "\n"; } int main() { long long a, b; cin >> a >> b; long long left = 0, right = 1e5; while(right - left > 1) { long long mid = (right + left)/2; if(mid*(mid + 1) <= (a + b)*2) { left = mid; } else { right = mid; } } vector day_a, day_b; long long problems = left; for(long long i = problems; i >= 1; i--) { if(a >= i) { day_a.push_back(i); a -= i; } else { for(; i >= 1; i--) { if(i == a) { day_a.push_back(i); a -= i; } else { day_b.push_back(i); b -= i; } } } } display(day_a); display(day_b); return 0; } ================================================ FILE: 2020/Practice/Explanations/Cycles Explanation.txt ================================================ The idea is to be greedy. First, we will take a complete graph of K vertices. A vertex with K vertices has C(K, 3) triangles. We will choose the largest K such that C(K, 3) <= E ----- After this, when we add the new vertex, we will connect it to as many vertices as possible so that the number of triangles is <= E If we connect this vertex with the first v vertices, then we will be adding C(v, 2) triangles. ----- 1. First take a complete graph 2. Then, take a new vertex and connect it to the first i vertices so that total edges <= E ----- int main() { int no_of_edges; cin >> no_of_edges; int complete_graph = 0; for(int i = 1; ; i++) { if(choose_3(i) > no_of_edges) { complete_graph = i - 1; no_of_edges -= choose_3(complete_graph); break; } } vector extra_matching; while(no_of_edges > 0) { for(int i = complete_graph; i >= 0; i--) { if(choose_2(i) <= no_of_edges) { extra_matching.push_back(i); no_of_edges -= choose_2(i); break; } } } memset(graph, 0, sizeof(graph)); for(int i = 1; i <= complete_graph; i++) { for(int j = i + 1; j <= complete_graph; j++) { add_edge(i, j); } } for(int i = 0; i < extra_matching.size(); i++) { int v = complete_graph + i + 1; int v_limit = extra_matching[i]; for(int w = 1; w <= v_limit; w++) { add_edge(v, w); } } int no_of_vertices = complete_graph + extra_matching.size(); cout << no_of_vertices << "\n"; for(int i = 1; i <= no_of_vertices; i++) { for(int j = 1; j <= no_of_vertices; j++) { cout << graph[i][j]; } cout << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Explanations/Elections Explanation.txt ================================================ Let us try to iterate over the final number of votes of the winning part. If the winning party has T votes in the end, then 1. Every party with more than T votes has to have less than T votes 2. Party 1 must have at least T votes ----- First, we will go through all the parties. For each party, which has more than T votes, we will choose it's cheapest votes till it has less than T votes Then, we will take the remaining votes, and start choosing the lowest cost till we have >= T votes ----- #include #include #include using namespace std; const int MAX_PARTIES = 3333; vector > votes; long long cost_if_final_count(int n) { int additional_votes = 0; long long cost = 0; vector extra_votes; for(int i = 2; i < votes.size(); i++) { for(int j = 0; j < votes[i].size(); j++) { //cout << "Party = " << i << " Person = " << j << "\n"; if(j + n <= votes[i].size()) { additional_votes++; cost += votes[i][j]; } else { //cout << "Extra \n"; extra_votes.push_back(votes[i][j]); } } } int remaining = n - votes[1].size() - additional_votes; //cout << "Remaining = " << remaining << "\n"; if(remaining <= 0) { return cost; } sort(extra_votes.begin(), extra_votes.end()); for(int i = 0; i < remaining && i < extra_votes.size(); i++) { cost += extra_votes[i]; } return cost; } int main() { int no_of_voters, no_of_parties; cin >> no_of_voters >> no_of_parties; votes.resize(no_of_parties + 1); for(int i = 1; i <= no_of_voters; i++) { int party, cost; cin >> party >> cost; votes[party].push_back(cost); } for(int i = 2; i <= no_of_parties; i++) { sort(votes[i].begin(), votes[i].end()); } long long answer = 1e18; for(int i = 1; i <= no_of_voters; i++) { //cout << "cost " << i << " = " << cost_if_final_count(i) << "\n"; answer = min(answer, cost_if_final_count(i)); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Fight Against Traffic Explanation.txt ================================================ There are only 1000 vertices, so we can iterate over all pairs of edges. How do we check if pair (u, v) is good ? First of all, (u, v) should not already have an edge between them. Secondly, if we add an edge between (u, v), it should not decrease the shortest distance. There are two possible paths. S -> u -> v -> T S -> v -> u -> T Both of these should be >= Distance of T from S ----- To aid in our calculation, we will precompute, Distance_source(v) and Distance_target(v), for all vertices v The new distance is either Distance_source(u) + 1 + Distance_target(v) or Distance_source(v) + 1 + Distance_target(u) Please note that we cannot do this with 1 Distance vector. It is a graph, not a tree and there may be multiple paths from one vertex to another. For each vertex, we need to know the shortest distance between each vertex and the source and the target. We can do this with two BFS ----- #include #include #include #include using namespace std; const int MAX_N = 1005; vector graph[MAX_N]; set edge_exists[MAX_N]; void bfs(int source, vector &distance) { queue Q; Q.push(source); distance[source] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = 0; i < graph[u].size(); i++) { int v = graph[u][i]; if(distance[v] == -1) { distance[v] = distance[u] + 1; Q.push(v); } } } } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; int source, target; cin >> source >> target; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); edge_exists[u].insert(v); edge_exists[v].insert(u); } vector source_distance(no_of_vertices + 1, -1), target_distance(no_of_vertices + 1, -1); bfs(source, source_distance); bfs(target, target_distance); int minimum_distance = source_distance[target]; long long no_of_good_pairs = 0; for(int u = 1; u <= no_of_vertices; u++) { for(int v = u + 1; v <= no_of_vertices; v++) { if(edge_exists[u].count(v) == 1) { continue; } if(source_distance[u] + 1 + target_distance[v] >= minimum_distance && source_distance[v] + 1 + target_distance[u] >= minimum_distance) { no_of_good_pairs++; } } } cout << no_of_good_pairs << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Hacker, Pack your Bags Explanation.txt ================================================ Let us treat each left and right border as an 'event'. An event has 1. X 2. Cost 3. Duration 4. Is_left -> Indicating if it's left or right ----- We will sort the events by their x-point and keep a map minimum_cost(d) indicates the minimum_cost with duration d ----- 1. When we enter into a left segment, we will check the minimum_cost(d - A[i].duration) 2. When we enter into a right segment, we will update the value of minimum_cost(A[i].duration) This maintains the invariant that minimum_cost(d) only holds the cost of those events who's right border we have already crossed, ensuring there is no intersection ----- int main() { int no_of_segments, total; cin >> no_of_segments >> total; vector A; for(int i = 1; i <= no_of_segments; i++) { int left, right, x; cin >> left >> right >> x; A.push_back(Point(left, x, right - left + 1, true)); A.push_back(Point(right, x, right - left + 1, false)); } sort(A.begin(), A.end(), sort_by_point); map minimum_cost; const int oo = 2e9 + 7; int answer = oo; for(int i = 0; i < 2*no_of_segments; i++) { if(A[i].is_left) { if(minimum_cost.find(total - A[i].duration) != minimum_cost.end()) { answer = min(answer, minimum_cost[total - A[i].duration] + A[i].cost); } } else { if(minimum_cost.find(A[i].duration) != minimum_cost.end()) { minimum_cost[A[i].duration] = min(minimum_cost[A[i].duration], A[i].cost); } else { minimum_cost[A[i].duration] = A[i].cost; } } } cout << (answer >= oo ? -1 : answer) << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Imbalance Array Explanation.txt ================================================ For each A[i], let us count the number of subarrays it is the minimum in and the number of subarrays it is the maximum in. Suppose A[L[i], R[i]], is the range in which A[i] is the minimum element. How to calculate the number of subarrays ? The left half can end anywhere between L[i], i and the right half can end anywhere between i, R[i]. So we multiply this. (i - L[i] + 1)(R[i] - i + 1) ----- A problem arises when we face equal elements. How to deal with this ? Suppose, we have a subarray [1, 2, 1]. Both the 1's will be considered the minimum and we will be over counting. In order to overcome this, we will place a bijection. For each subarray, we will only consider the leftmost or rightmost maxima and minima. This way, each maxima and minima will be counted exactly once. So, L[i] is the first index such that A[L[i]] <= A[i] And R[i] is the first index such that A[R[i]] < A[i] So, A[i] cannot have any equal elements on the left but can have equal elements on the right. ----- We can compute this with a stack in O(n) time. void compute_max_borders(int n, vector &A, vector &L, vector &R) { const int oo = 1e9 + 9; stack < pair > left_max; left_max.push(make_pair(0, oo)); for(int i = 1; i <= n; i++) { while(left_max.top().second < A[i]) { left_max.pop(); } L[i] = left_max.top().first + 1; //Range in which A[i] is maximum left_max.push(make_pair(i, A[i])); } stack < pair > right_max; right_max.push(make_pair(n + 1, oo)); for(int i = n; i >= 1; i--) { while(right_max.top().second <= A[i]) { right_max.pop(); } R[i] = right_max.top().first - 1; right_max.push(make_pair(i, A[i])); } } void compute_min_borders(int n, vector &A, vector &L, vector &R) { const int oo = 1e9 + 9; stack < pair > left_min; left_min.push(make_pair(0, -oo)); for(int i = 1; i <= n; i++) { while(left_min.top().second > A[i]) { left_min.pop(); } L[i] = left_min.top().first + 1; //cout << "L " << i << " = " << L[i] << "\n"; left_min.push(make_pair(i, A[i])); } stack < pair > right_min; right_min.push(make_pair(n + 1, -oo)); for(int i = n; i >= 1; i--) { while(right_min.top().second >= A[i]) { right_min.pop(); } R[i] = right_min.top().first - 1; right_min.push(make_pair(i, A[i])); } } ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector left_max_border(no_of_elements + 1), right_max_border(no_of_elements + 1); compute_max_borders(no_of_elements, A, left_max_border, right_max_border); long long total_maximum = 0; for(int i = 1; i <= no_of_elements; i++) { long long left_half = i - left_max_border[i], right_half = (right_max_border[i] - i); long long no_of_maximas = (left_half + 1)*(right_half + 1); total_maximum += no_of_maximas*A[i]; } vector left_min_border(no_of_elements + 1), right_min_border(no_of_elements + 1); compute_min_borders(no_of_elements, A, left_min_border, right_min_border); long long total_minimum = 0; for(int i = 1; i <= no_of_elements; i++) { long long left_half = i - left_min_border[i], right_half = right_min_border[i] - i; long long no_of_minima = (left_half + 1)*(right_half + 1); total_minimum += no_of_minima*A[i]; } long long answer = total_maximum - total_minimum; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Laboratory Work Explanation.txt ================================================ If the Average (X) = Average (Y), then they must have the same sum. Let us solve the problem on (0, 1, 2) and then map it to the range asked. We can use the operation 1 + 1 = 0 + 2 to make the sum invariant The number of operations is either min(f[0], f[2]) or f[1]/2, whichever is larger. There is another condition that min(Y) = min(X) and max(Y) = max(X) So, if f[0] = 0 or f[2] = 0, we cannot change (1, 1) to (0, 2) ----- int main() { int no_of_points; cin >> no_of_points; vector X(no_of_points); for(int i = 0; i < no_of_points; i++) { cin >> X[i]; } sort(all(X)); int minimum = X[0]; const int MAX_TYPES = 3; vector frequency(MAX_TYPES, 0); for(int i = 0; i < no_of_points; i++) { frequency[X[i] - minimum]++; } vector new_frequency(MAX_TYPES, 0); for(int t = 0; t < MAX_TYPES; t++) { new_frequency[t] = frequency[t]; } if(frequency[1]/2 > min(frequency[0], frequency[2]) && frequency[2] > 0 && frequency[0] > 0) { new_frequency[0] = frequency[0] + frequency[1]/2; new_frequency[1] = frequency[1]%2; new_frequency[2] = frequency[2] + frequency[1]/2; } else if(frequency[1]/2 <= min(frequency[0], frequency[2])) { new_frequency[0] = frequency[0] - min(frequency[0], frequency[2]); new_frequency[1] = frequency[1] + 2*min(frequency[0], frequency[2]); new_frequency[2] = frequency[2] - min(frequency[0], frequency[2]); } int equal_elements = 0; for(int t = 0; t < MAX_TYPES; t++) { equal_elements += min(frequency[t], new_frequency[t]); } cout << equal_elements << "\n"; for(int t = 0; t < MAX_TYPES; t++) { for(int i = 0; i < new_frequency[t]; i++) { cout << minimum + t << " "; } } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Lieges of Legendre Explanation.txt ================================================ This is an impartial game. Let us try to reduce it to a game of NIM using the Sprague Grundy Theorem. Let us try to find out the grundy number of f(2n) f(2n) = mex{f(2n - 1), XOR(f(n), f(n), ... , f(n))} If K is even, then f(2n) = mex{f(2n - 1), 0} If K is odd, then f(2n) = mex{f(2n - 1), f(n)} ----- Let us write out the function for even K f(0) = 0 f(1) = mex(f(0)) = 1 f(2) = mex(f(1), 0) = 2 f(3) = mex(f(2)) = 0 f(4) = mex(f(3)) = 1 f(5) = mex(f(4)) = 0 Here, we can see that f(n) = 1, if n is odd and 0 if n is even > 2 We can prove this with mathematical induction. It is true for f(3), f(4) Suppose it is true for f(k), f(k + 1) f(k + 2) = mex(f(k + 1)) = mex(1) = 0 f(k + 3) = mex(f(k + 2), 0) = mex(0, 0) = 1 ----- Let us write out the first few values with odd K f(0) = 0 f(1) = mex(f(0)) = 1 f(2) = mex(f(1)) = 0 f(3) = mex(f(2)) = 1 f(4) = mex(f(3), f(2)) = 2 f(5) = mex(f(4)) = 0 f(6) = mex(f(5), f(3)) = 2 f(7) = 0 f(8) = 1 f(9) = 0 f(10) = 1 f(11) = 0 f(12) = 1 f(13) = 0 f(14) = 1 We see a pattern emerge that f(n) = 0 for all odd n > 3 and f(n) > 0 for all even n > 2 We can prove this with Mathematical Induction. It is true for f(5), f(6). Suppose it is true for f(k), f(k + 1) f(k + 2) = mex{f(k + 1)} = 0, since f(k + 1) > 0 by the Induction Hypothesis f(k + 3) = mex{f(k + 2), f((k + 3)/2)} > 0 ----- For odd K, we can return the answer as 0 if it is odd > 3 And if it is even, then we will check the value of f(n/2) If f(n/2) = 1, then f(n) = 2 If f(n/2) > 1, then f(n) = 1 The only exception is f(4) = 2 even though f(4/2) = 0 because f(3) = 1 and f(2) = 0 The time complexity is O(log MAXN) ----- int get_grundy(int n, int k) { if(n == 0) { return 0; } if(n == 1) { return 1; } if(k%2 == 0) { if(n == 2) { return 2; } return (n%2 == 0 ? 1 : 0); } else { if(n%2 == 1) { return (n <= 3 ? 1 : 0); } if(n == 2) { return 0; } if(n == 4) { return 2; } return (get_grundy(n/2, k) == 1 ? 2 : 1); } } ================================================ FILE: 2020/Practice/Explanations/Line Explanation.txt ================================================ Ax + By = -C We will use the extended gcd algorithm to find x, y such that Ax + By = G And then multiply the whole equation by (-C/G) If C is not divisible by G, then it is not possible ----- long long extended_gcd(long long A, long long B, long long &x, long long &y) { if(B == 0) { x = 1; y = 0; return A; } long long x1, y1; long long gcd = extended_gcd(B, A%B, x1, y1); y = x1 - (A/B)*y1; x = y1; //cout << "(" << A << "," << B << ") = " << x << "," << y << "\n"; return gcd; } int main() { long long A, B, C; cin >> A >> B >> C; long long X = 0, Y = 0; long long gcd_A_B = extended_gcd(A, B, X, Y); X *= (-C/gcd_A_B); Y *= (-C/gcd_A_B); if(C%gcd_A_B == 0) cout << X << " " << Y << "\n"; else cout << "-1\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Marina and Vyasa Explanation.txt ================================================ Instead of working around the number of difference, let us look at the number of matches. Suppose there are S characters that are the same i.e. S[i] = T[i] If we have to have K differences, we have to have (N - K) matches. At first, we will try to match all the characters where they are same. If that is insufficient, we will do the following For a given pair, S(i), T(i) and S(j), T(j) Answer[i] = S[i], Answer[j] = T[j] This increases the number of matches by 1. So the minimum length of the string should be S + 2(M - S), where M is the number of matches that we need to make. ------ char other(char c1, char c2) { const int NO_OF_ALPHABETS = 26; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { char current = 'a' + alpha; if(current != c1 && current != c2) { return current; } } return 'z'; } int main() { int length, differences; string S, T; cin >> length >> differences >> S >> T; int same = 0; for(int i = 0; i < length; i++) { if(S[i] == T[i]) { same++; } } int matches = length - differences; int minimum_length = same + 2*max(matches - same, 0); if(minimum_length > length) { cout << "-1\n"; return 0; } string answer = S; int a_matches = length, b_matches = same; for(int i = 0; i < length; i++) { if(S[i] != T[i]) { if(b_matches < matches) { answer[i] = T[i]; a_matches--; b_matches++; } else if(a_matches > matches) { answer[i] = other(S[i], T[i]); a_matches--; } } } for(int i = 0; i < length && (a_matches > matches || b_matches > matches); i++) { if(S[i] == T[i]) { answer[i] = other(S[i], T[i]); a_matches--; b_matches--; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Match Points Explanation.txt ================================================ 1. We can actually do binary search and check if it is possible to obtain K pairs 2. To check if it is possible to obtain K pairs, we will try to match the first K points with the last K points. 3. How to do the matching ? Let us take A[1] and match it with A[n - k + 1] Suppose we have two points L1 < L2 and R1 < R2 Then, it is always best to pair [L1, R1], [L2, R2] If [L1, R2] and [L2, R1] are good segments, then even [L1, R1] and [L2, R2] are good segments. As R1 is paired with a smaller element in L1 and L2 is paired with a larger element R2 Using this Exchange Argument we can see that it is always best to pair A[1], A[n - k + 1] A[2], A[n - k + 2] . . A[k], A[n] ----- int main() { int no_of_elements, distance; cin >> no_of_elements >> distance; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int left_pairs = 0, right_pairs = no_of_elements/2 + 1; while(right_pairs - left_pairs > 1) { int mid = (left_pairs + right_pairs)/2; int good_pairs = 0; for(int i = 1; i <= mid; i++) { if(A[no_of_elements - mid + i] - A[i] >= distance) { good_pairs++; } } if(good_pairs == mid) { left_pairs = mid; } else { right_pairs = mid; } } int answer = left_pairs; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Molly and Chemicals Explanation.txt ================================================ The number of perfect powers of any integer will not be too many. It will be at most 40, in fact, in the given range. If S[R] - S[L] = k^p We will keep track of the frequency of prefix sum. For every S[R], it will create a good segment with every S[L] = k^p - S[L] We will add the frequency of (k^p - S[L]) to the answer ----- int main() { int no_of_elements, k; cin >> no_of_elements >> k; vector powers; precompute(powers, k); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map prefix_sum_frequency; long long prefix = 0; prefix_sum_frequency[prefix] = 1; long long no_of_segments = 0; for(int i = 1; i <= no_of_elements; i++) { prefix += A[i]; for(int j = 0; j < powers.size(); j++) { no_of_segments += prefix_sum_frequency[prefix - powers[j]]; } prefix_sum_frequency[prefix]++; } cout << no_of_segments << "\n"; return 0; } ------ void precompute(vector &P, long long k) { P.push_back(1); if(k == 0 || k == 1) { return; } if(k == -1) { P.push_back(-1); return; } long long oo = 1e14; while(abs(P.back()) <= oo) { //cout << P.back() << "\n"; P.push_back(P.back()*k); } } ================================================ FILE: 2020/Practice/Explanations/Moodular Arithmetic Explanation.txt ================================================ Let us study the implication of the functional equation. Suppose f(n) = x f(k n) = k x f(k^2 n) = k f(k n) = k^2 x f(k^3 n) = k f(k^2 n) = k^3 x And so on f(k^i n) = k^i f(n) So, if we assign f(n) to a value, the values of f(kn), f(k^2 n), f(k^3 n), ... , f(k^i n) are determined until k^{i + 1} = 1 because (n, kn, k^2 n, ... k^i n are all distinct) What about f(0) ? f(0) = k f(0) (mod p) (k - 1) f(0) = 0 (mod p) This means that f(0) = 0 since p cannot divide (k - 1) as k <= p So, we can divide {1, ... , p - 1} into (p - 1)/m subgroups where m is the order of k. In each subgroup, we can choose one value freely among p options and the rest are determined. The answer is p^{(p - 1)/m} ----- If k = 0, then f(0) = 0 (mod n) The remaining values can be chosen freely. This can be done in p^{p - 1} ways If k = 1, then f(n) = f(n) (mod n) This can be done in p^p ways. ------ int main() { int p, k; cin >> p >> k; const int MOD = 1e9 + 7; if(k == 0) { cout << power_mod(p, p - 1, MOD) << "\n"; return 0; } if(k == 1) { cout << power_mod(p, p, MOD) << "\n"; return 0; } cout << power_mod(p, (p - 1)/order(k, p), MOD) << "\n"; return 0; } ------ We will use Lagrange's Theorem which says that the order of any subgroup divides the order of the group. This will enable us to find out the order of k. It must be a factor of (p - 1). ----- int order(int k, int m) { int answer = m - 1; for(int i = 1; i*i <= m - 1; i++) { if((m - 1)%i == 0) { if(power_mod(k, i, m) == 1) { answer = min(answer, i); } else if(power_mod(k, (m - 1)/i, m) == 1) { answer = min(answer, (m - 1)/i); } } } return answer; } ================================================ FILE: 2020/Practice/Explanations/Mouse Hunt Explanation.txt ================================================ We are given a 'functional' graph in which every vertex has exactly one edge going out of it. There is guaranteed to be at least one cycle. Let us break the graph into cycles. Each mouse will visit one of the cycles at least once. So, we will put 1 trap in each of the cycle ----- The problem is there might be vertices which lead into a cycle. Instead of 1 → 2 →3 →1, we might have 1 → 2 → 3 → 4 →5 → 3 So, the dfs gets a little tricky. We will maintain two variables for each vertex - Visited - Whether it is Visited and Current_DFS - Indicating if the current vertex has been visited in the current DFS. ----- We will begin a DFS when we encounter an unvisited vertex. 1. If we encounter a vertex which is already visited and also in this DFS, then we have found our cycle 2. If we encounter a vertex which was already visited in another DFS, then we have already processed that cycle before so we need not do it again ----- So, we will update the cost within the DFS function itself ----- void dfs(int v, int &total_cost) { //Cycle Starts here if(current_dfs[v]) { int cost_here = cost[v]; for(int i = to[v]; i != v; i = to[i]) { cost_here = min(cost_here, cost[i]); } total_cost += cost_here; return; } else if(visits[v]) //It was already linked to a cycle from some other dfs { return; } visits[v] = true; current_dfs[v] = true; dfs(to[v], total_cost); current_dfs[v] = false; } int main() { int no_of_vertices; cin >> no_of_vertices; cost.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> cost[i]; } to.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> to[i]; } int total_cost = 0; current_dfs.resize(no_of_vertices + 1, 0); visits.resize(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { if(!visits[i]) { dfs(i, total_cost); } } cout << total_cost << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Multiplicity Explanation.txt ================================================ Let f(i, j) denote the number of sequences of length j ending at A[i] Now, j has to be a divisor of A[i] so we need not check all integers, but only the divisors of A[i] f(i, j) = f(i - 1, j - 1) + f(i - 2, j - 1) + ... + f(1, j - 1) We want to know the number of sequences of length (j - 1) ending anywhere before A[i] ----- We do not need to do O(n^2) each time. Just like the Coin Change DP problem, we can optimise it to O(N) space We will maintain a running variable. Let g(i) be equal to the number of sequences of length i As we will be processing the elements in order from 1 to N, we can take advantage of our processing order. At no point in our DP do we ever need to refer to a state from a greater i than the one we are at. So, g(i) = g(i - 1), if i is a divisor of the current element ----- Also, we cannot factorise the integers in time. We must use a sieve to precompute the divisors of each of the integers ----- int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX = 1e6 + 5; vector > divisors(MAX); for(int i = 1; i < MAX; i++) { for(int multiple = i; multiple < MAX; multiple += i) { divisors[multiple].push_back(i); } } const int MOD = 1e9 + 7; vector no_of_sequences(MAX, 0), sequences_here(MAX, 0); long long total_sequences = 0; no_of_sequences[0] = 1; for(int i = 1; i <= no_of_elements; i++) { for(int d = 0; d < divisors[A[i]].size(); d++) { int m = divisors[A[i]][d]; sequences_here[m] = no_of_sequences[m - 1]; } for(int d = 0; d < divisors[A[i]].size(); d++) { int m = divisors[A[i]][d]; no_of_sequences[m] += sequences_here[m]; no_of_sequences[m] %= MOD; } } for(int i = 1; i < MAX; i++) { total_sequences += no_of_sequences[i]; total_sequences %= MOD; } cout << total_sequences << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Multipliers Explanation.txt ================================================ Let N = p1^a1 p2^a2 ... pk^ak Instead of trying to find out the product of all divisors, let us try to find out the exponent of each prime number in the final product Suppose N = 2^3 3^2 5 Let us look at how many times each exponent of 2 is counted 2.(3) 2.(3.5) 2.(3^2) 2.(3^2 . 5) 2^2.(3) 2^2.(3.5) 2^2.(3^2) 2^2.(3^2 . 5) 2^3.(3) 2^3.(3.5) 2^3.(3^2) 2^3.(3^2 . 5) ---- Each exponent of 2 is paired with - Number of factors of (3^2 5) We know that the number of factors of p1^a1 p2^a2 ... pk^ak is (a1 + 1) (a2 + 1) ... (ak + 1) How many times is each exponent of p1 counted ? (a2 + 1) (a3 + 1) ... (ak + 1) The number of divisors without p1 ----- So, the net contribution of p1 is {a1(a1 + 1)/2} (a2 + 1) (a3 + 1) ... (ak + 1) ----- This is the same for all prime factors. It is easy to do this in 2 linear passes but how do we do this in 1 linear pass ? We need to use our creativity to find a beautiful solution in 1 pass through The prime factors ----- Let us remember Fermat's Little Theorem, a^{m - 1} = 1 (mod m) if m is prime ----- Let P represent the product of all divisors and d represent the number of divisors When we encounter the first prime factor, P = p1^{a1.(a1 + 1)/2} d = (a1 + 1) Later, when we go to p2, We will make P = power(P, (a2 + 1)). power(p2^{a2.(a2 + 1)/2}, d) d = d.(a2 + 1) ---- In general when we arrive at the i-th prime, We 1. Raise the product so far of the first (i - 1) factors to the power (ai + 1) 2. Raise pi^{ai.(ai + 1)/2} to the power d 3. Update d This ensures that each prime is raised to the product of all factors excluding itself ----- int main() { const int MOD = 1e9 + 7; long long product = 1LL; int no_of_primes; cin >> no_of_primes; map exponent; for(int i = 1; i <= no_of_primes; i++) { int prime_i; scanf("%d", &prime_i); exponent[prime_i]++; } long long no_of_divisors = 1; for(map :: iterator it = exponent.begin(); it != exponent.end(); it++) { int p = it->first; long long exp = it->second; long long divisor_product_here = power_mod(p, (exp*(exp + 1))/2, MOD); product = power_mod(product, exp + 1, MOD)*power_mod(divisor_product_here, no_of_divisors, MOD); product %= MOD; no_of_divisors *= (exp + 1); no_of_divisors %= (MOD - 1); } cout << product << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/My Pretty Girl Nora Explanation.txt ================================================ Suppose we divide it into d stages first and d = a.b The number of comparisons will not increase if we divide into a first and then b The number of comparisons when there are n people = nd(d - 1)/2d = n(d - 1)/2 We will use a Sieve to precompute the largest prime factor of every integer. We can compute the answer too. For every integer, we will see which of it's prime factors is the best first choice. We need to be careful about modulo ----- int main() { long long t, left, right; cin >> t >> left >> right; const int MOD = 1e9 + 7; vector largest_prime_factor(right + 1, 0); vector minimum_comparisons(right + 1, 1e16); minimum_comparisons[1] = 0; for(long long i = 2; i <= right; i++) { if(largest_prime_factor[i] == 0) { largest_prime_factor[i] = i; for(long long multiple = i*i; multiple <= right; multiple += i) { if(largest_prime_factor[multiple] == 0) { largest_prime_factor[multiple] = i; } } } for(int x = i; x != 1; x /= largest_prime_factor[x]) { int remaining = i/largest_prime_factor[x]; long long comparisons_here = (i*(largest_prime_factor[x] - 1))/2 + minimum_comparisons[remaining]; minimum_comparisons[i] = min(minimum_comparisons[i], comparisons_here); } minimum_comparisons[i] %= MOD; } long long answer = 0, coefficient = 1; for(int i = left; i <= right; i++) { answer += (coefficient*minimum_comparisons[i])%MOD; coefficient = (coefficient*t)%MOD; answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Optimal Number Permutation Explanation.txt ================================================ The sum will always be non negative. Let us try to make it 0 The 1's should be at a distance of (n - 1) The 2's should be at a distance of (n - 2) The 3's should be at a distance of (n - 3) . . . The n's can be at any position since (n - i) = 0 ----- We will place 1 at (1, n), 3 at (2, n - 1) and so on We will place 2 at (n + 1, 2n - 1), 4 at (n + 2, 2n - 2) and so on We can place the n's anywhere. Since the distance reduces by 1 at each integer and the distance between the free places reduces by 2 on placing an integer, it is a good idea to keep integers of the same parity together. ----- Ultimately, the array will look like all the odd integers in first half and even integers in second half with n in the last position and either in the middle of the first or second half, depend on it's parity. ----- 10 1 3 5 7 9 9 7 5 3 1 2 4 6 8 10 8 6 4 2 10 11 1 3 5 7 9 11 9 7 5 3 1 2 4 6 8 10 10 8 6 4 2 11 ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(2*no_of_elements + 1); for(int front = 1, back = no_of_elements, odd = 1; odd <= no_of_elements; front++, back--, odd += 2) { A[front] = A[back] = odd; } for(int front = no_of_elements + 1, back = 2*no_of_elements - 1, even = 2; even <= no_of_elements; front++, back--, even += 2) { A[front] = A[back] = even; } for(int i = 1; i <= 2*no_of_elements; i++) { if(A[i] == 0) { A[i] = no_of_elements; } } for(int i = 1; i <= 2*no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Pair of Numbers Explanation.txt ================================================ Here is the crucial insight If an element in [L, R] divides every other element in it, then it is the GCD Now, for each segment how do we check if the GCD occurs in it ? If the GCD occurs in it, then the GCD is the minimum integer GCD[L, R] = Min[L, R] Is the condition we need to check ----- Let us use Sparse Tables for this as there are no update operations required We will do binary search on the length and settle the on the maximum length such that GCD[segment] = Minimum[segment] ----- After finding out the maximum length, we will just collect all of them in a vector ----- #include #include #include using namespace std; const int MAX_N = 3e5 + 5, MAX_L = 20; int no_of_elements, A[MAX_N]; int gcd_table[MAX_N][MAX_L], min_table[MAX_N][MAX_L]; int gcd(int x, int y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } int is_bit_set(int n, int bit) { return ( (n&(1 << bit)) != 0 ); } void precompute() { for(int i = 1; i <= no_of_elements; i++) { gcd_table[i][0] = A[i]; min_table[i][0] = A[i]; } for(int l = 1; l < MAX_L; l++) { int jump = (1 << (l - 1)); for(int i = 1; i + (1 << l) - 1 <= no_of_elements; i++) { int next = i + jump; gcd_table[i][l] = gcd(gcd_table[i][l - 1], gcd_table[next][l - 1]); min_table[i][l] = min(min_table[i][l - 1], min_table[next][l - 1]); } } } pair compute(int i, int length) { int gcd_here = A[i], min_here = A[i]; for(int bit = MAX_L; bit >= 0; bit--) { if(is_bit_set(length, bit)) { gcd_here = gcd(gcd_here, gcd_table[i][bit]); min_here = min(min_here, min_table[i][bit]); i += (1 << bit); } } return make_pair(gcd_here, min_here); } int possible(int length) { for(int i = 1; i + length - 1 <= no_of_elements; i++) { pair answer = compute(i, length); int gcd_here = answer.first, minimum_here = answer.second; if(gcd_here == minimum_here) { return true; } } return false; } int main() { cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } precompute(); int left = 1, right = no_of_elements + 1; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid)) { left = mid; } else { right = mid; } } vector answer; for(int i = 1; i + left - 1 <= no_of_elements; i++) { pair answer_here = compute(i, left); int gcd_here = answer_here.first, min_here = answer_here.second; if(gcd_here == min_here) { answer.push_back(i); } } cout << answer.size() << " " << left - 1 << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Pashmak and Graph Explanation.txt ================================================ 1. We will keep an empty graph and add the edges one by one in ascending order of weight 2. When we add an edge (u, v) then we will update path[v] = max(1 + path[u], path[v]) 3. We have to be careful on handling edges of the same weight Suppose we have multiple edges ending at u and then at v, we can't use both u and v So, we will process all edges of the same weigh together ----- struct Edge { int source, destination, weight; int operator <(const Edge &A) { return (weight < A.weight); } }; int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); vector edge(no_of_edges + 1); for(int i = 1; i <= no_of_edges; i++) { scanf("%d %d %d", &edge[i].source, &edge[i].destination, &edge[i].weight); } sort(all(edge)); vector maximum_ending_at(no_of_vertices + 1, 0); vector maximum_with_this_weight(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_edges; ) { int j = i; for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = 0; } //Process all edges having this weight. Have a different vector so you don't interact with equal weights. for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = max(maximum_with_this_weight[edge[j].destination], 1 + maximum_ending_at[edge[j].source]); } for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_ending_at[edge[j].destination] = max(maximum_ending_at[edge[j].destination], maximum_with_this_weight[edge[j].destination]); } i = j; } int maximum_path = 0; for(int i = 1; i <= no_of_vertices; i++) maximum_path = max(maximum_path, maximum_ending_at[i]); printf("%d\n", maximum_path); return 0; } ================================================ FILE: 2020/Practice/Explanations/Pavel and Triangles Explanation.txt ================================================ Let us make 1 observation 2^i > 1 + 2 + 2^2 + ... + 2^{i - 1} So, let us look at the largest side of the triangle. Let it be 2^i One of the other two sides also should be = 2^i, Otherwise, if both sides 2^j and 2^k are < 2^i, it will not satisfy the triangle inequality ----- Every triangle is of this form (2^i, 2^j, 2^j) i < j (2^i, 2^i, 2^i) ----- Let us be greedy. We will go through the sticks greedily For each i, we will try to pair 2 of it's sticks with as many of the sticks remaining in the prefix. Then, we will try to make as many equilateral triangles as possible ----- This solution is always optimal. Let us suppose there is some optimal solution where the sticks of our triplet (i, j, j) are used in different triplets (i, k1, k1), (j, k2, k2) and (j, k3, k3) we can swap them to have the same arrangement (i, j, j), (k1, k2, k2) and (k1, k3, k3) Our solution won't get worse. We can apply a similar exchange argument to all cases relating to how many sticks we use ----- int main() { int no_of_sticks; cin >> no_of_sticks; vector A(no_of_sticks + 1); for(int i = 1; i <= no_of_sticks; i++) { cin >> A[i]; } long long no_of_triangles = 0; int remaining_sticks = 0; for(int highest = 1; highest <= no_of_sticks; highest++) { int triangles_here = min(remaining_sticks, A[highest]/2); no_of_triangles += triangles_here; A[highest] -= 2*triangles_here; remaining_sticks = remaining_sticks - triangles_here; no_of_triangles += A[highest]/3; A[highest] %= 3; remaining_sticks += A[highest]; } cout << no_of_triangles << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Plus and XOR Explanation.txt ================================================ Observation - X is a submask of Y Whenever X has a bit set, Y also has a bit set. If X has some bits set that Y does not, we can make X[i] = 0 and Y[i] = 1 And the sum and XOR would not change. Y = X + (Bits where only Y has a bit) But, we can get this value easily from the xor ! X^Y = (Bits where only Y has a bit) = B So, Y = X + B A = X + Y = X + (X + B) = 2X + B X = (A - B)/2 We have to check that A and B are non negative, (A - B) is even and X^Y = B Use unsigned long long instead of long long to avoid overflow ------ int main() { unsigned long long A, B; cin >> A >> B; //Y = X + B, A = 2X + B if(A < B || (A - B)%2 != 0) { cout << "-1\n"; return 0; } unsigned long long X = (A - B)/2, Y = A - X; //cout << X + Y << " " << (X^Y) << "\n"; if(X + Y != A || (X^Y) != B) { cout << "-1\n"; return 0; } cout << X << " " << Y << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Points Explanation.txt ================================================ We want to compute (x2 - x1)^2 + (y2 - y1)^2 for every pair. X and Y is independent so we will compute it differently Let us look at the X's. A given X1 is linked with (n - 1) other points (X1 - X2)^2 = X1^2 + X2^2 - 2X1.X2 X1 is linked with (N - 1) points so each square is counted (N - 1) times. Now, let us try to calculate the linear term. Each X1 is multiplied with (X1 + X2 + ... + Xn - X1) Note that we do not need to put a multiplier of 2 here since we will be adding Xi.Xj when we at Xi and we will be adding Xj.Xi when we are at Xi So, we only have to add it once ------ long long calculate(vector &P, int n) { long long squares = 0; for(int i = 1; i <= n; i++) { squares += (n - 1)*P[i]*P[i]; } long long sum = 0; for(int i = 1; i <= n; i++) { sum += P[i]; } long long linear_term = 0; for(int i = 1; i <= n; i++) { linear_term += P[i]*(sum - P[i]);// 2*P[i]*P[i]; } return (squares - linear_term); } int main() { int no_of_points; cin >> no_of_points; vector X(no_of_points + 1); vector Y(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) { cin >> X[i] >> Y[i]; } long long distance = calculate(X, no_of_points) + calculate(Y, no_of_points); cout << distance << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Prime Number Explanation.txt ================================================ The exponent of the i-th numerator will be (Sum - A[i]) The GCD of the numerator will be the minimum exponent The GCD of the fraction will be min(minimum_exponent, sum) ----- Now, how do we find out the minimum exponent ? At first, we will keep track of all the exponents. If the smallest exponent E[1] occurs x times or 2x times or any multiple of x times, Then, we can combine x terms of E[1] to get a new exponent of (E[1] + 1) frequency[E[1] + 1] += frequency[E[1]]/x We do this till frequency[E[1]] is not a multiple of x Then, the GCD of the numerator is E[1] ----- We can use a Set for our purpose ----- #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long power_mod(long long x, long long power, long long mod) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%mod; x = (x*x)%mod; power = power/2; } return result; } int main() { int no_of_elements, x; cin >> no_of_elements >> x; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long sum = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; } set S; map frequency; for(int i = 1; i <= no_of_elements; i++) { frequency[sum - A[i]]++; S.insert(sum - A[i]); } const int MOD = 1e9 + 7; long long answer; for(auto it = S.begin(); ; it++) { while(frequency[*(S.begin())]%x == 0) { long long exponent = *(S.begin()); long long new_exponent = exponent + 1; frequency[new_exponent] += frequency[exponent]/x; S.insert(new_exponent); S.erase(exponent); } if(frequency[*( S.begin() )] != 0) { answer = min(sum, *( S.begin() )); break; } } cout << power_mod(x, answer, MOD) << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Ramesses and Corner Inversion Explanation.txt ================================================ Let us look for an invariant in this operation. In 1 operation, we will be flipping 2 elements of a row and 2 elements of a column. This means that (0,0) -> (1, 1) (0,1) -> (1, 0) (1, 1) -> (1, 1) All these operations preserve the sum (mod 2) We have to check if the parity of all rows and columns are the same in A and B ----- #include #include using namespace std; void read(vector > &A) { for(int i = 1; i < A.size(); i++) { for(int j = 1; j < A[0].size(); j++) { cin >> A[i][j]; } } } void compute(vector > &A, vector &row_sum, vector &column_sum) { for(int i = 1; i < A.size(); i++) { for(int j = 1; j < A[0].size(); j++) { row_sum[i] += A[i][j]; column_sum[j] += A[i][j]; } } } int main() { int rows, columns; cin >> rows >> columns; vector > A(rows + 1, vector (columns + 1)); read(A); vector > B(rows + 1, vector (columns + 1)); read(B); vector A_row_sum(rows + 1), A_column_sum(columns + 1); compute(A, A_row_sum, A_column_sum); vector B_row_sum(rows + 1), B_column_sum(columns + 1); compute(B, B_row_sum, B_column_sum); int row_and_column_same_parity = true; for(int i = 1; i <= rows; i++) { if(A_row_sum[i]%2 != B_row_sum[i]%2) { row_and_column_same_parity = false; } } for(int j = 1; j <= columns; j++) { if(A_column_sum[j]%2 != B_column_sum[j]%2) { row_and_column_same_parity = false; } } cout << (row_and_column_same_parity ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: 2020/Practice/Explanations/Scheme.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e5 + 15; vector graph[MAX_N]; vector visited(MAX_N, false); vector incoming(MAX_N, 0); vector beginning; vector ending; void dfs(int v) { visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(visited[child]) { ending.push_back(child); return; } dfs(child); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { int destination; scanf("%d", &destination); graph[i].push_back(destination); incoming[destination]++; } for(int i = 1; i <= no_of_vertices; i++) { if(incoming[i] == 0) { beginning.push_back(i); dfs(i); } } for(int i = 1; i <= no_of_vertices; i++) { if(!visited[i]) { beginning.push_back(i); dfs(i); } } int no_of_sinks = 0; for(int i = 1; i <= no_of_vertices; i++) { if(incoming[i] == 0) { no_of_sinks++; } } int simple_cycle = (no_of_sinks == 0 && beginning.size() == 1); int new_edges = (simple_cycle ? 0 : beginning.size()); printf("%d\n", new_edges); for(int i = 0; i < new_edges; i++) { printf("%d %d \n",ending[i], beginning[(i + 1)%new_edges]); } return 0; } ================================================ FILE: 2020/Practice/Explanations/Secret Passwords Explanation.txt ================================================ 1. Let us draw a graph where each alphabet is a vertex 2. We will draw an edge between two alphabets if they occur in the same word 3. The number of components in this graph is the number of equivalent passwords. ----- 1. I did this by creating a bitmask corresponding to each word 2. If a word has two bits set - B1 and B2, connect (B1, B2) using a DSU structure 3. Each time we perform a 'unite' operation, the number of connected components reduces by 1 4. We need to be careful of 1 thing. In the beginning we created a DSU of 26 vertices But all 26 alphabets might not be used. The alphabets that are not used will be single components 5. So, the answer is the number of components in our graph - the number of unused alphabets ----- int main() { int no_of_words; cin >> no_of_words; vector used(NO_OF_ALPHABETS, false); DSU dsu(NO_OF_ALPHABETS); for(int i = 1; i <= no_of_words; i++) { string word; cin >> word; int mask = 0; for(int j = 0; j < word.size(); j++) { mask |= (1 << (word[j] - 'a')); used[word[j] - 'a'] = true; } for(int bit_1 = 0; bit_1 < NO_OF_ALPHABETS; bit_1++) { for(int bit_2 = 0; bit_2 < NO_OF_ALPHABETS; bit_2++) { if(!is_set(mask, bit_1) || !is_set(mask, bit_2) || dsu.get_parent(bit_1) == dsu.get_parent(bit_2)) { continue; } dsu.unite(bit_1, bit_2); } } } int unused_alphabets = 0; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(!used[alpha]) { unused_alphabets++; } } int actual_components = dsu.no_of_components - unused_alphabets; cout << actual_components << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Segments Explanation.txt ================================================ The idea is to treat each entry and exit as an 'event' and sort all the events. When we meet an 'ending', we put a nail on it. This satisfies all the segments which are open. So we will remove all the open segments from our list. ---- int main() { int no_of_segments; cin >> no_of_segments; vector S; for(int i = 0; i < no_of_segments; i++) { int left, right; cin >> left >> right; if(left > right) { swap(left, right); } S.push_back(segment(left, ENTRY, i)); S.push_back(segment(right, EXIT, i)); } sort(all(S), sort_by_left); vector already_handled(no_of_segments, false); vector meeting_points; stack handled_indices; for(int i = 0; i < 2*no_of_segments; i++) { if(already_handled[S[i].index]) { continue; } if(S[i].type == ENTRY) { handled_indices.push(S[i].index); } else if(S[i].type == EXIT) { meeting_points.push_back(S[i].point); while(handled_indices.size() > 0) { already_handled[handled_indices.top()] = true; handled_indices.pop(); } } } cout << meeting_points.size() << "\n"; for(int i = 0; i < meeting_points.size(); i++) { cout << meeting_points[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/Special Segments of Permutation Explanation.txt ================================================ Let us try to brute force this problem. Let Left_border[i] represent the first index on the left of P[i] that is > P[i] Let Right_border[i] represent the first index on the right We will go through each j in the Left_border and if it is P[j], Check if (P[i] - P[j]) is present in [i, Right_border[i]] ------ int get_count(int left_1, int right_1, int left_2, int right_2, int total_sum) { if(right_2 - left_2 < right_1 - left_1) { swap(right_1, right_2); swap(left_1, left_2); } int count = 0; for(int i = left_1; i <= right_1; i++) { int remaining = total_sum - permutation[i]; if(1 <= remaining && remaining <= no_of_elements && left_2 <= position[remaining] && position[remaining] <= right_2) { count++; } } return count; } ----- This approach looks like it is O(n^2) but it is actually O(N log N) provided we choose the smaller segment among the left and right border each time Let us look at the largest element of the array. It divides the array into 2 segments of length - m1, m2 where m1 + m2 = n - 1 The minimum of m1, m2 <= n/2 So the number of comparisons done in n/2 Now, let us look at the largest elements of segments m1 and m2 They will lead to m1/2 <= n/4 and m2/2 <= n/2 comparisons The number of comparisons for these 3 elements is n(1/2 + 1/4 + 1/2) Similarly, we will go to the largest elements in the remaining segments. Each element will have a number of comparisons of the form n/2^i, i >= 1 So, finally, the time complexity will be n x O(log n) = O(n log n) ----- Although we are processing the elements from i = 1 to n, the time complexity is easier to process if we visit the elements in descending order. That's what makes this problem and this complexity analysis so beautiful ! ----- Now, how do we find out the left and right border of each i ? We can do it with a linear scan and a stack. Initially, the stack is empty. When we encounter P[i], we will pop the top of the stack as long as stack.top < P[i] And then we will push P[i] We have popped off all indices j, such that P[j] < P[i] This is optimal, because any future index k, such that j < i < k and P[j] > P[k] Will be better matched to i instead as P[i] > P[j] > P[k] ----- int main() { cin >> no_of_elements; permutation.resize(no_of_elements + 1); position.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> permutation[i]; position[permutation[i]] = i; } vector left_border(no_of_elements + 1); stack > left_S; left_S.push(make_pair(no_of_elements + 1, 0)); for(int i = 1; i <= no_of_elements; i++) { while(left_S.top().first < permutation[i]) { left_S.pop(); } left_border[i] = left_S.top().second + 1; left_S.push(make_pair(permutation[i], i)); } stack > right_S; vector right_border(no_of_elements + 1); right_S.push(make_pair(no_of_elements + 1, no_of_elements + 1)); for(int i = no_of_elements; i >= 1; i--) { while(right_S.top().first < permutation[i]) { right_S.pop(); } right_border[i] = right_S.top().second - 1; right_S.push(make_pair(permutation[i], i)); } int no_of_special_segments = 0; for(int i = 1; i <= no_of_elements; i++) { no_of_special_segments += get_count(left_border[i], i - 1, i + 1, right_border[i], permutation[i]); //cout << "i = " << permutation[i] << " Count = " << no_of_special_segments << "\n"; } cout << no_of_special_segments << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/The Sum of the k-th Powers Explanation.txt ================================================ Let f(n, k) = 1^k + 2^k + ... + n^k f(n, k) is a polynomial of degree k + 1. We can invoke the Fundamental Theorem of Algebra and interpolate it by getting the value of this function at (k + 2) points. ----- If n <= (k + 2), we can give the answer directly. Otherwise, we will perform Lagrangian Interpolation in O(k) time. ----- Proof that f(n, k) is a polynomial of degree (k + 1) by Mathematical Induction f(n, 1) = n^2/2 + n/2 is a polynomial of degree 2. Let it be true for f(n, k) Let us take the derivative of f(n, k + 1) with respect to k f'(n, k + 1) = k(1^k + 2^k + ... + n^k) = k.f(n, k) Since the derivative is a polynomial of degree (k + 1), f(n, k + 1) is a polynomial function of degree (k + 2). This means that we can perform Lagrangian Interpolation on it. ----- How do we perform Lagrangian Interpolation in O(k) time ? The numerator is (n - 1)(n - 2) ... (n - (i - 1)) (n - (i + 1)) ... (n - (k + 1)) What happens when we transition from i to i + 1 ? We must remove (n - (i + 1)) from the product and put (n - i) back into the product. The denominator is a little more tricky. At first, it is (1 - 2)(1 - 3) .... (1 - (k + 1)) Then, it becomes (2 - 1) (2 - 3) .... (2 - (k + 1)) Since the values that we have sampled the function at {1, 2, ... , k + 1} are contiguous, we can take advantage of it. The running product increases by 1 at each step. We will keep track of the smallest and largest term in the denominator product. At each step, we will remove the smallest term, and add a (largest + 1) term into the product. There is a special case here. The denominator will never have a term of 0. So if either smallest or largest points to 0, increase it by 1 again. Also, ensure that the terms are never negative as we are dealing with MOD. ----- int main() { long long n, power; cin >> n >> power; //f(i) = 1^k + 2^k + ... + i^k vector value(power + 3, 0); for(int i = 1; i <= power + 2; i++) { value[i] = (value[i - 1] + power_mod(i, power))%MOD; } if(n <= power + 2) { cout << value[n] << "\n"; return 0; } long long numerator = 1, denominator = 1; long long largest = (1 - 2 + MOD)%MOD, smallest = (1 - (power + 2) + MOD)%MOD; for(int i = 2; i <= power + 2; i++) { numerator = (numerator*(n - i))%MOD; denominator = (denominator*(1 - i + MOD))%MOD; } long long answer = value[1]*numerator; answer = (answer*inverse(denominator))%MOD; for(int i = 2; i <= power + 2; i++) { numerator = (numerator*inverse(n - i))%MOD; numerator = (numerator*(n - (i - 1)))%MOD; largest = (largest + 1)%MOD; if(largest == 0) { largest = (largest + 1)%MOD; } if(smallest == 0) { smallest = (smallest + 1)%MOD; } denominator = (denominator*inverse(smallest))%MOD; denominator = (denominator*(largest))%MOD;// cout << "Remove small = " << smallest << " largest = " << largest << " D = " << denominator << "\n"; smallest = (smallest + 1)%MOD; long long current_term = (numerator*inverse(denominator))%MOD; current_term = (value[i]*current_term)%MOD; answer = (answer + current_term)%MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Explanations/The Treasure of Segments Explanation.txt ================================================ Let us count the number of deletions we have to make for each segment. For there to be no segments outside a segment [L, R], there should be no segment ending before L and beginning after R. These segments are disjoint. So, we will do binary search to count the number of segments such that 1. R[i] < L 2. R < L[i] For each [L, R] ----- void solve() { int no_of_segments; cin >> no_of_segments; vector sorted_left(no_of_segments + 1), sorted_right(no_of_segments + 1); vector left(no_of_segments + 1), right(no_of_segments + 1); for(int i = 1; i <= no_of_segments; i++) { cin >> left[i] >> right[i]; sorted_left[i] = left[i]; sorted_right[i] = right[i]; } sort(all(sorted_left)); sort(all(sorted_right)); int minimum_deletions = no_of_segments; for(int i = 1; i <= no_of_segments; i++) { int after_right = no_of_segments - (upper_bound(all(sorted_left), right[i]) - sorted_left.begin()) + 1; int before_left = lower_bound(all(sorted_right), left[i]) - sorted_right.begin() - 1; //cout << "For [" << left[i] << "," << right[i] << "] Before Left = " << before_left << " and after right = " << after_right << "\n"; int deletions_here = after_right + before_left; minimum_deletions = min(minimum_deletions, deletions_here); } cout << minimum_deletions << "\n"; } ================================================ FILE: 2020/Practice/Explanations/Winter is Here Explanation.txt ================================================ Let us try to count the contribution of all sequences who's GCD = G Now, suppose there are n elements which are divisible by G. What is the contribution of each such sequence ? The contribution is 1. C(n, 1) + 2. C(n, 2) + 3. C(n, 3) + ... + n. C(n, n) = sum k C(n, k) = sum k n/k sum(n - 1, k - 1) = n 2^{n - 1} Let this be f(n) ----- Now, there is a problem here. This is all the sequences which are divisible by G. But, they might also be divisible by 2G, 3G or some other multiple of G, which means G might not be it's GCD To resolve this issue, We will start from G = 10^6 and then go downwards to 2 When we are at G = i, we will maintain the invariant that we have calculated f(i + 1), f(i + 2), ... , f(10^6) f(G) = n 2^{n - 1} - f(2G) - f(3G) - .... This will give us exactly the contribution of all sequences who's GCD = G ----- int main() { const int MAX_N = 1e6 + 5, MOD = 1e9 + 7; int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector multiple_count(MAX_N, 0); for(int i = 1; i <= no_of_elements; i++) { multiple_count[A[i]]++; } for(int m = 1; m < MAX_N; m++) { for(int multiple = 2*m; multiple < MAX_N; multiple += m) { multiple_count[m] += multiple_count[multiple]; } } vector answer(MAX_N, 0); for(int m = MAX_N - 1; m >= 1; m--) { answer[m] = multiple_count[m]*power_mod(2, multiple_count[m] - 1, MOD); answer[m] %= MOD; //cout << answer[m] << "\n"; for(int multiple = 2*m; multiple < MAX_N; multiple += m) { answer[m] = (answer[m] - answer[multiple] + MOD)%MOD; } //cout << answer[m] << "\n"; //cout << "Answer " << m << " = " << answer[m] << "\n"; } long long total_answer = 0; for(int m = 2; m < MAX_N; m++) { total_answer = (total_answer + answer[m]*m)%MOD; } cout << total_answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Alternative Thinking.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; int alternating_subsequence = 0; for(int i = 0; i < length; i++) { if(i == 0 || S[i] != S[i - 1]) { alternating_subsequence++; } } int answer = min(alternating_subsequence + 2, length); cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Ant Colony.cpp ================================================ #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; struct node { int gcd, minimum, minimum_frequency; node(){} node(int G, int M, int F) { gcd = G; minimum = M; minimum_frequency = F; } }; const int MAX_N = 1e5 + 5, oo = 1e9 + 9; node tree[4*MAX_N]; int A[MAX_N]; int gcd(int a, int b) { if(min(a, b) == 0) { return max(a, b); } return gcd(max(a, b)%min(a, b), min(a, b)); } node merge(node &A, node &B) { node C; C.gcd = gcd(A.gcd, B.gcd); if(A.minimum == B.minimum) { C.minimum = A.minimum; C.minimum_frequency = A.minimum_frequency + B.minimum_frequency; } else if(A.minimum < B.minimum) { C.minimum = A.minimum; C.minimum_frequency = A.minimum_frequency; } else if(B.minimum < A.minimum) { C.minimum = B.minimum; C.minimum_frequency = B.minimum_frequency; } return C; } void build(int n, int left, int right) { if(left == right) { tree[n] = node(A[left], A[left], 1); return; } int mid = (left + right)/2; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); tree[n] = merge(tree[LEFT(n)], tree[RIGHT(n)]); } node query(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || right < left) { return node(0, oo, 0); } if(query_left <= left && right <= query_right) { return tree[n]; } int mid = (left + right)/2; node left_answer = query(LEFT(n), left, mid, query_left, query_right); node right_answer = query(RIGHT(n), mid + 1, right, query_left, query_right); //cout << " At " << left << "," << right << " LEFT answer(" << left << "," << mid <<") = " << left_answer.gcd << " RIGHT answer(" << mid + 1 << "," << right << ") = " << right_answer.gcd << "\n"; return merge(left_answer, right_answer); } int main() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } build(1, 1, no_of_elements); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { int left, right; cin >> left >> right; node answer = query(1, 1, no_of_elements, left, right); int free = 0; //cout << "GCD = " << answer.gcd << " " << "Minimum = " << answer.minimum << "\n"; if(answer.gcd == answer.minimum) { free = answer.minimum_frequency; } int remaining = right - (left - 1) - free; cout << remaining << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Programs/Anton and Chess.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int check(int x, vector > &A, char attacker_1, char queen = 'Q') { pair king = make_pair(x, 'K'); int next = upper_bound(all(A), king) - A.begin(); if(next < A.size() && (A[next].second == attacker_1 || A[next].second == queen)) { return true; } int before = next - 1; if(before >= 0 && (A[before].second == attacker_1 || A[before].second == queen)) { return true; } return false; } int main() { int no_of_black_pieces; cin >> no_of_black_pieces; long long king_x, king_y; cin >> king_x >> king_y; long long king_diagonal = king_x - king_y; long long king_antidiagonal = king_x + king_y; vector > row, column, diagonal, anti_diagonal; for(int i = 1; i <= no_of_black_pieces; i++) { char piece; long long x, y; cin >> piece >> x >> y; if(x == king_x) { row.push_back(make_pair(y, piece)); } if(y == king_y) { column.push_back(make_pair(x, piece)); } if(x - y == king_diagonal) { diagonal.push_back(make_pair(x + y, piece)); } if(x + y == king_antidiagonal) { anti_diagonal.push_back(make_pair(x - y, piece)); } } sort(all(row)); sort(all(column)); sort(all(diagonal)); sort(all(anti_diagonal)); int in_check = false; in_check = (check(king_y, row, 'R') || check(king_x, column, 'R') || check(king_antidiagonal, diagonal, 'B') || check(king_diagonal, anti_diagonal,'B') ); cout << (in_check ? "YES" : "NO") << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Anton and Ira.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1), S(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } for(int i = 1; i <= no_of_elements; i++) { cin >> S[i]; } vector label(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { label[S[i]] = i; } for(int i = 1; i <= no_of_elements; i++) { P[i] = label[P[i]]; } long long cost = 0; vector > swaps; for(int current = no_of_elements, i; current >= 1; current--) { for(i = 1; i <= no_of_elements; i++) { if(P[i] == current) { break; } } //cout << "Current = " << current << " i = " << i << " \n"; for(int j = i + 1; j <= current; j++) { if(P[j] <= i) { //cout << "j = " << j << "\n"; swap(P[i], P[j]); swaps.push_back(make_pair(i, j)); cost += (j - i); i = j; } } } cout << cost << " " << swaps.size() << "\n"; for(int i = 0; i < swaps.size(); i++) { cout << swaps[i].first << " " << swaps[i].second << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Programs/Ants in Leaves.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 5e5 + 5; vector tree[MAX_N]; vector depths; void dfs(int v, int parent_v, int depth) { if(tree[v].size() == 1) { depths.push_back(depth); } for(int child_v : tree[v]) { if(child_v == parent_v) { continue; } dfs(child_v, v, depth + 1); } } int get_answer(int v) { dfs(v, 1, 0); sort(all(depths)); vector visit_order(depths.size()); for(int i = 0; i < visit_order.size(); i++) { visit_order[i] = depths[i]; if(i > 0) { visit_order[i] = max(visit_order[i - 1] + 1, visit_order[i]); } } depths.clear(); //cout << " Answer here = " << visit_order.back() << "\n"; return visit_order.back(); } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1, no_of_edges = no_of_vertices - 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } int answer = 0; for(int child : tree[1]) { answer = max(answer, get_answer(child) + 1); //cout << child << " "; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Army Creation.cpp ================================================ #include #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 1e5 +5; int k_th_ancestor[MAX_N]; vector indices[MAX_N]; vector tree[3*MAX_N]; vector merge(vector &L, vector &R) { vector answer; for(int l = 0, r = 0; l < L.size() || r < R.size(); ) { if(l == L.size()) { answer.push_back(R[r++]); continue; } if(r == R.size()) { answer.push_back(L[l++]); continue; } if(L[l] <= R[r]) { answer.push_back(L[l++]); } else { answer.push_back(R[r++]); } } return answer; } void build(int n, int left, int right) { if(left == right) { tree[n].push_back(k_th_ancestor[left]); /*cout << "n = " << n <<"[" << left <<"," << right << "]\n" << endl; for(int i = 0; i < tree[n].size(); i++) { cout << tree[n][i] << " "; } cout << "\n";*/ return; } int mid = (left + right)/2; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); tree[n] = merge(tree[LEFT(n)], tree[RIGHT(n)]); /*cout << "n = " << n <<"[" << left <<"," << right << "]\n" << endl; for(int i = 0; i < tree[n].size(); i++) { cout << tree[n][i] << " "; } cout << "\n";*/ } int query(int n, int left, int right, int query_left, int query_right, int x) { if(query_right < left || right < query_left) { return 0; } if(query_left <= left && right <= query_right) { return (upper_bound(all(tree[n]), x - 1) - tree[n].begin()); } int mid = (left + right)/2; return (query(LEFT(n), left, mid, query_left, query_right, x) + query(RIGHT(n), mid + 1, right, query_left, query_right, x)); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; indices[A[i]].push_back(i); if(indices[A[i]].size() > k) { int k_th_step = indices[A[i]].size() - 1 - k; k_th_ancestor[i] = indices[A[i]][k_th_step]; //cout << " K-th " << i << " = " << k_th_ancestor[i] << "\n"; } else { k_th_ancestor[i] = 0; } } build(1, 1, no_of_elements); int no_of_queries; cin >> no_of_queries; int answer = 0; for(int i = 1; i <= no_of_queries; i++) { int x, y; cin >> x >> y; int left = ((x + answer)%no_of_elements) + 1; int right = ((y + answer)%no_of_elements) + 1; if(left > right) { swap(left, right); } // cout << "L = " << left << " R = " << right << "\n"; //vector range = query(1, 1, no_of_elements, left, right); /*cout << "Size = " << range.size() << "\n"; for(int i = 0; i < range.size(); i++) { cout << range[i] << " "; } cout << "\n";*/ answer = query(1, 1, no_of_elements, left, right, left); cout << answer << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Programs/Bargain.cpp ================================================ #include #include using namespace std; long long power_mod(long long x, long long power, long long mod) { long long result = 1LL; while(power > 0) { if(power%2 == 1) { result = (result*x)%mod; } power = power >> 1; x = (x*x)%mod; } return result; } long long inverse(long long x, long long mod) { return power_mod(x, mod - 2, mod); } long long choose_2(long long n, long long mod) { return ((n*(n + 1))/2)%mod; } int main() { string S; cin >> S; const int MOD = 1e9 + 7; vector suffix_cost(S.size() + 5); for(int i = S.size() - 1, suffix = 0; i >= 0; i--, suffix++) { suffix_cost[i] = power_mod(10, suffix, MOD)*(S[i] - '0'); suffix_cost[i] %= MOD; suffix_cost[i] *= choose_2(i, MOD); suffix_cost[i] %= MOD; } vector multiplier(S.size() + 5, 0); for(int i = 1; i <= S.size(); i++) { multiplier[i] = (multiplier[i - 1] + (i)*power_mod(10, i - 1, MOD))%MOD; } vector prefix_cost(S.size() + 1, 0); for(int i = 0; i < S.size(); i++) { prefix_cost[i] = ((multiplier[S.size() - 1 - i])*(S[i] - '0'))%MOD; //cout << "Prefix Cost " << i << " = " << prefix_cost[i] << "\n"; } long long answer = 0; for(int i = 0; i < S.size(); i++) { answer += (prefix_cost[i] + suffix_cost[i])%MOD; answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Concatenated Multiples.cpp ================================================ #include #include #include using namespace std; int no_of_digits(int n) { int count = 0; while(n) { count++; n /= 10; } //cout << "N = " << n << " Count = " << count << "\n"; return count; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_DIGITS = 11; map frequency_mod[MAX_DIGITS]; long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { for(long long t = 10, d = 1; d < MAX_DIGITS; d++, t = (t*10)%k) { frequency_mod[d][ (A[i]*t)%k ]++; //cout << "D = " << d << " M = " << (A[i]*t)%k << " = " << frequency_mod[d][ (A[i]*t)%k ] << "\n"; } } for(int i = 1; i <= no_of_elements; i++) { long long first_part_mod = (0 - A[i]%k + k)%k; //cout << "Need d = " << no_of_digits(A[i]) << " with M = " << first_part_mod << "\n"; answer += frequency_mod[no_of_digits(A[i])][first_part_mod]; //cout << "Answer = " << answer << "\n"; long long t = 1; for(long long d = 1; d <= no_of_digits(A[i]) ;d++) { t = (t*10)%k; } if( (t*A[i] + A[i])%k == 0 ) { //cout << "Self!\n"; answer--; } //cout << "Answer = " << answer << "\n"; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Count Pairs.cpp ================================================ #include #include #include using namespace std; long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { int no_of_elements, p, k; cin >> no_of_elements >> p >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map value_frequency; for(int i = 1; i <= no_of_elements; i++) { long long value = (A[i]*A[i])%p; value = (value*A[i])%p; value = (value*A[i])%p; value = (value - k*A[i])%p; value = (value + p)%p; value_frequency[value]++; } long long no_of_pairs = 0; for(auto it = value_frequency.begin(); it != value_frequency.end(); it++) { no_of_pairs += choose_2(it->second); } cout << no_of_pairs << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Cram Time.cpp ================================================ #include #include using namespace std; void display(vector &A) { cout << A.size() << "\n"; for(int i = 0; i < A.size(); i++) { cout << A[i] << " "; } cout << "\n"; } int main() { long long a, b; cin >> a >> b; long long left = 0, right = 1e5; while(right - left > 1) { long long mid = (right + left)/2; if(mid*(mid + 1) <= (a + b)*2) { left = mid; } else { right = mid; } } vector day_a, day_b; long long problems = left; for(long long i = problems; i >= 1; i--) { if(a >= i) { day_a.push_back(i); a -= i; } else { for(; i >= 1; i--) { if(i == a) { day_a.push_back(i); a -= i; } else { day_b.push_back(i); b -= i; } } } } display(day_a); display(day_b); return 0; } ================================================ FILE: 2020/Practice/Programs/Cycles.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 105; int graph[MAX_N][MAX_N]; long long choose_3(long long n) { return (n*(n - 1)*(n - 2))/6; } long long choose_2(long long n) { return (n*(n - 1))/2; } void add_edge(int u, int v) { graph[u][v] = 1; graph[v][u] = 1; } int main() { int no_of_edges; cin >> no_of_edges; int complete_graph = 0; for(int i = 1; ; i++) { if(choose_3(i) > no_of_edges) { complete_graph = i - 1; no_of_edges -= choose_3(complete_graph); break; } } vector extra_matching; while(no_of_edges > 0) { for(int i = complete_graph; i >= 0; i--) { if(choose_2(i) <= no_of_edges) { extra_matching.push_back(i); no_of_edges -= choose_2(i); break; } } } memset(graph, 0, sizeof(graph)); for(int i = 1; i <= complete_graph; i++) { for(int j = i + 1; j <= complete_graph; j++) { add_edge(i, j); } } for(int i = 0; i < extra_matching.size(); i++) { int v = complete_graph + i + 1; int v_limit = extra_matching[i]; for(int w = 1; w <= v_limit; w++) { add_edge(v, w); } } int no_of_vertices = complete_graph + extra_matching.size(); cout << no_of_vertices << "\n"; for(int i = 1; i <= no_of_vertices; i++) { for(int j = 1; j <= no_of_vertices; j++) { cout << graph[i][j]; } cout << "\n"; } return 0; } ================================================ FILE: 2020/Practice/Programs/Elections.cpp ================================================ #include #include #include using namespace std; const int MAX_PARTIES = 3333; vector > votes; long long cost_if_final_count(int n) { int additional_votes = 0; long long cost = 0; vector extra_votes; for(int i = 2; i < votes.size(); i++) { for(int j = 0; j < votes[i].size(); j++) { //cout << "Party = " << i << " Person = " << j << "\n"; if(j + n <= votes[i].size()) { additional_votes++; cost += votes[i][j]; } else { //cout << "Extra \n"; extra_votes.push_back(votes[i][j]); } } } int remaining = n - votes[1].size() - additional_votes; //cout << "Remaining = " << remaining << "\n"; if(remaining <= 0) { return cost; } sort(extra_votes.begin(), extra_votes.end()); for(int i = 0; i < remaining && i < extra_votes.size(); i++) { cost += extra_votes[i]; } return cost; } int main() { int no_of_voters, no_of_parties; cin >> no_of_voters >> no_of_parties; votes.resize(no_of_parties + 1); for(int i = 1; i <= no_of_voters; i++) { int party, cost; cin >> party >> cost; votes[party].push_back(cost); } for(int i = 2; i <= no_of_parties; i++) { sort(votes[i].begin(), votes[i].end()); } long long answer = 1e18; for(int i = 1; i <= no_of_voters; i++) { //cout << "cost " << i << " = " << cost_if_final_count(i) << "\n"; answer = min(answer, cost_if_final_count(i)); } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Fight Against Traffic.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 1005; vector graph[MAX_N]; set edge_exists[MAX_N]; void bfs(int source, vector &distance) { queue Q; Q.push(source); distance[source] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = 0; i < graph[u].size(); i++) { int v = graph[u][i]; if(distance[v] == -1) { distance[v] = distance[u] + 1; Q.push(v); } } } } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; int source, target; cin >> source >> target; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); edge_exists[u].insert(v); edge_exists[v].insert(u); } vector source_distance(no_of_vertices + 1, -1), target_distance(no_of_vertices + 1, -1); bfs(source, source_distance); bfs(target, target_distance); int minimum_distance = source_distance[target]; long long no_of_good_pairs = 0; for(int u = 1; u <= no_of_vertices; u++) { for(int v = u + 1; v <= no_of_vertices; v++) { if(edge_exists[u].count(v) == 1) { continue; } if(source_distance[u] + 1 + target_distance[v] >= minimum_distance && source_distance[v] + 1 + target_distance[u] >= minimum_distance) { no_of_good_pairs++; } } } cout << no_of_good_pairs << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Hacker, pack your Bags.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct Point { int x, cost, duration, is_left; Point(){} Point(int X, int C, int D, int is_L) { x = X; cost = C; duration = D; is_left = is_L; } }; int sort_by_point(Point &A, Point &B) { if(A.x == B.x) { return (A.is_left && !B.is_left ? true : false); } return (A.x < B.x); } int main() { int no_of_segments, total; cin >> no_of_segments >> total; vector A; for(int i = 1; i <= no_of_segments; i++) { int left, right, x; cin >> left >> right >> x; A.push_back(Point(left, x, right - left + 1, true)); A.push_back(Point(right, x, right - left + 1, false)); } sort(A.begin(), A.end(), sort_by_point); map minimum_cost; const int oo = 2e9 + 7; int answer = oo; for(int i = 0; i < 2*no_of_segments; i++) { if(A[i].is_left) { if(minimum_cost.find(total - A[i].duration) != minimum_cost.end()) { answer = min(answer, minimum_cost[total - A[i].duration] + A[i].cost); } } else { if(minimum_cost.find(A[i].duration) != minimum_cost.end()) { minimum_cost[A[i].duration] = min(minimum_cost[A[i].duration], A[i].cost); } else { minimum_cost[A[i].duration] = A[i].cost; } } } cout << (answer >= oo ? -1 : answer) << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Imbalanced Array.cpp ================================================ #include #include #include using namespace std; void compute_max_borders(int n, vector &A, vector &L, vector &R) { const int oo = 1e9 + 9; stack < pair > left_max; left_max.push(make_pair(0, oo)); for(int i = 1; i <= n; i++) { while(left_max.top().second < A[i]) { left_max.pop(); } L[i] = left_max.top().first + 1; //Range in which A[i] is maximum left_max.push(make_pair(i, A[i])); } stack < pair > right_max; right_max.push(make_pair(n + 1, oo)); for(int i = n; i >= 1; i--) { while(right_max.top().second <= A[i]) { right_max.pop(); } R[i] = right_max.top().first - 1; right_max.push(make_pair(i, A[i])); } } void compute_min_borders(int n, vector &A, vector &L, vector &R) { const int oo = 1e9 + 9; stack < pair > left_min; left_min.push(make_pair(0, -oo)); for(int i = 1; i <= n; i++) { while(left_min.top().second > A[i]) { left_min.pop(); } L[i] = left_min.top().first + 1; //cout << "L " << i << " = " << L[i] << "\n"; left_min.push(make_pair(i, A[i])); } stack < pair > right_min; right_min.push(make_pair(n + 1, -oo)); for(int i = n; i >= 1; i--) { while(right_min.top().second >= A[i]) { right_min.pop(); } R[i] = right_min.top().first - 1; right_min.push(make_pair(i, A[i])); } } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector left_max_border(no_of_elements + 1), right_max_border(no_of_elements + 1); compute_max_borders(no_of_elements, A, left_max_border, right_max_border); long long total_maximum = 0; for(int i = 1; i <= no_of_elements; i++) { long long left_half = i - left_max_border[i], right_half = (right_max_border[i] - i); long long no_of_maximas = (left_half + 1)*(right_half + 1); total_maximum += no_of_maximas*A[i]; } vector left_min_border(no_of_elements + 1), right_min_border(no_of_elements + 1); compute_min_borders(no_of_elements, A, left_min_border, right_min_border); long long total_minimum = 0; for(int i = 1; i <= no_of_elements; i++) { long long left_half = i - left_min_border[i], right_half = right_min_border[i] - i; long long no_of_minima = (left_half + 1)*(right_half + 1); total_minimum += no_of_minima*A[i]; } long long answer = total_maximum - total_minimum; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Laboratory Work.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_points; cin >> no_of_points; vector X(no_of_points); for(int i = 0; i < no_of_points; i++) { cin >> X[i]; } sort(all(X)); int minimum = X[0]; const int MAX_TYPES = 3; vector frequency(MAX_TYPES, 0); for(int i = 0; i < no_of_points; i++) { frequency[X[i] - minimum]++; } vector new_frequency(MAX_TYPES, 0); for(int t = 0; t < MAX_TYPES; t++) { new_frequency[t] = frequency[t]; } if(frequency[1]/2 > min(frequency[0], frequency[2]) && frequency[2] > 0 && frequency[0] > 0) { new_frequency[0] = frequency[0] + frequency[1]/2; new_frequency[1] = frequency[1]%2; new_frequency[2] = frequency[2] + frequency[1]/2; } else if(frequency[1]/2 <= min(frequency[0], frequency[2])) { new_frequency[0] = frequency[0] - min(frequency[0], frequency[2]); new_frequency[1] = frequency[1] + 2*min(frequency[0], frequency[2]); new_frequency[2] = frequency[2] - min(frequency[0], frequency[2]); } int equal_elements = 0; for(int t = 0; t < MAX_TYPES; t++) { equal_elements += min(frequency[t], new_frequency[t]); } cout << equal_elements << "\n"; for(int t = 0; t < MAX_TYPES; t++) { for(int i = 0; i < new_frequency[t]; i++) { cout << minimum + t << " "; } } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Lieges of Legendre.cpp ================================================ #include #include using namespace std; int get_grundy(int n, int k) { if(n == 0) { return 0; } if(n == 1) { return 1; } if(k%2 == 0) { if(n == 2) { return 2; } return (n%2 == 0 ? 1 : 0); } else { if(n%2 == 1) { return (n <= 3 ? 1 : 0); } if(n == 2) { return 0; } if(n == 4) { return 2; } return (get_grundy(n/2, k) == 1 ? 2 : 1); } } int main() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); vector grundy(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; grundy[i] = get_grundy(A[i], k); } int nim_sum = 0; for(int i = 1; i <= no_of_elements; i++) { nim_sum ^= grundy[i]; } cout << (nim_sum != 0 ? "Kevin" : "Nicky") << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Line.cpp ================================================ #include #include #include using namespace std; long long extended_gcd(long long A, long long B, long long &x, long long &y) { if(B == 0) { x = 1; y = 0; return A; } long long x1, y1; long long gcd = extended_gcd(B, A%B, x1, y1); y = x1 - (A/B)*y1; x = y1; //cout << "(" << A << "," << B << ") = " << x << "," << y << "\n"; return gcd; } int main() { long long A, B, C; cin >> A >> B >> C; long long X = 0, Y = 0; long long gcd_A_B = extended_gcd(A, B, X, Y); X *= (-C/gcd_A_B); Y *= (-C/gcd_A_B); if(C%gcd_A_B == 0) cout << X << " " << Y << "\n"; else cout << "-1\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Marina and Vyasa.cpp ================================================ #include using namespace std; char other(char c1, char c2) { const int NO_OF_ALPHABETS = 26; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { char current = 'a' + alpha; if(current != c1 && current != c2) { return current; } } return 'z'; } int main() { int length, differences; string S, T; cin >> length >> differences >> S >> T; int same = 0; for(int i = 0; i < length; i++) { if(S[i] == T[i]) { same++; } } int matches = length - differences; int minimum_length = same + 2*max(matches - same, 0); if(minimum_length > length) { cout << "-1\n"; return 0; } string answer = S; int a_matches = length, b_matches = same; for(int i = 0; i < length; i++) { if(S[i] != T[i]) { if(b_matches < matches) { answer[i] = T[i]; a_matches--; b_matches++; } else if(a_matches > matches) { answer[i] = other(S[i], T[i]); a_matches--; } } } for(int i = 0; i < length && (a_matches > matches || b_matches > matches); i++) { if(S[i] == T[i]) { answer[i] = other(S[i], T[i]); a_matches--; b_matches--; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Match Points.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, distance; cin >> no_of_elements >> distance; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int left_pairs = 0, right_pairs = no_of_elements/2 + 1; while(right_pairs - left_pairs > 1) { int mid = (left_pairs + right_pairs)/2; int good_pairs = 0; for(int i = 1; i <= mid; i++) { if(A[no_of_elements - mid + i] - A[i] >= distance) { good_pairs++; } } if(good_pairs == mid) { left_pairs = mid; } else { right_pairs = mid; } } int answer = left_pairs; cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Molly and Chemicals.cpp ================================================ #include #include #include using namespace std; void precompute(vector &P, long long k) { P.push_back(1); if(k == 0 || k == 1) { return; } if(k == -1) { P.push_back(-1); return; } long long oo = 1e14; while(abs(P.back()) <= oo) { //cout << P.back() << "\n"; P.push_back(P.back()*k); } } int main() { int no_of_elements, k; cin >> no_of_elements >> k; vector powers; precompute(powers, k); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map prefix_sum_frequency; long long prefix = 0; prefix_sum_frequency[prefix] = 1; long long no_of_segments = 0; for(int i = 1; i <= no_of_elements; i++) { prefix += A[i]; for(int j = 0; j < powers.size(); j++) { no_of_segments += prefix_sum_frequency[prefix - powers[j]]; } prefix_sum_frequency[prefix]++; } cout << no_of_segments << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Moodular Arithmetic.cpp ================================================ #include using namespace std; long long power_mod(long long x, long long power, long long m) { long long result = 1; while(power > 0) { if(power%2 == 1) result = (result*x)%m; x = (x*x)%m; power = power >> 1; } return result; } int order(int k, int m) { int answer = m - 1; for(int i = 1; i*i <= m - 1; i++) { if((m - 1)%i == 0) { if(power_mod(k, i, m) == 1) { answer = min(answer, i); } else if(power_mod(k, (m - 1)/i, m) == 1) { answer = min(answer, (m - 1)/i); } } } return answer; } int main() { int p, k; cin >> p >> k; const int MOD = 1e9 + 7; if(k == 0) { cout << power_mod(p, p - 1, MOD) << "\n"; return 0; } if(k == 1) { cout << power_mod(p, p, MOD) << "\n"; return 0; } cout << power_mod(p, (p - 1)/order(k, p), MOD) << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Mouse Hunt.cpp ================================================ #include #include using namespace std; vector cost, to, visits, current_dfs; vector < vector > cycle; void dfs(int v, int &total_cost) { //Cycle Starts here if(current_dfs[v]) { int cost_here = cost[v]; for(int i = to[v]; i != v; i = to[i]) { cost_here = min(cost_here, cost[i]); } total_cost += cost_here; return; } else if(visits[v]) //It was already linked to a cycle from some other dfs { return; } visits[v] = true; current_dfs[v] = true; dfs(to[v], total_cost); current_dfs[v] = false; } int main() { int no_of_vertices; cin >> no_of_vertices; cost.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> cost[i]; } to.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> to[i]; } int total_cost = 0; current_dfs.resize(no_of_vertices + 1, 0); visits.resize(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { if(!visits[i]) { dfs(i, total_cost); } } cout << total_cost << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Multiplicity.cpp ================================================ #include #include #include using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX = 1e6 + 5; vector > divisors(MAX); for(int i = 1; i < MAX; i++) { for(int multiple = i; multiple < MAX; multiple += i) { divisors[multiple].push_back(i); } } const int MOD = 1e9 + 7; vector no_of_sequences(MAX, 0), sequences_here(MAX, 0); long long total_sequences = 0; no_of_sequences[0] = 1; for(int i = 1; i <= no_of_elements; i++) { for(int d = 0; d < divisors[A[i]].size(); d++) { int m = divisors[A[i]][d]; sequences_here[m] = no_of_sequences[m - 1]; } for(int d = 0; d < divisors[A[i]].size(); d++) { int m = divisors[A[i]][d]; no_of_sequences[m] += sequences_here[m]; no_of_sequences[m] %= MOD; } } for(int i = 1; i < MAX; i++) { total_sequences += no_of_sequences[i]; total_sequences %= MOD; } cout << total_sequences << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Multipliers.cpp ================================================ #include #include using namespace std; #define PHI(x) 500000002 long long power_mod(long long x, long long power, long long mod) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%mod; x = (x*x)%mod; power = power >> 1; } return result; } long long ceil(long long n, long long x) { long long quotient = n/x; long long remainder = n%x; return (quotient + (remainder > 0)); } int main() { const int MOD = 1e9 + 7; long long product = 1LL; int no_of_primes; cin >> no_of_primes; map exponent; for(int i = 1; i <= no_of_primes; i++) { int prime_i; scanf("%d", &prime_i); exponent[prime_i]++; } long long no_of_divisors = 1; for(map :: iterator it = exponent.begin(); it != exponent.end(); it++) { int p = it->first; long long exp = it->second; long long divisor_product_here = power_mod(p, (exp*(exp + 1))/2, MOD); product = power_mod(product, exp + 1, MOD)*power_mod(divisor_product_here, no_of_divisors, MOD); product %= MOD; no_of_divisors *= (exp + 1); no_of_divisors %= (MOD - 1); } cout << product << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/My Pretty Girl Nora.cpp ================================================ #include #include using namespace std; int main() { long long t, left, right; cin >> t >> left >> right; const int MOD = 1e9 + 7; vector largest_prime_factor(right + 1, 0); vector minimum_comparisons(right + 1, 1e16); minimum_comparisons[1] = 0; for(long long i = 2; i <= right; i++) { if(largest_prime_factor[i] == 0) { largest_prime_factor[i] = i; for(long long multiple = i*i; multiple <= right; multiple += i) { if(largest_prime_factor[multiple] == 0) { largest_prime_factor[multiple] = i; } } } for(int x = i; x != 1; x /= largest_prime_factor[x]) { int remaining = i/largest_prime_factor[x]; long long comparisons_here = (i*(largest_prime_factor[x] - 1))/2 + minimum_comparisons[remaining]; minimum_comparisons[i] = min(minimum_comparisons[i], comparisons_here); } minimum_comparisons[i] %= MOD; } long long answer = 0, coefficient = 1; for(int i = left; i <= right; i++) { answer += (coefficient*minimum_comparisons[i])%MOD; coefficient = (coefficient*t)%MOD; answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Optimal Number Permutation.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(2*no_of_elements + 1); for(int front = 1, back = no_of_elements, odd = 1; odd <= no_of_elements; front++, back--, odd += 2) { A[front] = A[back] = odd; } for(int front = no_of_elements + 1, back = 2*no_of_elements - 1, even = 2; even <= no_of_elements; front++, back--, even += 2) { A[front] = A[back] = even; } for(int i = 1; i <= 2*no_of_elements; i++) { if(A[i] == 0) { A[i] = no_of_elements; } } for(int i = 1; i <= 2*no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Pair of Numbers.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 3e5 + 5, MAX_L = 20; int no_of_elements, A[MAX_N]; int gcd_table[MAX_N][MAX_L], min_table[MAX_N][MAX_L]; int gcd(int x, int y) { if(min(x, y) == 0) { return max(x, y); } return gcd(max(x, y)%min(x, y), min(x, y)); } int is_bit_set(int n, int bit) { return ( (n&(1 << bit)) != 0 ); } void precompute() { for(int i = 1; i <= no_of_elements; i++) { gcd_table[i][0] = A[i]; min_table[i][0] = A[i]; } for(int l = 1; l < MAX_L; l++) { int jump = (1 << (l - 1)); for(int i = 1; i + (1 << l) - 1 <= no_of_elements; i++) { int next = i + jump; gcd_table[i][l] = gcd(gcd_table[i][l - 1], gcd_table[next][l - 1]); min_table[i][l] = min(min_table[i][l - 1], min_table[next][l - 1]); } } } pair compute(int i, int length) { int gcd_here = A[i], min_here = A[i]; for(int bit = MAX_L; bit >= 0; bit--) { if(is_bit_set(length, bit)) { gcd_here = gcd(gcd_here, gcd_table[i][bit]); min_here = min(min_here, min_table[i][bit]); i += (1 << bit); } } return make_pair(gcd_here, min_here); } int possible(int length) { //cout << "Length = " << length << "\n"; for(int i = 1; i + length - 1 <= no_of_elements; i++) { pair answer = compute(i, length); //cout << "Computed\n"; int gcd_here = answer.first, minimum_here = answer.second; //cout << "GCD[" << i << "," << i + length - 1 << "] = " << gcd_here << "\n"; //cout << "Min[" << i << "," << i + length - 1 << "] = " << minimum_here << "\n"; if(gcd_here == minimum_here) { return true; } } return false; } int main() { cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } precompute(); int left = 1, right = no_of_elements + 1; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid)) { left = mid; } else { right = mid; } } vector answer; for(int i = 1; i + left - 1 <= no_of_elements; i++) { pair answer_here = compute(i, left); int gcd_here = answer_here.first, min_here = answer_here.second; if(gcd_here == min_here) { answer.push_back(i); } } cout << answer.size() << " " << left - 1 << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Pashmak and Graph.cpp ================================================ #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; struct Edge { int source, destination, weight; int operator <(const Edge &A) { return (weight < A.weight); } }; int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); vector edge(no_of_edges + 1); for(int i = 1; i <= no_of_edges; i++) { scanf("%d %d %d", &edge[i].source, &edge[i].destination, &edge[i].weight); } sort(all(edge)); vector maximum_ending_at(no_of_vertices + 1, 0); vector maximum_with_this_weight(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_edges; ) { int j = i; for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = 0; } //Process all edges having this weight. Have a different vector so you don't interact with equal weights. for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = max(maximum_with_this_weight[edge[j].destination], 1 + maximum_ending_at[edge[j].source]); } for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_ending_at[edge[j].destination] = max(maximum_ending_at[edge[j].destination], maximum_with_this_weight[edge[j].destination]); } i = j; } int maximum_path = 0; for(int i = 1; i <= no_of_vertices; i++) maximum_path = max(maximum_path, maximum_ending_at[i]); printf("%d\n", maximum_path); return 0; } ================================================ FILE: 2020/Practice/Programs/Pavel and Triangles.cpp ================================================ #include #include using namespace std; int main() { int no_of_sticks; cin >> no_of_sticks; vector A(no_of_sticks + 1); for(int i = 1; i <= no_of_sticks; i++) { cin >> A[i]; } long long no_of_triangles = 0; int remaining_sticks = 0; for(int highest = 1; highest <= no_of_sticks; highest++) { int triangles_here = min(remaining_sticks, A[highest]/2); no_of_triangles += triangles_here; A[highest] -= 2*triangles_here; remaining_sticks = remaining_sticks - triangles_here; no_of_triangles += A[highest]/3; A[highest] %= 3; remaining_sticks += A[highest]; } cout << no_of_triangles << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Plus and Xor.cpp ================================================ #include using namespace std; int main() { unsigned long long A, B; cin >> A >> B; //Y = X + B, A = 2X + B if(A < B || (A - B)%2 != 0) { cout << "-1\n"; return 0; } unsigned long long X = (A - B)/2, Y = A - X; //cout << X + Y << " " << (X^Y) << "\n"; if(X + Y != A || (X^Y) != B) { cout << "-1\n"; return 0; } cout << X << " " << Y << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Points.cpp ================================================ #include #include using namespace std; long long calculate(vector &P, int n) { long long squares = 0; for(int i = 1; i <= n; i++) { squares += (n - 1)*P[i]*P[i]; } long long sum = 0; for(int i = 1; i <= n; i++) { sum += P[i]; } long long linear_term = 0; for(int i = 1; i <= n; i++) { linear_term += P[i]*(sum - P[i]);// 2*P[i]*P[i]; } return (squares - linear_term); } int main() { int no_of_points; cin >> no_of_points; vector X(no_of_points + 1); vector Y(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) { cin >> X[i] >> Y[i]; } long long distance = calculate(X, no_of_points) + calculate(Y, no_of_points); cout << distance << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Prime Number.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long power_mod(long long x, long long power, long long mod) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%mod; x = (x*x)%mod; power = power/2; } return result; } int main() { int no_of_elements, x; cin >> no_of_elements >> x; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long sum = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; } set S; map frequency; for(int i = 1; i <= no_of_elements; i++) { frequency[sum - A[i]]++; S.insert(sum - A[i]); } const int MOD = 1e9 + 7; long long answer; for(auto it = S.begin(); ; it++) { while(frequency[*(S.begin())]%x == 0) { long long exponent = *(S.begin()); long long new_exponent = exponent + 1; frequency[new_exponent] += frequency[exponent]/x; S.insert(new_exponent); S.erase(exponent); } if(frequency[*( S.begin() )] != 0) { answer = min(sum, *( S.begin() )); break; } } cout << power_mod(x, answer, MOD) << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Ramesses and Corner Inversion.cpp ================================================ #include #include using namespace std; void read(vector > &A) { for(int i = 1; i < A.size(); i++) { for(int j = 1; j < A[0].size(); j++) { cin >> A[i][j]; } } } void compute(vector > &A, vector &row_sum, vector &column_sum) { for(int i = 1; i < A.size(); i++) { for(int j = 1; j < A[0].size(); j++) { row_sum[i] += A[i][j]; column_sum[j] += A[i][j]; } } } int main() { int rows, columns; cin >> rows >> columns; vector > A(rows + 1, vector (columns + 1)); read(A); vector > B(rows + 1, vector (columns + 1)); read(B); vector A_row_sum(rows + 1), A_column_sum(columns + 1); compute(A, A_row_sum, A_column_sum); vector B_row_sum(rows + 1), B_column_sum(columns + 1); compute(B, B_row_sum, B_column_sum); int row_and_column_same_parity = true; for(int i = 1; i <= rows; i++) { if(A_row_sum[i]%2 != B_row_sum[i]%2) { row_and_column_same_parity = false; } } for(int j = 1; j <= columns; j++) { if(A_column_sum[j]%2 != B_column_sum[j]%2) { row_and_column_same_parity = false; } } cout << (row_and_column_same_parity ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: 2020/Practice/Programs/Scheme.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e5 + 15; vector graph[MAX_N]; vector visited(MAX_N, false); vector incoming(MAX_N, 0); vector beginning; vector ending; void dfs(int v) { visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(visited[child]) { ending.push_back(child); return; } dfs(child); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { int destination; scanf("%d", &destination); graph[i].push_back(destination); incoming[destination]++; } for(int i = 1; i <= no_of_vertices; i++) { if(incoming[i] == 0) { beginning.push_back(i); dfs(i); } } for(int i = 1; i <= no_of_vertices; i++) { if(!visited[i]) { beginning.push_back(i); dfs(i); } } int no_of_sinks = 0; for(int i = 1; i <= no_of_vertices; i++) { if(incoming[i] == 0) { no_of_sinks++; } } int simple_cycle = (no_of_sinks == 0 && beginning.size() == 1); int new_edges = (simple_cycle ? 0 : beginning.size()); printf("%d\n", new_edges); for(int i = 0; i < new_edges; i++) { printf("%d %d \n",ending[i], beginning[(i + 1)%new_edges]); } return 0; } ================================================ FILE: 2020/Practice/Programs/Secret Passwords.cpp ================================================ #include #include using namespace std; const int NO_OF_ALPHABETS = 26; struct DSU { int parent[NO_OF_ALPHABETS]; int no_of_components = NO_OF_ALPHABETS; DSU() {} DSU(int n) { for(int i = 0; i <= n; i++) { parent[i] = i; } } int get_parent(int n) { while(n != parent[n]) { parent[n] = parent[parent[n]]; n = parent[n]; } return n; } void unite(int x, int y) { int parent_x = get_parent(x), parent_y = get_parent(y); if(parent_x == parent_y) return; parent[parent_x] = parent[parent_y]; no_of_components--; } }; int is_set(long long n, int bit) { return ((n&(1 << bit)) != 0); } int main() { int no_of_words; cin >> no_of_words; vector used(NO_OF_ALPHABETS, false); DSU dsu(NO_OF_ALPHABETS); for(int i = 1; i <= no_of_words; i++) { string word; cin >> word; int mask = 0; for(int j = 0; j < word.size(); j++) { mask |= (1 << (word[j] - 'a')); used[word[j] - 'a'] = true; } for(int bit_1 = 0; bit_1 < NO_OF_ALPHABETS; bit_1++) { for(int bit_2 = 0; bit_2 < NO_OF_ALPHABETS; bit_2++) { if(!is_set(mask, bit_1) || !is_set(mask, bit_2) || dsu.get_parent(bit_1) == dsu.get_parent(bit_2)) { continue; } dsu.unite(bit_1, bit_2); } } } int unused_alphabets = 0; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { if(!used[alpha]) { unused_alphabets++; } } int actual_components = dsu.no_of_components - unused_alphabets; cout << actual_components << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Segments.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int ENTRY = 1, EXIT = 2; struct segment { int point, type, index; segment(){} segment(int P, int T, int I) { point = P; type = T; index = I; } }; int sort_by_left(segment &S_1, segment &S_2) { if(S_1.point == S_2.point) { return (S_1.type < S_2.type); } return (S_1.point < S_2.point); } int main() { int no_of_segments; cin >> no_of_segments; vector S; for(int i = 0; i < no_of_segments; i++) { int left, right; cin >> left >> right; if(left > right) { swap(left, right); } S.push_back(segment(left, ENTRY, i)); S.push_back(segment(right, EXIT, i)); } sort(all(S), sort_by_left); vector already_handled(no_of_segments, false); vector meeting_points; stack handled_indices; for(int i = 0; i < 2*no_of_segments; i++) { if(already_handled[S[i].index]) { continue; } if(S[i].type == ENTRY) { handled_indices.push(S[i].index); } else if(S[i].type == EXIT) { meeting_points.push_back(S[i].point); while(handled_indices.size() > 0) { already_handled[handled_indices.top()] = true; handled_indices.pop(); } } } cout << meeting_points.size() << "\n"; for(int i = 0; i < meeting_points.size(); i++) { cout << meeting_points[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/Special Segments of Permutation.cpp ================================================ #include #include #include #include using namespace std; int no_of_elements; vector permutation; vector position; int get_count(int left_1, int right_1, int left_2, int right_2, int total_sum) { if(right_2 - left_2 < right_1 - left_1) { swap(right_1, right_2); swap(left_1, left_2); } int count = 0; for(int i = left_1; i <= right_1; i++) { int remaining = total_sum - permutation[i]; if(1 <= remaining && remaining <= no_of_elements && left_2 <= position[remaining] && position[remaining] <= right_2) { count++; } } return count; } int main() { cin >> no_of_elements; permutation.resize(no_of_elements + 1); position.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> permutation[i]; position[permutation[i]] = i; } vector left_border(no_of_elements + 1); stack > left_S; left_S.push(make_pair(no_of_elements + 1, 0)); for(int i = 1; i <= no_of_elements; i++) { while(left_S.top().first < permutation[i]) { left_S.pop(); } left_border[i] = left_S.top().second + 1; left_S.push(make_pair(permutation[i], i)); } stack > right_S; vector right_border(no_of_elements + 1); right_S.push(make_pair(no_of_elements + 1, no_of_elements + 1)); for(int i = no_of_elements; i >= 1; i--) { while(right_S.top().first < permutation[i]) { right_S.pop(); } right_border[i] = right_S.top().second - 1; right_S.push(make_pair(permutation[i], i)); } int no_of_special_segments = 0; for(int i = 1; i <= no_of_elements; i++) { no_of_special_segments += get_count(left_border[i], i - 1, i + 1, right_border[i], permutation[i]); } cout << no_of_special_segments << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/The Sum of the k-th Powers.cpp ================================================ #include #include using namespace std; const int MOD = 1e9 + 7; long long power_mod(long long x, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } long long inverse(long long x) { return power_mod(x, MOD - 2); } int main() { long long n, power; cin >> n >> power; //f(i) = 1^k + 2^k + ... + i^k vector value(power + 3, 0); for(int i = 1; i <= power + 2; i++) { value[i] = (value[i - 1] + power_mod(i, power))%MOD; } if(n <= power + 2) { cout << value[n] << "\n"; return 0; } long long numerator = 1, denominator = 1; long long largest = (1 - 2 + MOD)%MOD, smallest = (1 - (power + 2) + MOD)%MOD; for(int i = 2; i <= power + 2; i++) { numerator = (numerator*(n - i))%MOD; denominator = (denominator*(1 - i + MOD))%MOD; } long long answer = value[1]*numerator; answer = (answer*inverse(denominator))%MOD; for(int i = 2; i <= power + 2; i++) { numerator = (numerator*inverse(n - i))%MOD; numerator = (numerator*(n - (i - 1)))%MOD; largest = (largest + 1)%MOD; if(largest == 0) { largest = (largest + 1)%MOD; } if(smallest == 0) { smallest = (smallest + 1)%MOD; } denominator = (denominator*inverse(smallest))%MOD; denominator = (denominator*(largest))%MOD;// cout << "Remove small = " << smallest << " largest = " << largest << " D = " << denominator << "\n"; smallest = (smallest + 1)%MOD; long long current_term = (numerator*inverse(denominator))%MOD; current_term = (value[i]*current_term)%MOD; answer = (answer + current_term)%MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2020/Practice/Programs/The Treasure of Segments.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; void solve() { int no_of_segments; cin >> no_of_segments; vector sorted_left(no_of_segments + 1), sorted_right(no_of_segments + 1); vector left(no_of_segments + 1), right(no_of_segments + 1); for(int i = 1; i <= no_of_segments; i++) { cin >> left[i] >> right[i]; sorted_left[i] = left[i]; sorted_right[i] = right[i]; } sort(all(sorted_left)); sort(all(sorted_right)); int minimum_deletions = no_of_segments; for(int i = 1; i <= no_of_segments; i++) { int after_right = no_of_segments - (upper_bound(all(sorted_left), right[i]) - sorted_left.begin()) + 1; int before_left = lower_bound(all(sorted_right), left[i]) - sorted_right.begin() - 1; //cout << "For [" << left[i] << "," << right[i] << "] Before Left = " << before_left << " and after right = " << after_right << "\n"; int deletions_here = after_right + before_left; minimum_deletions = min(minimum_deletions, deletions_here); } cout << minimum_deletions << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2020/Practice/Programs/Winter is Here.cpp ================================================ #include #include using namespace std; long long power_mod(long long x, long long power, long long mod) { long long result = 1; while(power > 0) { if(power%2 == 1) result = (result*x)%mod; x = (x*x)%mod; power = power/2; } return result; } int main() { const int MAX_N = 1e6 + 5, MOD = 1e9 + 7; int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector multiple_count(MAX_N, 0); for(int i = 1; i <= no_of_elements; i++) { multiple_count[A[i]]++; } for(int m = 1; m < MAX_N; m++) { for(int multiple = 2*m; multiple < MAX_N; multiple += m) { multiple_count[m] += multiple_count[multiple]; } } vector answer(MAX_N, 0); for(int m = MAX_N - 1; m >= 1; m--) { answer[m] = multiple_count[m]*power_mod(2, multiple_count[m] - 1, MOD); answer[m] %= MOD; //cout << answer[m] << "\n"; for(int multiple = 2*m; multiple < MAX_N; multiple += m) { answer[m] = (answer[m] - answer[multiple] + MOD)%MOD; } //cout << answer[m] << "\n"; //cout << "Answer " << m << " = " << answer[m] << "\n"; } long long total_answer = 0; for(int m = 2; m < MAX_N; m++) { total_answer = (total_answer + answer[m]*m)%MOD; } cout << total_answer << "\n"; return 0; } ================================================ FILE: 2021/Combined Divisions/Deltix Round Summer 2021/Explanations/Take a Guess Explanation.txt ================================================ - The idea behind remembering this identity is that every bit that is set in both integers is counted twice and every bit that is set in only one of them is counted once. - Use this identity to find the first $3$ elements in $6$ steps and then find the remaining array elements with $2$ steps a piece. cpp #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int ask(int i, int j, string S) { int answer; cout << S << " " << i << " " << j << "\n"; cout.flush(); cin >> answer; return answer; } int main() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); int and_12 = ask(1, 2, "and"); int or_12 = ask(1, 2, "or"); int sum_12 = and_12 + or_12; int and_23 = ask(2, 3, "and"); int or_23 = ask(2, 3, "or"); int sum_23 = and_23 + or_23; int and_31 = ask(3, 1, "and"); int or_31 = ask(3, 1, "or"); int sum_31 = and_31 + or_31; A[1] = (sum_12 - sum_23 + sum_31)/2; A[2] = sum_12 - A[1]; A[3] = sum_23 - A[2]; //cout << A[1] << " " << A[2] << " " << A[3] << "\n"; for(int i = 4; i <= no_of_elements; i++) { int and_1i = ask(1, i, "and"); int or_1i = ask(1, i, "or"); int sum_1i = and_1i + or_1i; A[i] = sum_1i - A[1];//cout << A[i] << "\n"; } sort(all(A)); cout << "finish " << A[k] << "\n"; return 0; } ``` ================================================ FILE: 2021/Combined Divisions/Deltix Round Summer 2021/Programs/Take a Guess.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int ask(int i, int j, string S) { int answer; cout << S << " " << i << " " << j << "\n"; cout.flush(); cin >> answer; return answer; } int main() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); int and_12 = ask(1, 2, "and"); int or_12 = ask(1, 2, "or"); int sum_12 = and_12 + or_12; int and_23 = ask(2, 3, "and"); int or_23 = ask(2, 3, "or"); int sum_23 = and_23 + or_23; int and_31 = ask(3, 1, "and"); int or_31 = ask(3, 1, "or"); int sum_31 = and_31 + or_31; A[1] = (sum_12 - sum_23 + sum_31)/2; A[2] = sum_12 - A[1]; A[3] = sum_23 - A[2]; //cout << A[1] << " " << A[2] << " " << A[3] << "\n"; for(int i = 4; i <= no_of_elements; i++) { int and_1i = ask(1, i, "and"); int or_1i = ask(1, i, "or"); int sum_1i = and_1i + or_1i; A[i] = sum_1i - A[1];//cout << A[i] << "\n"; } sort(all(A)); cout << "finish " << A[k] << "\n"; return 0; } ================================================ FILE: 2021/Div 2/694/Explanations/Strange Definition Explanation.txt ================================================ XY must also be a perfect square ================================================ FILE: 2021/Div 2/694/Explanations/Strange Housing Explanation.txt ================================================ - We have to choose some non-adjacent vertices in the graph such that when we delete all edges that are not connected to one of these vertices, we still are connected. - Colour vertex $1$ white - Colour all the children of a white vertex black. - Black vertices lie between two white children. This is the invariant that we are maintaining. - Colour all the grand children of the white vertex as white. - It is important to colour all the grand children of white vertex as white rather than visit a black vertex and paint all of it's children white. The reason is that some black vertices might be connected to each other. So, we would end up repainting them white, which would not be correct. - If there is some vertex which is uncoloured in the end, then it means that the graph was not connected in the beginning ------ void solve() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; vector > graph(no_of_vertices + 1); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } const int UNCOLOURED = -1, BLACK = 0, WHITE = 1; vector colour(no_of_vertices + 1, UNCOLOURED); queue Q; colour[1] = WHITE; for(int child : graph[1]) { colour[child] = BLACK; Q.push(child); } while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int child : graph[v]) { if(colour[child] == UNCOLOURED) { colour[child] = WHITE; for(int grandchild : graph[child]) { colour[grandchild] = BLACK; Q.push(grandchild); } } } } vector answer; for(int i = 1; i <= no_of_vertices; i++) { if(colour[i] == WHITE) { answer.push_back(i); } if(colour[i] == UNCOLOURED) { cout << "NO\n"; return; } } cout << "YES\n"; cout << answer.size() << "\n"; for(int v : answer) { cout << v << " "; } cout << "\n"; } ================================================ FILE: 2021/Div 2/694/Explanations/Strange Shuffle Explanation.txt ================================================ # $A[p + i] + A[p - i] = 2k$ is invariant - In the beginning, $A[p + 1] = k + k/2$ and $A[p - 1] = k/2 + 0$ - $A[p + 1] + A[p - 1] = 2k$ - After the first second, everybody other than $A[p - 1], A[p], A[p + 1]$ has $k$ cards exactly. - Let us say this is true for the first $x$ seconds. In the $x + 1$ second, $A[p + x + 1]$ - Everybody to the right of the impostor has more than $k$ cards. - Suppose there are $10000$ people. - Divide into chunks of $100$ - $[1 - 100]$ - $[101 - 200]$ - $[201 - 300]$ - After $101$ operations, there will be $100$ people with more than $k$ cards. - It should have at have spilled over to at least one other chunk. - I will spend $200$ moves ($2$ rounds) only checking the first person of each chunk. --- - Suppose the impostor is in chunk $73$ at position $64$ - After $37$ moves, the infection spreads to chunk $74$ - After $1$ move, the infection is in $65$ - After $2$ moves, the infection is in $66$ - After $36$ moves, the infection is in $100$ - After $37$-th move, the infection goes to first person of chunk $74$ - When you reach the chunk $74$, you will reach in the $74$th move. So, you are in time to catch the infection. - In this scenario, $100$ moves are sufficient. --- - Suppose the impostor is in chunk $7$ at position $64$ - After $37$ moves, the infection spreads to chunk $8$ - But, you are visiting chunk $8$ at second $8$. So, you are too early to catch the infection. Our strategy is - At $1$ second we go to chunk $1$ - At $2$ second, we go to chunk $2$ --- - Use $200$ moves to find out someone who has $> k$ cards - Then use binary search to find the first person on his left who has $\le k$ cards. ================================================ FILE: 2021/Div 2/694/Programs/Strange Birthday Party.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, no_of_items; cin >> no_of_elements >> no_of_items; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector price(no_of_items + 1); for(int i = 1; i <= no_of_items; i++) { cin >> price[i]; } sort(A.begin(), A.end()); long long total = 0; for(int i = 1; i <= no_of_elements; i++) { total += price[A[i]]; } vector available(no_of_items + 1, true); for(int i = no_of_elements, first = 1; i >= 1 && first < A[i]; i--, first++) { available[first] = false; total -= (price[A[i]] - price[first]); } cout << total << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/694/Programs/Strange Definition.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 1e6 + 5; vector primes; vector value(MAX_N, 1); void sieve(int n) { vector largest_prime_factor(MAX_N, 0); for(long long i = 2; i < MAX_N; i++) { if(largest_prime_factor[i] == 0) { for(long long multiple = i; multiple < MAX_N; multiple += i) { largest_prime_factor[multiple] = i; } } } for(int i = 2; i < MAX_N; i++) { int current = i, exponent = 0; while(current%largest_prime_factor[i] == 0) { current /= largest_prime_factor[i]; exponent++; } value[i] = value[current]; if(exponent%2 == 1) { value[i] *= largest_prime_factor[i]; } } } void solve() { int no_of_elements; cin >> no_of_elements; map frequency; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; A[i] = value[A[i]]; frequency[A[i]]++; } int even_frequency = 0, max_frequency = frequency[1]; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { if(it->first == 1) { continue; } if(it->second%2 == 0) { even_frequency += it->second; } max_frequency = max(max_frequency, it->second); } int initial_answer = max_frequency; int final_answer = max(max_frequency, frequency[1] + even_frequency); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { long long time; cin >> time; int answer = (time == 0 ? initial_answer : final_answer); cout << answer << "\n"; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); sieve(MAX_N); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/694/Programs/Strange Housing.cpp ================================================ #include #include #include #include #include using namespace std; void solve() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; vector > graph(no_of_vertices + 1); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } const int UNCOLOURED = -1, BLACK = 0, WHITE = 1; vector colour(no_of_vertices + 1, UNCOLOURED); queue Q; colour[1] = WHITE; for(int child : graph[1]) { colour[child] = BLACK; Q.push(child); } while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int child : graph[v]) { if(colour[child] == UNCOLOURED) { colour[child] = WHITE; for(int grandchild : graph[child]) { colour[grandchild] = BLACK; Q.push(grandchild); } } } } vector answer; for(int i = 1; i <= no_of_vertices; i++) { if(colour[i] == WHITE) { answer.push_back(i); } if(colour[i] == UNCOLOURED) { cout << "NO\n"; return; } } cout << "YES\n"; cout << answer.size() << "\n"; for(int v : answer) { cout << v << " "; } cout << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/694/Programs/Strange List.cpp ================================================ #include #include #include using namespace std; void solve() { long long no_of_elements, x; cin >> no_of_elements >> x; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int stop = false; vector > value; for(int i = 1; i <= no_of_elements; i++) { value.push_back(make_pair(A[i], 1)); } for(int i = 0; !stop; i++) { if(value[i].first%x != 0) { stop = true; break; } value.push_back(make_pair(value[i].first/x, value[i].second*x)); } long long total = 0; for(int i = 0; i < value.size(); i++) { total += value[i].first*value[i].second; } cout << total << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/694/Programs/Strange Partition.cpp ================================================ #include #include using namespace std; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } void solve() { int no_of_elements, x; cin >> no_of_elements >> x; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_beauty(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_beauty[i] = prefix_beauty[i - 1] + ceil(A[i], x); } long long suffix_sum = A[no_of_elements]; long long min_beauty = prefix_beauty[no_of_elements], max_beauty = prefix_beauty[no_of_elements]; for(int i = no_of_elements - 1; i >= 1; i--) { suffix_sum += A[i]; min_beauty = min(min_beauty, prefix_beauty[i - 1] + ceil(suffix_sum, x)); max_beauty = max(max_beauty, prefix_beauty[i - 1] + ceil(suffix_sum, x)); } cout << min_beauty << " " << max_beauty << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/694/Programs/Strange Shuffle.cpp ================================================ #include #include #include #include #include using namespace std; int ask(int i) { int answer; cout << "? " << i << "\n"; cout.flush(); cin >> answer; return answer; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_elements, k; cin >> no_of_elements >> k; int block_size = floor(sqrt(no_of_elements)); int first_greater = 0; for(int round = 1; round <= 2 && first_greater == 0; round++) { for(int i = 1; i <= block_size && first_greater == 0; i++) { int cards = ask(i*block_size); if(cards > k) { first_greater = i*block_size; } } } //A[i - L] > K and A[i - R] <= K int left = 0, right = no_of_elements - 1; while(right - left > 1) { int mid = (left + right)/2; int check = (first_greater - 1 - mid + no_of_elements)%no_of_elements + 1; int cards = ask(check); if(cards > k) { left = mid; } else { right = mid; } } int impostor = (first_greater - 1 - right + no_of_elements)%no_of_elements + 1; cout << "! " << impostor << "\n"; return 0; } ================================================ FILE: 2021/Div 2/708/Explanations/Genius Explanation.txt ================================================ The primary insight of this problem is how to visualise the edge weights in between going from one problem to another. Suppose we go from problem i to problem j, the weight (complexity) will be a string of 1's in binary where the bits [j, i - 1] will be set. ----- Let f(i) be the maximum score if the last problem we solve is problem i For each i, we will check every possibility for the second last problem j but we have to be careful to do this in such a way that the weights are increasing. f(i) = max(f(i), f(j) + |S[i] - S[j]|) ----- We have to make sure that the last problem we have solved at problem j is of lower weight than [i-j] One of the ways to do this is to add another dimension to the DP. f(i, k) = Be the maximum score ending at problem i, if the last problem solved was problem k. So, for updating f(i, j), we will use all f(j, k) where [k-j] < [j-i] The problem with this is, which vertex do we start with ? Suppose we are first finding out f(1, _), but the best path to 1, might be 5 -> 10 -> 1 But we have not yet computed f(10, 5) So, there is a problem regarding which vertex to start with and how to update the transition correctly. ----- There is an ingenious insight to solve this issue. Instead of iterating over the vertices, we will iterate over the edges. We will visit the edges in ascending order of their weight. (Our binary interpretation of the edges already told us that they were unique.) Since we are visiting the edges in ascending order, we can freely update f(i) = max{f(i), f(j) + |S[i] - S[j]}, and rest assured that the last problem at j was of lower weight than [i-j]. However, since we are iterating over edges and not vertices, we have to be sure to update both vertices. So, when we visit edge [i-j] update f(i) = max{f(i), f(j) + |S[i] - S[j]|} and f(j) = max{f(j), f(i) + |S[i] - S[j]} ----- How to visit the edges in ascending order ? Iterate over the higher bit i from i = 0 to N - 1 Iterate over the lower bit from j = i - 1 to 0 ----- void solve() { int no_of_problems; cin >> no_of_problems; vector tag(no_of_problems + 1), score(no_of_problems + 1); for(int i = 1; i <= no_of_problems; i++) { cin >> tag[i]; } for(int i = 1; i <= no_of_problems; i++) { cin >> score[i]; } vector score_ending_at(no_of_problems + 1); for(int i = 1; i <= no_of_problems; i++) { for(int j = i - 1; j > 0; j--) { if(tag[i] == tag[j]) { continue; } long long current_i = score_ending_at[i], current_j = score_ending_at[j], score_here = abs(score[i] - score[j]); score_ending_at[i] = max(score_ending_at[i], current_j + score_here); score_ending_at[j] = max(score_ending_at[j], current_i + score_here); } } long long answer = 0; for(int i = 1; i <= no_of_problems; i++) { answer = max(answer, score_ending_at[i]); } cout << answer << "\n"; } ================================================ FILE: 2021/Div 2/708/Explanations/M Arrays Explanation.txt.txt ================================================ Reduce A[i] to (A[i] mod m) for all elements. After that, all the 0's go to 1 array. If M is even, all the M/2 also go to one array. Other wise look at each pair (i, j) such that i + j = 0 (mod m) separetly We will make an array like (i, j, i, j, i) (i) (i) (i) (i) The number of arrays if their frequencies differ by more than 1 is |F[i] - F[j]| ------ void solve() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); vector frequency(m + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]%m]++; } int arrays = (frequency[0] > 0 ? 1 : 0); for(int i = 1, j = m - 1; i <= j; i++, j--) { if(frequency[i] == 0 && frequency[j] == 0) { continue; } if(i == j || abs(frequency[i] - frequency[j]) <= 1) { arrays++; } else { arrays += abs(frequency[i] - frequency[j]); } } cout << arrays << "\n"; } ================================================ FILE: 2021/Div 2/708/Explanations/Meximization Explanation.txt.txt ================================================ 1. Print the unique elements in ascending order. This is the optimal way. The MEX is the highest at each prefix in this way 2. Print the remaining elements in any order. It does not impact the MEX ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); vector frequency(101, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; } for(int i = 0; i <= 100; i++) { if(frequency[i] > 0) { cout << i << " "; frequency[i]--; } } for(int i = 0; i <= 100; i++) { while(frequency[i] > 0) { cout << i << " "; frequency[i]--; } } cout << "\n"; } ================================================ FILE: 2021/Div 2/708/Explanations/Square Free Division Explanation.txt.txt ================================================ 1. Reduce each integer to it's square free form i.e. Keep only those primes which occur an odd number of times in the prime factorisation of n an odd number of times. Now, if PQ is a perfect square, then P = Q 2. The problem is now reduced to this - Divide the array into minimum number of segments after K changes such that each segment consists of distinct elements. 3. For each i, find out left(i, j). which is the earliest left point of a segment ending at i that has only distinct elements after j changes. 4. Use Left(i, j) to compute f(i, j) which is the minimum number of segments for the first i elements after j changes. Iterate over the number of changes on the last segments and find out the left point accordingly. ----- How to find out the best left ? We will do an O(n) scan for each k using two pointers L and R. We will maintain the invariant that the segment [L, R] has exactly k duplicates and [L, R] is the longest such segment. Left(R, k) = L And then, we will decrease R. L and R touch each element once so it is O(n) complexity. Overall complexity for this is O(nk) vector > best_left(no_of_elements + 1, vector (no_of_changes + 1)); for(int change = 0; change <= no_of_changes; change++) { int left = no_of_elements + 1, right = no_of_elements, duplicates = 0; while(right >= 1) { while(left >= 1) { if(duplicates == change && frequency[A[left - 1]] > 0) { break; } if(frequency[A[left - 1]] > 0) { duplicates++; } frequency[A[left - 1]]++; left--; } best_left[right][change] = max(left, 1); //cout << "For " << right << " best " << left << "\n"; if(frequency[A[right]] > 1) { duplicates--; } frequency[A[right]]--; right--; } } ----- Here is how we calculate the DP vector > minimum_segments(no_of_elements + 1, vector (no_of_changes + 1, oo)); for(int i = 1; i <= no_of_elements; i++) { for(int changes = 0; changes <= no_of_changes; changes++) { if(changes > 0) { minimum_segments[i][changes] = minimum_segments[i][changes - 1]; } for(int last_changes = 0; last_changes <= changes; last_changes++) { int left = best_left[i][last_changes]; if(left == 1) { minimum_segments[i][changes] = 1; continue; } minimum_segments[i][changes] = min(minimum_segments[i][changes], minimum_segments[left - 1][changes - last_changes] + 1); } } } ================================================ FILE: 2021/Div 2/708/Explanations/k-LCM Explanation.txt.txt ================================================ Pad it with (K - 3) ones and then reuse the solution for (N - (k - 3)) 1. If n is odd - 1, N/2, N/2 2. (n mod 4) = 2, - 2, (N - 2)/2, (N - 2)/2, LCM = (N - 2)/2, because (N - 2)/2 is also even 3. (n mod 4) = n/2, n/4, n/4, LCM = n/2 ----- void solve_3(int n) { switch(n%4) { case 1 : case 3 : cout << "1 " << n/2 << " " << n/2 << "\n"; return; case 2 : cout << "2 " << (n - 2)/2 << " " << (n - 2)/2 << "\n"; return; case 0 : cout << n/2 << " " << n/4 << " " << n/4 << "\n"; return; } } void solve() { int n, k; cin >> n >> k; for(int i = 1; i <= k - 3; i++) { cout << "1 "; } solve_3(n - (k - 3)); } ================================================ FILE: 2021/Div 2/708/Programs/Genius.cpp ================================================ #include #include using namespace std; void solve() { int no_of_problems; cin >> no_of_problems; vector tag(no_of_problems + 1), score(no_of_problems + 1); for(int i = 1; i <= no_of_problems; i++) { cin >> tag[i]; } for(int i = 1; i <= no_of_problems; i++) { cin >> score[i]; } vector score_ending_at(no_of_problems + 1); for(int i = 1; i <= no_of_problems; i++) { for(int j = i - 1; j > 0; j--) { if(tag[i] == tag[j]) { continue; } long long current_i = score_ending_at[i], current_j = score_ending_at[j], score_here = abs(score[i] - score[j]); score_ending_at[i] = max(score_ending_at[i], current_j + score_here); score_ending_at[j] = max(score_ending_at[j], current_i + score_here); } } long long answer = 0; for(int i = 1; i <= no_of_problems; i++) { answer = max(answer, score_ending_at[i]); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/708/Programs/M Arrays.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); vector frequency(m + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]%m]++; } int arrays = (frequency[0] > 0 ? 1 : 0); for(int i = 1, j = m - 1; i <= j; i++, j--) { if(frequency[i] == 0 && frequency[j] == 0) { continue; } if(i == j || abs(frequency[i] - frequency[j]) <= 1) { arrays++; } else { arrays += abs(frequency[i] - frequency[j]); } } cout << arrays << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/708/Programs/Meximization.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); vector frequency(101, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; } for(int i = 0; i <= 100; i++) { if(frequency[i] > 0) { cout << i << " "; frequency[i]--; } } for(int i = 0; i <= 100; i++) { while(frequency[i] > 0) { cout << i << " "; frequency[i]--; } } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/708/Programs/Square Free Division.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e7 + 5, oo = 1e9; vector primes; vector value(MAX_N, 1); vector frequency(MAX_N, 0); void sieve(int n) { vector largest_prime_factor(MAX_N, 0); for(long long i = 2; i < MAX_N; i++) { if(largest_prime_factor[i] == 0) { for(long long multiple = i; multiple < MAX_N; multiple += i) { largest_prime_factor[multiple] = i; } } } for(int i = 2; i < MAX_N; i++) { int current = i, exponent = 0; while(current%largest_prime_factor[i] == 0) { current /= largest_prime_factor[i]; exponent++; } value[i] = value[current]; if(exponent%2 == 1) { value[i] *= largest_prime_factor[i]; } } } void solve() { int no_of_elements, no_of_changes; cin >> no_of_elements >> no_of_changes; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; A[i] = value[A[i]]; frequency[A[i]] = 0; } vector > best_left(no_of_elements + 1, vector (no_of_changes + 1)); for(int change = 0; change <= no_of_changes; change++) { int left = no_of_elements + 1, right = no_of_elements, duplicates = 0; while(right >= 1) { while(left > 1) { if(duplicates == change && frequency[A[left - 1]] > 0) { break; } if(frequency[A[left - 1]] > 0) { duplicates++; } frequency[A[left - 1]]++; left--; } best_left[right][change] = left; //cout << "For " << right << " best " << left << "\n"; if(frequency[A[right]] > 1) { duplicates--; } frequency[A[right]]--; right--; } } vector > minimum_segments(no_of_elements + 1, vector (no_of_changes + 1, oo)); for(int i = 1; i <= no_of_elements; i++) { for(int changes = 0; changes <= no_of_changes; changes++) { if(changes > 0) { minimum_segments[i][changes] = minimum_segments[i][changes - 1]; } for(int last_changes = 0; last_changes <= changes; last_changes++) { int left = best_left[i][last_changes]; if(left == 1) { minimum_segments[i][changes] = 1; continue; } minimum_segments[i][changes] = min(minimum_segments[i][changes], minimum_segments[left - 1][changes - last_changes] + 1); } } } cout << minimum_segments[no_of_elements][no_of_changes] << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); sieve(MAX_N); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) { solve(); } return 0; } ================================================ FILE: 2021/Div 2/708/Programs/k-LCM.cpp ================================================ #include using namespace std; void solve_3(int n) { switch(n%4) { case 1 : case 3 : cout << "1 " << n/2 << " " << n/2 << "\n"; return; case 2 : cout << "2 " << (n - 2)/2 << " " << (n - 2)/2 << "\n"; return; case 0 : cout << n/2 << " " << n/4 << " " << n/4 << "\n"; return; } } void solve() { int n, k; cin >> n >> k; for(int i = 1; i <= k - 3; i++) { cout << "1 "; } solve_3(n - (k - 3)); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Explanations/Bananas in a MIrcorwave Explanation.txt.txt ================================================ # Visit each banana at most twice - Suppose we had to do it naively. How would we do it $?$ - For each time step, visit all the bananas that we have gotten previously and then perform the current operation $Y$ times and mark their states as visited. - We just need one observation. - Suppose we start at $b_1$ and are performing addition. - We only need to keep going as long as the integers generated weren't reachable. - $b_1 + x, b_1 + 2x, b_1 + 3x, \dots , b_1 + kx$ - Suppose some $b_k = b_1 + kx$ is already visited. - We will stop here and break. - The reason is that if when we pick $b_k$ and start performing this same operation $Y$ times, we will get all the same states and more. - If we continue applying on $b_1$, we will get $b_1 + (k + 1)x, b_1 + (k + 2)x, \dots , b_1 + Yx$ - If we start from $b_k$, we will get $b_k + x, b_k + 2x, \dots , b_k + Yx$ - The elements visited after $b_k$ from $b_1$ will be a subset (prefix) of the elements visited starting from $b_k$. So, instead of continuing from $b_1$, we will stop and start afresh from $b_k$ --- - Each element is visited at most twice. If we start applying operations from $x$, we would only have visited from the most recent integer in $[x - Y, X]$ that was already visited. - So, $x$ is only visited twice. - This is similar to a two pointer idea and. ----- long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } long long operate(int type, long long b, long long x) { switch(type) { case ADD : return ceil(b*MOD + x, MOD); case MULTIPLY : return ceil(b*x, MOD); } } int main() { int no_of_timesteps, target_bananas; cin >> no_of_timesteps >> target_bananas; vector can_get(target_bananas + 1, -1), previous_get(target_bananas + 1, false); can_get[0] = 0; for(int i = 1; i <= no_of_timesteps; i++) { int type; long long x, repetition; cin >> type >> x >> repetition; previous_get = can_get; for(int b = 0; b <= target_bananas; b++) { //cout << "From " << b << "\n"; if(previous_get[b] != -1) { for(long long t = 1, next = b; t <= repetition; t++) { next = operate(type, next, x); //cout << "Getting " << next << "\n"; if(next > target_bananas || previous_get[next] != -1) { break; } can_get[next] = i; //cout << "Can get " << next << " = " << can_get[next] << "\n"; } } } } for(int i = 1; i <= target_bananas; i++) { cout << can_get[i] << " "; } return 0; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Explanations/Box Fitting Explanation.txt ================================================ Maintain a multiset of all the rectangles. Try to fill each layer greedily by choosing the largest size that fits. If a layer is full or the smallest layer does not fit in the rectangle, move to the next layer. ----- void solve() { int no_of_elements, W; cin >> no_of_elements >> W; multiset M; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; M.insert(A[i]); } int no_of_levels = 0, base = W, remaining_base = W; while(M.size() > 0) { no_of_levels++; remaining_base = base; while(remaining_base > 0 && M.size() > 0) { auto it = M.lower_bound(remaining_base); if(it != M.begin()) { it--; } int x = *it; //cout << "Remaining = " << remaining_base << " x = " << x << "\n"; if(x > remaining_base) { break; } else { remaining_base -= x; M.erase(it); } } } cout << no_of_levels << "\n"; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Explanations/GCD Sum Explanation.txt.txt ================================================ Keep checking consecutive integers till we get an integer that meets the condition. ----- void solve() { long long n; cin >> n; long long answer = n; while(__gcd(answer, sum_of_digits(answer)) == 1) answer++; cout << answer << "\n"; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Explanations/Two Houses Explanation.txt.txt ================================================ # $K_a > K_b \implies b \to a$ so only check $a \to b$ ## Unique Topological Sort on the Strongly Connected Graph - This graph has the property that there is an edge between every pair of vertices. - Let us compress all strongly connected components into a single vertex and look at this graph. - Just like the original graph, this graph will also have every pair connected. - Since every pair has a directed graph, for every pair there $(u, v)$, we know which vertex should come first in the topological sort. The topological sort is unique. --- ## The indegree of a vertex is also sorted in ascending order in the topological sort - Let us consider two adjacent nodes in the topological sort of the SCC graph - $L, R$ - Let $u$ be in $L$ and $v$ be in $R$ - Every pair is connected and the topological sort is unique and these are adjacent nodes so the indegree contribution from the other nodes to $L$ and $R$ will be equal. - So, let us delete all other nodes from the graph and only look at $L$ and $R$ - $L$ is a $SCC$ so each vertex will have indegree at most $|L| - 1$ - There can be no incoming edge from any vertex in $R$ - Each vertex in $R$ will have indegree $\ge |L|$ - It has to have incoming edges from every vertex in $L$ --- ## Reachability - If $K_a < K_b$, either $a$ and $b$ are is the same SCC or $b$ is in a SCC to the left of $a$ in the topological sort enumeration - Either way $a \to b$ --- - Sort all the pairs by $(K_a - K_b)$ - Process the pairs in descending order of this value - For every pair, we are guaranteed that the higher order is reachable from the lower order so only query the other pair. ----- ```cpp int main() { int no_of_vertices; cin >> no_of_vertices; vector indegree(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> indegree[i]; } vector < pair > > edges; for(int i = 1; i <= no_of_vertices; i++) { for(int j = i + 1; j <= no_of_vertices; j++) { int weight = abs(indegree[i] - indegree[j]); pair E = make_pair(i, j); edges.push_back(make_pair(weight, E)); } } sort(edges.begin(), edges.end()); reverse(edges.begin(), edges.end()); int answer_u = 0, answer_v = 0; for(int i = 0; i < edges.size(); i++) { int u = edges[i].second.first, v = edges[i].second.second; if(indegree[u] > indegree[v]) { swap(u, v); } cout << "? " << v << " " << u << "\n"; cout.flush(); string reply; cin >> reply; if(reply[0] == 'Y') { answer_u = u; answer_v = v; break; } } cout << "! " << answer_u << " " << answer_v << "\n"; return 0; } ``` ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Programs/Bananas in a Microwave.cpp ================================================ #include #include using namespace std; const int MOD = 1e5, ADD = 1, MULTIPLY = 2; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } long long operate(int type, long long b, long long x) { switch(type) { case ADD : return ceil(b*MOD + x, MOD); case MULTIPLY : return ceil(b*x, MOD); } } int main() { int no_of_timesteps, target_bananas; cin >> no_of_timesteps >> target_bananas; vector can_get(target_bananas + 1, -1), previous_get(target_bananas + 1, false); can_get[0] = 0; for(int i = 1; i <= no_of_timesteps; i++) { int type; long long x, time; cin >> type >> x >> time; previous_get = can_get; for(int b = 0; b <= target_bananas; b++) { //cout << "From " << b << "\n"; if(previous_get[b] != -1) { for(long long t = 1, next = b; t <= time; t++) { next = operate(type, next, x); //cout << "Getting " << next << "\n"; if(next > target_bananas || previous_get[next] != -1) { break; } can_get[next] = i; //cout << "Can get " << next << " = " << can_get[next] << "\n"; } } } } for(int i = 1; i <= target_bananas; i++) { cout << can_get[i] << " "; } return 0; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Programs/Box Fitting.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements, W; cin >> no_of_elements >> W; multiset M; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; M.insert(A[i]); } int no_of_levels = 0, base = W, remaining_base = W; while(M.size() > 0) { no_of_levels++; remaining_base = base; while(remaining_base > 0 && M.size() > 0) { auto it = M.lower_bound(remaining_base); if(it != M.begin()) { it--; } int x = *it; //cout << "Remaining = " << remaining_base << " x = " << x << "\n"; if(x > remaining_base) { break; } else { remaining_base -= x; M.erase(it); } } } cout << no_of_levels << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Programs/GCD Sum.cpp ================================================ #include #include using namespace std; long long sum_of_digits(long long n) { long long sum = 0; while(n) { sum += n%10; n /= 10; } return sum; } void solve() { long long n; cin >> n; long long answer = n; while(__gcd(answer, sum_of_digits(answer)) == 1) answer++; cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/711 CodeCraft 2021/Programs/Two Houses.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_vertices; cin >> no_of_vertices; vector indegree(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> indegree[i]; } vector < pair > > edges; for(int i = 1; i <= no_of_vertices; i++) { for(int j = i + 1; j <= no_of_vertices; j++) { int weight = abs(indegree[i] - indegree[j]); pair E = make_pair(i, j); edges.push_back(make_pair(weight, E)); } } sort(edges.begin(), edges.end()); reverse(edges.begin(), edges.end()); int answer_u = 0, answer_v = 0; for(int i = 0; i < edges.size(); i++) { int u = edges[i].second.first, v = edges[i].second.second; if(indegree[u] > indegree[v]) { swap(u, v); } cout << "? " << v << " " << u << "\n"; cout.flush(); string reply; cin >> reply; if(reply[0] == 'Y') { answer_u = u; answer_v = v; break; } } cout << "! " << answer_u << " " << answer_v << "\n"; return 0; } ================================================ FILE: 2021/Div 2/712 Div 2/Explanations/3 Colouring Explanation.txt ================================================ Let us divide the chessboard into even and odd squares. (Imagine a normal chessboard). Even and odd squares never touch each other. We will colour the even squares black and the odd squares white, as far as possible. We will use the colour red only if squares of any one parity are completely over. ----- 1. We will try to colour an even cell black or an odd cell white in a given move. 2. If we cannot do either of these moves, it means either the even or odd cells are completely coloured. So, we will colour cells of the available parity with Red. ----- #include #include using namespace std; void display(vector > &grid) { for(int i = 1; i < grid.size(); i++) { for(int j = 1; j < grid.size(); j++) { cout << grid[i][j]; } cout << "\n"; } } pair colour(vector > &grid, int n, int parity, int col) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if( (i + j)%2 == parity && grid[i][j] == 0) { grid[i][j] = col; return make_pair(i, j); } } } return make_pair(0, 0); } int main() { int n; cin >> n; const int BLACK = 1, WHITE = 2, RED = 3; int available_even =(n*n)/2 + ((n*n)%2 == 1 ? 1 : 0), available_odd = (n*n)/2; vector > grid(n + 1, vector (n + 1, 0)); for(int i = 1; i <= n*n; i++) { int alice_colour; cin >> alice_colour; int bob_colour; int parity = (i%2); pair P; switch(alice_colour) { case BLACK : if(available_odd > 0) { bob_colour = WHITE; P = colour(grid, n, 1, WHITE); available_odd--; } else { bob_colour = RED; P = colour(grid, n, 0, RED); available_even--; } break; case WHITE : if(available_even > 0) { bob_colour = BLACK; P = colour(grid, n, 0, BLACK); available_even--; } else { bob_colour = RED; P = colour(grid, n, 1, RED); available_odd--; } break; case RED : if(available_even > 0) { bob_colour = BLACK; P = colour(grid, n, 0, BLACK); available_even--; } else { bob_colour = WHITE; P = colour(grid, n, 1, WHITE); available_odd--; } } cout << bob_colour << " " << P.first << " " << P.second << "\n"; cout.flush(); //display(grid); } return 0; } ================================================ FILE: 2021/Div 2/712 Div 2/Explanations/Deja Vu Explanation.txt.txt ================================================ Insert an A at the first point where S[n - i - 1] is not A ----- void solve() { string S; cin >> S; int all_A = true; for(int i = 0; i < S.size(); i++) { if(S[i] != 'a') { all_A = false; break; } } if(all_A) { cout << "NO\n"; return; } cout << "YES\n"; int remaining = 0; for(int i = 0, j = S.size() - 1; i < S.size(); i++, j--) { if(S[j] != 'a') { remaining = i; cout << "a"; break; } else { cout << S[i]; } } for(int i = remaining; i < S.size(); i++) { cout << S[i]; } cout << "\n"; } ================================================ FILE: 2021/Div 2/712 Div 2/Explanations/Flip the Bits Explanation.txt.txt ================================================ Keep track of the prefix sum of A There are only certain points in A where we can flip the prefix. Go from the suffix to 1 and keep visiting smaller prefixes. Flip a prefix if (A[i] != B[i]) Keep a variable 'flip' to simulate the flip. If we flip a segment twice, it is the same as not flipping it. So, if (A[i] = B[i]), make flip = false ----- char other(char ch) { return (ch == '1' ? '0' : '1'); } void solve() { int length; cin >> length; string A, B; cin >> A >> B; vector ones(A.size(), 0); for(int i = 0; i < A.size(); i++) { if(i == 0) { ones[i] = (A[i] == '1'); } else { ones[i] = ( (A[i] == '1') + ones[i - 1]); } } int flip = false; for(int i = A.size() - 1; i >= 0; i--) { //cout << "At " << i << "\n"; if(2*ones[i] == i + 1) { //cout << "Equal "; if(flip) { if(A[i] == B[i]) { flip = false; } else { A[i] = other(A[i]); flip = true; } } else { if(A[i] != B[i]) { A[i] = other(A[i]); flip = true; } } } else { if(flip) { A[i] = other(A[i]); } } // cout << "Flip = " << flip << " A = " << A[i] << "\n"; } int same = true; for(int i = 0; i < A.size(); i++) { if(A[i] != B[i]) { same = false; break; } } cout << (same ? "YES" : "NO") << "\n"; } ================================================ FILE: 2021/Div 2/712 Div 2/Programs/3 Colouring.cpp ================================================ #include #include using namespace std; void display(vector > &grid) { for(int i = 1; i < grid.size(); i++) { for(int j = 1; j < grid.size(); j++) { cout << grid[i][j]; } cout << "\n"; } } pair colour(vector > &grid, int n, int parity, int col) { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if( (i + j)%2 == parity && grid[i][j] == 0) { grid[i][j] = col; return make_pair(i, j); } } } return make_pair(0, 0); } int main() { int n; cin >> n; const int BLACK = 1, WHITE = 2, RED = 3; int available_even =(n*n)/2 + ((n*n)%2 == 1 ? 1 : 0), available_odd = (n*n)/2; vector > grid(n + 1, vector (n + 1, 0)); for(int i = 1; i <= n*n; i++) { int alice_colour; cin >> alice_colour; int bob_colour; int parity = (i%2); pair P; switch(alice_colour) { case BLACK : if(available_odd > 0) { bob_colour = WHITE; P = colour(grid, n, 1, WHITE); available_odd--; } else { bob_colour = RED; P = colour(grid, n, 0, RED); available_even--; } break; case WHITE : if(available_even > 0) { bob_colour = BLACK; P = colour(grid, n, 0, BLACK); available_even--; } else { bob_colour = RED; P = colour(grid, n, 1, RED); available_odd--; } break; case RED : if(available_even > 0) { bob_colour = BLACK; P = colour(grid, n, 0, BLACK); available_even--; } else { bob_colour = WHITE; P = colour(grid, n, 1, WHITE); available_odd--; } } cout << bob_colour << " " << P.first << " " << P.second << "\n"; cout.flush(); //display(grid); } return 0; } ================================================ FILE: 2021/Div 2/712 Div 2/Programs/Déjà Vu.cpp ================================================ #include #include #include using namespace std; void solve() { string S; cin >> S; int all_A = true; for(int i = 0; i < S.size(); i++) { if(S[i] != 'a') { all_A = false; break; } } if(all_A) { cout << "NO\n"; return; } cout << "YES\n"; int remaining = 0; for(int i = 0, j = S.size() - 1; i < S.size(); i++, j--) { if(S[j] != 'a') { remaining = i; cout << "a"; break; } else { cout << S[i]; } } for(int i = remaining; i < S.size(); i++) { cout << S[i]; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/712 Div 2/Programs/Flip the Bits.cpp ================================================ #include #include #include using namespace std; char other(char ch) { return (ch == '1' ? '0' : '1'); } void solve() { int length; cin >> length; string A, B; cin >> A >> B; vector ones(A.size(), 0); for(int i = 0; i < A.size(); i++) { if(i == 0) { ones[i] = (A[i] == '1'); } else { ones[i] = ( (A[i] == '1') + ones[i - 1]); } } int flip = false; for(int i = A.size() - 1; i >= 0; i--) { //cout << "At " << i << "\n"; if(2*ones[i] == i + 1) { //cout << "Equal "; if(flip) { if(A[i] == B[i]) { flip = false; } else { A[i] = other(A[i]); flip = true; } } else { if(A[i] != B[i]) { A[i] = other(A[i]); flip = true; } } } else { if(flip) { A[i] = other(A[i]); } } // cout << "Flip = " << flip << " A = " << A[i] << "\n"; } int same = true; for(int i = 0; i < A.size(); i++) { if(A[i] != B[i]) { same = false; break; } } cout << (same ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/AND Sequences Explanation.txt.txt ================================================ A[1] = AND(A[2], A[3], ... , A[n]) Since AND(x, x) = x AND(A[1], AND(A[2], A[3], ... , A[n]) ) = AND(A[1], ... , A[n]) = A[1] Similarly, AND(A[1], ... , A[n - 1]) = A[n] So, the AND of the whole array is A[1] = A[n] ------ We will place the array AND at A[1] and at A[n] Since the AND of the whole array is x, AND(x, any subset of A) = x So, as long as A[1] = A[n] = x, the AND of every prefix and every suffix is equal If there is any other element at A[1], then A[1] =/= AND(A[2], ... , A[n]) ----- 1. Find out the frequency of every element. 2. Count the number of ways to place the array AND at the two ends 3. The remaining (n - 2) elements can be permuted in (n - 2)! ways ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long array_and = (1LL << 60) - 1; map frequency; for(int i = 1; i <= no_of_elements; i++) { array_and &= A[i]; frequency[A[i]]++; } const int MOD = 1e9 + 7; long long answer = choose_2(frequency[array_and], MOD)*factorial(no_of_elements - 2, MOD); answer %= MOD; cout << answer << "\n"; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/Add One Explanation.txt.txt ================================================ Let f(i) be the length of 10 after i moves. How to build the recurrence for f(i) ? In 10 moves, every digit becomes a 2 digit number except the 9, which becomes a 3 digit number (109) 9 -> 10 -> 21 32 43 54 65 76 87 98 109 f(i) = 2f(i - 10) + Number of 9's f(i) = f(i - 10) + f(i - 10) + Number of 9's f(i) = f(i - 10) + f(i - 9) After one move from (i - 10), all the digits remain single digits except 9 which becomes 2 digits f(i - 9) = f(i - 10) + Number of 9's ----- In order to find the length of d after i moves, we will first calculate the number of mvoes to make it = 10 and then use f(i - (10 - d)) ----- void precompute() { for(int i = 0; i <= 8; i++) { length[i] = 2; } length[9] = 3; for(int i = 10; i < MAX_N; i++) { length[i] = (length[i - 9] + length[i - 10])%MOD; } } void solve() { int n, no_of_operations; cin >> n >> no_of_operations; long long answer = 0; while(n > 0) { int digit = n%10; long long this_length = (no_of_operations < 10 - digit ? 1 : length[no_of_operations - (10 - digit)]); //cout << "D = " << digit << " this = " << this_length << "\n"; n /= 10; answer = (answer + this_length)%MOD; } cout << answer << "\n"; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/Arrays and Peaks Explanation.txt.txt ================================================ We will put all the peaks in the even positions. If the number of peaks is more than N/2, it is not possible since the first and last elements cannot be peaks. If it is <= N/2, we can just use the even positions ----- void solve() { int no_of_elements, no_of_peaks; cin >> no_of_elements >> no_of_peaks; if(no_of_peaks > no_of_elements/2 - (no_of_elements%2 == 0)) { cout << "-1\n"; return; } vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { A[i] = i; } for(int i = 2, peaks = 0; peaks < no_of_peaks && i < no_of_elements; i += 2, peaks++) { swap(A[i], A[i + 1]); } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/Cost Equilibrium Explanation.txt.txt ================================================ # The sinks must occur before or after the sources - The final value $S/n$ is uniquely determined. - Elements greater than the final value have to be the source and those smaller have to be the sink - The final value, source and sink are determined uniquely. ## How much does each element contribute to the sum $?$ - Suppose $A(i)$ is a source and there are $L$ sinks it contributed to that occur before it and $R$ sinks that occur after it. - It will contribute $Li - Ri = (L - R)i$ - The contribution of each sink or source can be appropriately varied by changing the values it shares with the sinks on the left and right. - However, if all the sinks are on the left, it will contribute $Li$ exactly and no more or less. - If all the sinks are on the right, it will contribute $-Ri$ exactly and no more or less - If all the sinks occur after all the sources or vice versa, the cost is uniquely determined. --- ## How to count the permutations $?$ - We can count the number of ways to permute the sinks and sources among themselves using multinomial coefficients. (Since duplicates are allowed). - The $E$ elements which are already equal to the final value can be placed $N - E + 1$ gaps - This is given by stars and bars as it is the number of ways to distribute $E$ stars using $N$ bars. $(N + 1$ gaps $)$ $$\binom{N - E}{E}$$ - The sinks and sources can be permuted as groups in $2!$ ways so multiply the answer by $2$ --- ## The Exceptions - If there are $0$ sinks or $0$ sources, any permutation of the array is acceptable. So, count all of them using the multinomial coefficient - If there is exactly $1$ sink or exactly $1$ source, the contribution to the sum will always be the same regardless of how the sinks (or sources) are distributed to it's left or right. - $1$ sink or $1$ source is a special case because the cost is uniquely determined. - We need to count all permutations in this case too. ----- int main() { precompute(); int no_of_elements; cin >> no_of_elements; map frequency; long long sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; sum += A[i]; frequency[A[i]]++; } if(sum%no_of_elements != 0) { cout << "0\n"; return 0; } int final_value = (sum/no_of_elements); vector F, source_frequency, sink_frequency; for(auto it = frequency.begin(); it != frequency.end(); it++) { if(it->first > final_value) { source_frequency.push_back(it->second); } else if(it->first < final_value) { sink_frequency.push_back(it->second); } F.push_back(it->second); } long long answer; if(source_frequency.size() == 0 || sink_frequency.size() == 0 || (source_frequency.size() == 1 && source_frequency[0] == 1) || (sink_frequency.size() == 1 && sink_frequency[0] == 1) ) { answer = multinomial(F); cout << answer << "\n"; return 0; } long long sources = multinomial(source_frequency), sink = multinomial(sink_frequency); long long equal_values = frequency[final_value], spaces = no_of_elements - equal_values + 1; long long remaining = stars_and_bars(equal_values, spaces - 1); answer = (sources*sink)%MOD; answer = (answer*remaining)%MOD; answer = (answer*2)%MOD;; cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/GCD and MST Explanation.txt ================================================ Let us visit the vertices in ascending order and check how many edges has this as the weight. If A[i] >= P, then we will stop because we no longer need to check anything and can just add the P-edges Now, which vertices will have A[i] as the weight ? Check the nearest j to the i as long as A[i, j] or A[j, i] are >= A[i] and divisible by A[i] We will add another condition. Maintain a vector is_connected, which is true if A[i] is connected to the vertex A[i + 1], either directly or indirectly. When we are going left, we will stop at the first vertex j where is_connected[i] is true Since A[i] has been connected to A[j - 1] already, placing another edge between A[i], A[j] will create a cycle. Moreover, we are visiting the weights in ascending order so A[j] has been connected to A[j - 1] with less expensive edges. When we are going right, we will stop at the first vertex j where is_connected[j - 1] is true because this means that A[j], A[j - 1] are already connected and A[j] was connected to the tree using lighter edges ----- void solve() { int no_of_elements, p; cin >> no_of_elements >> p; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_connected_right(no_of_elements + 1, false); vector < pair > values; for(int i = 1; i <= no_of_elements; i++) { values.push_back(make_pair(A[i], i)); } sort(values.begin(), values.end()); long long weight = 0; for(int i = 0; i < values.size(); i++) { int gcd = values[i].first, index = values[i].second; if(gcd >= p) { break; } for(int j = index - 1; j >= 1; j--) { if(A[j] < gcd || A[j]%gcd != 0 || is_connected_right[j]) { break; } is_connected_right[j] = true; weight += gcd; } for(int j = index + 1; j <= no_of_elements; j++) { if(A[j] < gcd || A[j]%gcd != 0 || is_connected_right[j - 1]) { break; } is_connected_right[j - 1] = true; weight += gcd; } } for(int i = 1; i <= no_of_elements - 1; i++) { if(!is_connected_right[i]) { weight += p; } } cout << weight << "\n"; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/GCD and MST Explanation.txt.txt ================================================ Let us visit the vertices in ascending order and check how many edges has this as the weight. If A[i] >= P, then we will stop because we no longer need to check anything and can just add the P-edges Now, which vertices will have A[i] as the weight ? Check the nearest j to the i as long as A[i, j] or A[j, i] are >= A[i] and divisible by A[i] We will add another condition. Maintain a vector is_connected, which is true if A[i] is connected to the vertex A[i + 1], either directly or indirectly. When we are going left, we will stop at the first vertex j where is_connected[i] is true Since A[i] has been connected to A[j - 1] already, placing another edge between A[i], A[j] will create a cycle. Moreover, we are visiting the weights in ascending order so A[j] has been connected to A[j - 1] with less expensive edges. When we are going right, we will stop at the first vertex j where is_connected[j - 1] is true because this means that A[j], A[j - 1] are already connected and A[j] was connected to the tree using lighter edges ----- void solve() { int no_of_elements, p; cin >> no_of_elements >> p; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_connected_right(no_of_elements + 1, false); vector < pair > values; for(int i = 1; i <= no_of_elements; i++) { values.push_back(make_pair(A[i], i)); } sort(values.begin(), values.end()); long long weight = 0; for(int i = 0; i < values.size(); i++) { int gcd = values[i].first, index = values[i].second; if(gcd >= p) { break; } for(int j = index - 1; j >= 1; j--) { if(A[j] < gcd || A[j]%gcd != 0 || is_connected_right[j]) { break; } is_connected_right[j] = true; weight += gcd; } for(int j = index + 1; j <= no_of_elements; j++) { if(A[j] < gcd || A[j]%gcd != 0 || is_connected_right[j - 1]) { break; } is_connected_right[j - 1] = true; weight += gcd; } } for(int i = 1; i <= no_of_elements - 1; i++) { if(!is_connected_right[i]) { weight += p; } } cout << weight << "\n"; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Explanations/Swapping Problem Explanation.txt.txt ================================================ Let us interpret the problem geometrically. We have some segments [L, R] and must do some swaps to minimize the sum of segments. It is best to swap some segments which intersect. If we swap segments which don't intersect, we will only increase the sum. Let us consider two intersecting segments [L1, R1], [L2, R2] L1 < L2 < R1 < R2 Here, if we swap (R1, R2), we will not be reducing the sum of segments. The overlap between the two segments will remain [L2, R1] If we have to reduce the sum of segments, we must swap a left with a right We have to swap (L2, R2) The situation is similar if one segment contains the other L1 < L2 < R2 < R1 It is always better to swap a left point with a right point rather than 2 lefts or 2 rights ----- So, we will look at all the segments given to us. If (A[i] < B[i]), we can swap the right If (A[i] > B[i]), we can swap the left We must always swap a left segment with a right segment. Instead of minimizing the sum, let us try to look for a pair of segments 1. One is Left and the other is right 2. Maximum overlap ------ In both our sets L and R, we will keep track of the prefix maximum end point of each segment. Then, we will iterate over each segment. Suppose our current segment is in R, we will look for the first segment in L such that The starting point is <= A[i] The ending point is the prefix maximum. The overlap is min(R[i], prefix Maximum Left) We will choose the segment which maximises the overlap. We can use binary search in a map for this. ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1), B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } map X, Y; for(int i = 1; i <= no_of_elements; i++) { if(A[i] <= B[i]) { X[A[i]] = max(X[A[i]], B[i]); } else { Y[B[i]] = max(Y[B[i]], A[i]); } } update_prefix_max(X); update_prefix_max(Y); long long overlap = 0; for(int i = 1; i <= no_of_elements; i++) { long long overlap_here = 0; if(A[i] <= B[i]) { auto it = Y.upper_bound(A[i]); if(it != Y.begin()) { it--; int left = A[i], right = min(it->second, B[i]); overlap_here = right - left; } } else { auto it = X.upper_bound(B[i]); if(it != X.begin()) { it--; int left = B[i], right = min(it->second, A[i]); overlap_here = right - left; } } overlap = max(overlap, overlap_here); } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer += abs(A[i] - B[i]); } answer -= 2*overlap; cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Programs/AND Sequences.cpp ================================================ #include #include #include using namespace std; long long factorial(long long n, long long mod) { long long answer = 1; for(int i = 1; i <= n; i++) { answer = (answer*i)%mod; } return answer; } long long choose_2(long long n, long long mod) { long long answer = n*(n - 1); return (answer%mod); } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long array_and = (1LL << 60) - 1; map frequency; for(int i = 1; i <= no_of_elements; i++) { array_and &= A[i]; frequency[A[i]]++; } const int MOD = 1e9 + 7; long long answer = choose_2(frequency[array_and], MOD)*factorial(no_of_elements - 2, MOD); answer %= MOD; cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Programs/Add One.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 2e5 + 5, MOD = 1e9 + 7; int length[MAX_N]; void precompute() { for(int i = 0; i <= 8; i++) { length[i] = 2; } length[9] = 3; for(int i = 10; i < MAX_N; i++) { length[i] = (length[i - 9] + length[i - 10])%MOD; } } void solve() { int n, no_of_operations; cin >> n >> no_of_operations; long long answer = 0; while(n > 0) { int digit = n%10; long long this_length = (no_of_operations < 10 - digit ? 1 : length[no_of_operations - (10 - digit)]); //cout << "D = " << digit << " this = " << this_length << "\n"; n /= 10; answer = (answer + this_length)%MOD; } cout << answer << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); precompute(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Programs/Arrays and Peaks.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, no_of_peaks; cin >> no_of_elements >> no_of_peaks; if(no_of_peaks > no_of_elements/2 - (no_of_elements%2 == 0)) { cout << "-1\n"; return; } vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { A[i] = i; } for(int i = 2, peaks = 0; peaks < no_of_peaks && i < no_of_elements; i += 2, peaks++) { swap(A[i], A[i + 1]); } for(int i = 1; i <= no_of_elements; i++) { cout << A[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Programs/Cost Equilibrium.cpp ================================================ #include #include #include using namespace std; const int MOD = 1e9 + 7, MAX_N = 1e5 + 5; vector factorial(MAX_N, 0), inverse_factorial(MAX_N, 0); long long power_mod(long long x, long long power, long long mod) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%mod; x = (x*x)%mod; power = power >> 1; } return result; } void precompute() { factorial[0] = 1; for(int i = 1; i < MAX_N; i++) { factorial[i] = (i*factorial[i - 1])%MOD; } //i*(i - 1)! = i! inverse_factorial[MAX_N - 1] = power_mod(factorial[MAX_N - 1], MOD - 2, MOD); for(int i = MAX_N - 2; i >= 0; i--) { inverse_factorial[i] = (i + 1)*inverse_factorial[i + 1]; inverse_factorial[i] %= MOD; } } long long multinomial(vector &frequency) { long long total = 0; long long numerator = 0, inverse_denominator = 1; for(int i = 0; i < frequency.size(); i++) { total += frequency[i]; inverse_denominator *= inverse_factorial[frequency[i]]; inverse_denominator %= MOD; } numerator = factorial[total]; long long answer = (numerator*inverse_denominator)%MOD; return answer; } long long stars_and_bars(long long stars, long long bars) { long long numerator = factorial[stars + bars - 1]; long long inverse_denominator = (inverse_factorial[stars]*inverse_factorial[bars - 1])%MOD; return (numerator*inverse_denominator)%MOD; } int main() { precompute(); int no_of_elements; cin >> no_of_elements; map frequency; long long sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; sum += A[i]; frequency[A[i]]++; } if(sum%no_of_elements != 0) { cout << "0\n"; return 0; } int final_value = (sum/no_of_elements); vector F, source_frequency, sink_frequency; for(auto it = frequency.begin(); it != frequency.end(); it++) { if(it->first > final_value) { source_frequency.push_back(it->second); } else if(it->first < final_value) { sink_frequency.push_back(it->second); } F.push_back(it->second); } long long answer; if(source_frequency.size() == 0 || sink_frequency.size() == 0 || (source_frequency.size() == 1 && source_frequency[0] == 1) || (sink_frequency.size() == 1 && sink_frequency[0] == 1) ) { answer = multinomial(F); cout << answer << "\n"; return 0; } long long sources = multinomial(source_frequency), sink = multinomial(sink_frequency); long long equal_values = frequency[final_value], spaces = no_of_elements - equal_values + 1; long long remaining = stars_and_bars(equal_values, spaces); answer = (sources*sink)%MOD; answer = (answer*remaining)%MOD; answer = (answer*2)%MOD;; cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Programs/GCD and MST.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, p; cin >> no_of_elements >> p; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector is_connected_right(no_of_elements + 1, false); vector < pair > values; for(int i = 1; i <= no_of_elements; i++) { values.push_back(make_pair(A[i], i)); } sort(values.begin(), values.end()); long long weight = 0; for(int i = 0; i < values.size(); i++) { int gcd = values[i].first, index = values[i].second; if(gcd >= p) { break; } for(int j = index - 1; j >= 1; j--) { if(A[j] < gcd || A[j]%gcd != 0 || is_connected_right[j]) { break; } is_connected_right[j] = true; weight += gcd; } for(int j = index + 1; j <= no_of_elements; j++) { if(A[j] < gcd || A[j]%gcd != 0 || is_connected_right[j - 1]) { break; } is_connected_right[j - 1] = true; weight += gcd; } } for(int i = 1; i <= no_of_elements - 1; i++) { if(!is_connected_right[i]) { weight += p; } } cout << weight << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/714 Division by Zero 2021/Programs/Swapping Problem.cpp ================================================ #include #include #include using namespace std; void update_prefix_max(map &M) { int prefix_max = 0; for(auto it = M.begin(); it != M.end(); it++) { prefix_max = max(prefix_max, it->second); it->second = prefix_max; } } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1), B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } map X, Y; for(int i = 1; i <= no_of_elements; i++) { if(A[i] <= B[i]) { X[A[i]] = max(X[A[i]], B[i]); } else { Y[B[i]] = max(Y[B[i]], A[i]); } } update_prefix_max(X); update_prefix_max(Y); long long overlap = 0; for(int i = 1; i <= no_of_elements; i++) { long long overlap_here = 0; if(A[i] <= B[i]) { auto it = Y.upper_bound(A[i]); if(it != Y.begin()) { it--; int left = A[i], right = min(it->second, B[i]); overlap_here = right - left; } } else { auto it = X.upper_bound(B[i]); if(it != X.begin()) { it--; int left = B[i], right = min(it->second, A[i]); overlap_here = right - left; } } overlap = max(overlap, overlap_here); } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer += abs(A[i] - B[i]); } answer -= 2*overlap; cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Div 2/716 Div 2/Programs/Product 1 mod N.cpp ================================================ #include #include #include using namespace std; int main() { int n; cin >> n; vector subsequence; long long product = 1; for(int i = 1; i <= n - 2; i++) { if(__gcd(i, n) == 1) { product = (product*i)%n; subsequence.push_back(i); } } if(product == n - 1) { product = (product*(n - 1))%n; subsequence.push_back(n - 1); } cout << subsequence.size() << "\n"; for(int i = 0; i < subsequence.size(); i++) { cout << subsequence[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: 2021/Div 2/722/Explanations/Parsa and Humungous Tree Explanation.txt ================================================ In the optimal value, every vertex will either be set to the left or right extreme. Let us consider some assignment of values to the tree and let v be some vertex which is not set to it's optimal value. We will show that assigning v = L[v] or v = R[v] will not result in a smaller answer And the answer will either increase or stay the same. - Let there be X neighbours with value smaller than v and Y neighbours with a larger value. - If X > Y, we can set v = R_v and get a larger answer. - Increasing v by 1, increases the sum by X - Y - Similarly, if X < Y, we can set v = L_v for a larger answer. - If X = Y, we can set it to either L_v, R_v and the answer will not change. ----- Let f(v, L) and f(v, R) be the maximum value for the subtree rooted at v, if v is set to L[v] or R[v] respectively. In order to transition, we will visit each of it's children c and check if it's better for this child to be set to it's left or right extreme. f(v, L) += max{|L[v] - L[c]| + f(c, L), |L[v] - R[c]| + f(c, R)} f(v, R) += max{|R[v] - L[c]| + f(c, L), |R[v] - R[c]| + f(c, R)} ----- void dfs(int v, int parent_v) { for(int child_v : tree[v]) { if(child_v == parent_v) { continue; } dfs(child_v, v); long long using_left_value_at_child = abs(left_value[v] - left_value[child_v]) + maximum_at[child_v][L]; long long using_right_value_at_child = abs(left_value[v] - right_value[child_v]) + maximum_at[child_v][R]; maximum_at[v][L] += max(using_left_value_at_child, using_right_value_at_child); using_left_value_at_child = abs(right_value[v] - left_value[child_v]) + maximum_at[child_v][L]; using_right_value_at_child = abs(right_value[v] - right_value[child_v]) + maximum_at[child_v][R]; maximum_at[v][R] += max(using_left_value_at_child, using_right_value_at_child); } /*cout << "At " << v << " L = " << left_value[v] << " Maximum = " << maximum_at[v][L] << "\n"; cout << "At " << v << " R = " << right_value[v] << " Maximum = " << maximum_at[v][R] << "\n";*/ } ================================================ FILE: 2021/Div 2/722/Programs/Parsa and Humungous Tree.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e5 + 5, MAX_ENDS = 2, L = 0, R = 1; vector tree[MAX_N]; long long maximum_at[MAX_N][MAX_ENDS], left_value[MAX_N], right_value[MAX_N]; void initialize(int no_of_vertices) { for(int i = 1; i <= no_of_vertices; i++) { tree[i].clear(); maximum_at[i][L] = maximum_at[i][R] = 0; } } void dfs(int v, int parent_v) { for(int child_v : tree[v]) { if(child_v == parent_v) { continue; } dfs(child_v, v); long long using_left_value_at_child = abs(left_value[v] - left_value[child_v]) + maximum_at[child_v][L]; long long using_right_value_at_child = abs(left_value[v] - right_value[child_v]) + maximum_at[child_v][R]; maximum_at[v][L] += max(using_left_value_at_child, using_right_value_at_child); using_left_value_at_child = abs(right_value[v] - left_value[child_v]) + maximum_at[child_v][L]; using_right_value_at_child = abs(right_value[v] - right_value[child_v]) + maximum_at[child_v][R]; maximum_at[v][R] += max(using_left_value_at_child, using_right_value_at_child); } /*cout << "At " << v << " L = " << left_value[v] << " Maximum = " << maximum_at[v][L] << "\n"; cout << "At " << v << " R = " << right_value[v] << " Maximum = " << maximum_at[v][R] << "\n";*/ } void solve() { int no_of_vertices; cin >> no_of_vertices; initialize(no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { cin >> left_value[i] >> right_value[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } dfs(1, 0); cout << max(maximum_at[1][L], maximum_at[1][R]) << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/724/Diluc and Kaeye Explanation.txt ================================================ If the array is partitioned into K parts, each of which have a ratio of p/q The ratio of the whole array is p/q Look at the ratio of the the current subarray [1, i]. Suppose it is (P/Q) in the lowest terms. We need to search for the rightmost occurrence of the same ratio. Suppose it is j P(i) = 1 + P(j) Where P(i) is the number of parts that we can divide [1, i] in. This is optimal because [j + 1, i] is the smallest part with ratio P/Q that ends at i. And we are adding the maximum number of parts that end at j ----- void solve() { int length; string S; cin >> length >> S; vector sum_d(length, 0), sum_k(length, 0); for(int i = 0; i < length; i++) { if(i > 0) { sum_d[i] = sum_d[i - 1]; sum_k[i] = sum_k[i - 1]; } switch(S[i]) { case 'D': sum_d[i]++; break; case 'K': sum_k[i]++; break; } } map , int> last_occurrence; vector answer(length, 1); for(int i = 0; i < length; i++) { pair ratio_here = make_pair(sum_d[i], sum_k[i]); ratio_here.first /= __gcd(sum_d[i], sum_k[i]); ratio_here.second /= __gcd(sum_d[i], sum_k[i]); if(last_occurrence.find(ratio_here) != last_occurrence.end()) { answer[i] = 1 + answer[last_occurrence[ratio_here]]; } last_occurrence[ratio_here] = i; } for(int i = 0; i < length; i++) { cout << answer[i] << " "; } cout << "\n"; } ================================================ FILE: 2021/Div 2/724/Explanations/Diluc and Kaeye Explanation.txt ================================================ If the array is partitioned into K parts, each of which have a ratio of p/q The ratio of the whole array is p/q Look at the ratio of the the current subarray [1, i]. Suppose it is (P/Q) in the lowest terms. We need to search for the rightmost occurrence of the same ratio. Suppose it is j P(i) = 1 + P(j) Where P(i) is the number of parts that we can divide [1, i] in. This is optimal because [j + 1, i] is the smallest part with ratio P/Q that ends at i. And we are adding the maximum number of parts that end at j ----- void solve() { int length; string S; cin >> length >> S; vector sum_d(length, 0), sum_k(length, 0); for(int i = 0; i < length; i++) { if(i > 0) { sum_d[i] = sum_d[i - 1]; sum_k[i] = sum_k[i - 1]; } switch(S[i]) { case 'D': sum_d[i]++; break; case 'K': sum_k[i]++; break; } } map , int> last_occurrence; vector answer(length, 1); for(int i = 0; i < length; i++) { pair ratio_here = make_pair(sum_d[i], sum_k[i]); ratio_here.first /= __gcd(sum_d[i], sum_k[i]); ratio_here.second /= __gcd(sum_d[i], sum_k[i]); if(last_occurrence.find(ratio_here) != last_occurrence.end()) { answer[i] = 1 + answer[last_occurrence[ratio_here]]; } last_occurrence[ratio_here] = i; } for(int i = 0; i < length; i++) { cout << answer[i] << " "; } cout << "\n"; } ================================================ FILE: 2021/Div 2/724/Programs/Diluc and Kaeya.cpp ================================================ #include #include #include #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; vector sum_d(length, 0), sum_k(length, 0); for(int i = 0; i < length; i++) { if(i > 0) { sum_d[i] = sum_d[i - 1]; sum_k[i] = sum_k[i - 1]; } switch(S[i]) { case 'D': sum_d[i]++; break; case 'K': sum_k[i]++; break; } } map , int> last_occurrence; vector answer(length, 1); for(int i = 0; i < length; i++) { pair ratio_here = make_pair(sum_d[i], sum_k[i]); ratio_here.first /= __gcd(sum_d[i], sum_k[i]); ratio_here.second /= __gcd(sum_d[i], sum_k[i]); if(last_occurrence.find(ratio_here) != last_occurrence.end()) { answer[i] = 1 + answer[last_occurrence[ratio_here]]; } last_occurrence[ratio_here] = i; } for(int i = 0; i < length; i++) { cout << answer[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; }   ================================================ FILE: 2021/Div 2/724/Programs/Omkar and Bad Story.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; int has_negative = false; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; if(A[i] < 0) { has_negative = true; } } if(has_negative) { cout << "NO\n"; return ; } int length = 300; cout << "YES\n"; cout << length << "\n"; for(int i = 0; i < length; i++) { cout << i << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/724/Programs/Omkar and Forest.cpp ================================================ #include #include using namespace std; long long power_mod(long long x, long long power, long long mod) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%mod; x = (x*x)%mod; power = power >> 1; } return result; } void solve() { int rows, columns; cin >> rows >> columns; vector grid(rows); for(int i = 0; i < rows; i++) { cin >> grid[i]; } const char FREE_SPACE = '#'; int free_spaces = 0; for(int r = 0; r < rows; r++) { for(int c = 0; c < columns; c++) { free_spaces += (grid[r][c] == FREE_SPACE); } } const int MOD = 1e9 + 7; long long answer = power_mod(2, free_spaces, MOD); if(free_spaces == rows*columns) { answer = (answer + MOD - 1)%MOD; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/724/Programs/Prinzessin der Verurteilung.cpp ================================================ #include #include #include using namespace std; const int MAX_LENGTH = 1e4; vector lexicographic_order; void precompute() { const int NO_OF_ALPHABETS = 26; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { string now; now += (char)('a' + alpha); lexicographic_order.push_back(now); } for(int p = 0; lexicographic_order.size() < MAX_LENGTH; p++) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { string now = lexicographic_order[p] + (char)('a' + alpha); lexicographic_order.push_back(now); } } } void solve() { int length; string S; cin >> length >> S; set distinct; for(int left = 0; left < length; left++) { string current; for(int right = left; right < length; right++) { current += S[right]; distinct.insert(current); } } for(string current : lexicographic_order) { if(distinct.count(current) == 0) { cout << current << "\n"; return ; } } } int main() { precompute(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/726/Explanations/Arithemtic Array Explanation.txt.txt ================================================ (a1 + a2 + ... + ak)/k = 1 => (a1 + a2 + ... + ak) = k If the sum is < N, then we only need to append one element to make the sum = N + 1 If the sum is > N, we will keep appending 0's till the sum is equal to the number of elements ----- void solve() { int no_of_elements; cin >> no_of_elements; int sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; sum += A[i]; } int answer = 0; if(sum > no_of_elements) { answer = sum - no_of_elements; } else if(sum < no_of_elements) { answer = 1; } else if(sum == no_of_elements) { answer = 0; } cout << answer << "\n"; } ================================================ FILE: 2021/Div 2/726/Explanations/Bad Boy Explanation.txt.txt ================================================ We will choose the end point that is furthest from (i, j), and then put the other yo-yo at the diagonally opposite end. ------ void solve() { int rows, columns, i, j; cin >> rows >> columns >> i >> j; int x1 = (2*i <= rows ? rows : 1); int y1 = (2*j <= columns ? columns : 1); int x2 = (x1 == 1 ? rows : 1); int y2 = (y1 == 1 ? columns : 1); cout << x1 << " " << y1 << " " << x2 << " " << y2 << "\n"; } ================================================ FILE: 2021/Div 2/726/Explanations/Challenging Cliffs Explanation.txt.txt ================================================ If there are x pairs (A[i], A[i + 1]) such that A[i] <= A[i + 1] in the original sorted array, we can have (x - 1) such pairs in the answer. Originally, there are (N - 1) such pairs, so the answer will have at least (N - 2) First, sort the array and choose the pair (A[i], A[i + 1]) that has the minimum A[i + 1] - A[i] Now, the answer array is this - A[i] + A[i + 2, N] + A[1, i - 2] + A[i] ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int best_1 = 1; for(int i = 2; i <= no_of_elements; i++) { if(A[i] - A[i - 1] < A[best_1 + 1] - A[best_1]) { best_1 = i - 1; } } vector answer(no_of_elements + 1); answer[1] = A[best_1]; answer[no_of_elements] = A[best_1 + 1]; int p = 2; for(int i = best_1 + 2; i <= no_of_elements; i++) { answer[p++] = A[i]; } for(int i = 1; i < best_1; i++) { answer[p++] = A[i]; } for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; } ================================================ FILE: 2021/Div 2/726/Explanations/Deleting Divisors Explanation.txt.txt ================================================ The game ends when n is prime or = 1 All primes are odd integers, except 2. If we had a strategy where we could ensure that n is odd after our turn and even before our turn, we would ensure that the final state only occurs after our move. We can do this whenever n is not a power of 2 ! ------ When n is not a power of 2, n has at least one odd divisor. We will subtract that to give our opponent an odd integer. All of an odd integer's divisors are odd. Subtracting any of them gives us an even integer. Further, we get an even integer that is not a power of 2. The reason is that if d|N => d|(N - d) because N = 0 (mod d) => N - d = 0 (mod d) So, even integers that are not powers of 2 are winning and odd integers are losing. ------ What happens for 2^p ? When we have a power of 2, subtracting one of it's divisors results in either an even integer that is not a power of 2 or 2^{p - 1} Converting it to an integer that is not a power of 2 is a losing move as the other player can win with the strategy outlined above. 2^1 is winning for the second player 2^2 is winning for the first player. 2^3 is winning for the second player and so on. Suppose by Mathematical Induction, that all odd powers of 2 are winning for Player 2 and even powers for Player 1 till 2^k 2^{k + 1} is winning for the first player only if 2^k is winning for the second player. So, 2^{k + 1} is winning only if (k + 1) is even. ------ Practical Solution During the Contest - Pattern Recognition - I precomputed the answer of the first $100$ integers and found that the second player was winning all odd integers and the first player was winning all even integers. - After getting $WA$ on the second test case, I looked for exceptions to this rule till $10^6$. I checked if there are any even integers where the second player wins or odd integers where the first player wins. - I found out that the second player wins whenever $n = 2^p$ and $p$ is odd void precompute() { int N = 1e7; vector winner(N + 1, 0); for(int i = 1; i <= N; i++) { //cout << i << " "; if(i == 1 || is_prime(i)) { //cout << " Winner = 2 Prime\n"; winner[i] = 2; continue; } for(int d = 2; d*d <= i; d++) { if(i%d != 0) { continue; } if(winner[i - d] == 2 || winner[i - i/d] == 2) { winner[i] = 1; //cout << "Winner 1\n"; continue; } } if(winner[i] == 0) winner[i] = 2; //cout << "Winner 2\n"; } cout << "***\n"; for(int i = 1; i <= N; i++) { if(winner[i]%2 == i%2) {cout << "i = " << i << " Winner = " << winner[i] << "\n"; factorise(i); } } } ================================================ FILE: 2021/Div 2/726/Explanations/Erase and Extend (Easy Version) Explanation.txt ================================================ The optimal answer consists of some prefix repeated again and again. We will perform some number of deletes and then only perform duplications. Suppose, we perform a deletion step after a duplication step and then do another duplication, if we get a smaller string, we could just do the same deletion before the first deletion step and get a smaller string. Go through all prefixes and iterate over the final string and choose the minimum ----- string concatenate_prefix(string S, int prefix, int k) { string answer; for(int i = 0; i < k; i++) { answer += S[i%prefix]; } return answer; } int main() { int length, k; cin >> length >> k; string S; cin >> S; string answer = concatenate_prefix(S, length, k); for(int i = 1; i <= S.size(); i++) { string current = concatenate_prefix(S, i, k); if(current < answer) { answer = current; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Div 2/726/Programs/Arithmetic Array.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; int sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; sum += A[i]; } int answer = 0; if(sum > no_of_elements) { answer = sum - no_of_elements; } else if(sum < no_of_elements) { answer = 1; } else if(sum == no_of_elements) { answer = 0; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/726/Programs/Bad Boy.cpp ================================================ #include #include using namespace std; void solve() { int rows, columns, i, j; cin >> rows >> columns >> i >> j; int x1 = (2*i <= rows ? rows : 1); int y1 = (2*j <= columns ? columns : 1); int x2 = (x1 == 1 ? rows : 1); int y2 = (y1 == 1 ? columns : 1); cout << x1 << " " << y1 << " " << x2 << " " << y2 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/726/Programs/Challenging Cliffs.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int best_1 = 1; for(int i = 2; i <= no_of_elements; i++) { if(A[i] - A[i - 1] < A[best_1 + 1] - A[best_1]) { best_1 = i - 1; } } vector answer(no_of_elements + 1); answer[1] = A[best_1]; answer[no_of_elements] = A[best_1 + 1]; int p = 2; for(int i = best_1 + 2; i <= no_of_elements; i++) { answer[p++] = A[i]; } for(int i = 1; i < best_1; i++) { answer[p++] = A[i]; } for(int i = 1; i <= no_of_elements; i++) { cout << answer[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/726/Programs/Deleting Divisors.cpp ================================================ #include #include using namespace std; int is_prime(int n) { for(int i = 2; i*i <= n; i++) { if(n%i == 0) { return false; } } return true; } int is_odd_power_of_2(int n) { int exponent = 0; while(n%2 == 0) { n /= 2; exponent++; } return (n == 1 && exponent%2 == 1); } void solve() { int n; cin >> n; if(is_prime(n) || n == 1 || is_odd_power_of_2(n)) { cout << "Bob\n"; return; } cout << (n%2 == 1 ? "Bob" : "Alice") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/726/Programs/Erase and Extend (Easy Version).cpp ================================================ #include #include using namespace std; string concatenate_prefix(string S, int prefix, int k) { string answer; for(int i = 0; i < k; i++) { answer += S[i%prefix]; } return answer; } int main() { int length, k; cin >> length >> k; string S; cin >> S; string answer = concatenate_prefix(S, length, k); for(int i = 1; i <= S.size(); i++) { string current = concatenate_prefix(S, i, k); if(current < answer) { answer = current; } } cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Div 2/726/Programs/Figure Fixing.cpp ================================================ #include #include using namespace std; const int UNCOLOURED = -1, RED = 0, BLUE = 1; int other(int colour) { return (1 - colour); } int dfs_bipartite_check(vector > &graph, int v, vector &C, int colour) { C[v] = colour; //cout << "Colour " << v << " = " << C[v] << "\n"; for(int child_v : graph[v]) { if(C[child_v] == C[v]) { //cout << v << " and " << child_v << " have the same colour\n"; return false; } if(C[child_v] == UNCOLOURED) { if(!dfs_bipartite_check(graph, child_v, C, other(colour))) { return false; } } } return true; } void solve() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; vector value(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> value[i]; } vector target(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { cin >> target[i]; } vector > graph(no_of_vertices + 1); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } vector colour(no_of_vertices + 1, UNCOLOURED); int is_bipartite = dfs_bipartite_check(graph, 1, colour, RED); long long red_remaining = 0, blue_remaining = 0, total_remaining = 0; for(int i = 1; i <= no_of_vertices; i++) { switch(colour[i]) { case RED : red_remaining += (target[i] - value[i]); break; case BLUE : blue_remaining += (target[i] - value[i]); break; } total_remaining += (target[i] - value[i]); } int possible; //cout << "Bipartite = " << is_bipartite << "\n"; if(is_bipartite) { possible = (red_remaining == blue_remaining); } else { possible = (total_remaining%2 == 0); } cout << (possible ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/727/Explanations/Constest Start Time Explanation.txt ================================================ Every body takes the same amount of time for a contest. A person conflicts only with those people who started after him. We need to count the number of new beginnings in [i.x, i.x + T] This is the same as counting the number of multiples of x in [0, T] = (T/x) However, a person will not have (T/x) conflicts if there aren't (T/x) people remaining. The last person has 0 conflicts The second last has 1 The third last hast 2 . The (T/x)-th has (T/x) - 1 So, for the last (T/x) - 1 people, the number of conflicts is 0 + 1 + 2 + 3 + ... + (T/x) - 1 For everyone else, the conflicts is (T/x) ------ long long get_sum(long long n) { return (n*(n + 1))/2; } void solve() { int no_of_contestants, start_time, duration; cin >> no_of_contestants >> start_time >> duration; long long answer; long long batch_1 = min(no_of_contestants, duration/start_time); answer = get_sum(batch_1 - 1); no_of_contestants -= batch_1; long long one_contestant_intersections = duration/start_time; answer += no_of_contestants*(one_contestant_intersections); cout << answer << "\n"; } ================================================ FILE: 2021/Div 2/727/Explanations/Love Song Explanation.txt.txt ================================================ Find the frequency of each alphabet in each range. The i-th alphabet contributes i x sum(i) to the whole answer ----- int main() { int length, no_of_queries; string S; cin >> length >> no_of_queries >> S; const int NO_OF_ALPHABETS = 26; vector > frequency(NO_OF_ALPHABETS, vector (length + 1, 0)); for(int i = 1; i <= length; i++) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { frequency[alpha][i] = frequency[alpha][i - 1]; } frequency[S[i - 1] - 'a'][i]++; } for(int i = 1; i <= no_of_queries; i++) { int left, right; cin >> left >> right; long long length = 0; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { long long frequency_here = frequency[alpha][right] - frequency[alpha][left - 1]; length += (alpha + 1)*frequency_here; } cout << length << "\n"; } return 0; } ================================================ FILE: 2021/Div 2/727/Explanations/Price Fixed Explanation.txt.txt ================================================ Sort the items in descending order of B. Each item costs the same so we want to buy as many items for cost 1 as possible. Go through the items one by one. Have 2 pointers L and R L points to the first available element in the prefix and R to the suffix. At each point, check if 1. We have bought enough items to avail the discount at R and buy item R at a discount 2. If not, is it possible to partially buy the items at L and then use the discount for R 3. If not, buy L completely and increment L ----- int sort_by_second(pair &P, pair &Q) { if(P.second == Q.second) { return (P.first > Q.first); } return (P.second > Q.second); } int main() { int no_of_elements; cin >> no_of_elements; vector > A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i].first >> A[i].second; } sort(A.begin() + 1, A.end(), sort_by_second); /*for(int i = 1; i <= no_of_elements; i++) { cout << A[i].first << " " << A[i].second << "\n"; }*/ long long total = 0, cost = 0; for(int left = 1, right = no_of_elements; left <= right; ) { if(total >= A[right].second) { cost += A[right].first; total += A[right].first; //cout << "Buying R = " << right << " Cost = " << cost << " Total = " << total << "\n"; right--; continue; } if(total + A[left].first < A[right].second) { cost += 2*A[left].first; total += A[left].first; //cout << "Buying L = " << left << " Cost = " << cost << " Total = " << total << "\n"; left++; continue; } long long remaining_2 = A[right].second - total; cost += 2*remaining_2; total += remaining_2; //cout << "Buying L = " << left << " Cost = " << cost << " Total = " << total; A[left].first -= remaining_2; //cout << " New Left = " << A[left].first << "\n"; } cout << cost << "\n"; return 0; } ================================================ FILE: 2021/Div 2/727/Explanations/Stable Groups Explanation.txt.txt ================================================ Keep track of all differences that are > x Put them in a priority queue and work on the smallest difference at each time. In order to split an integer N into parts such that each of them is <= x, we need N/x - 1 cuts Check if there are enough operations to cut the current part and then cut them accordingly. It is similar to the problem Carrots for Rabbits ----- long long ceil(long long numerator, long long denominator) { return (numerator/denominator) + (numerator%denominator != 0); } int main() { int no_of_elements; long long new_additions, difference; cin >> no_of_elements >> new_additions >> difference; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); priority_queue , greater > PQ; for(int i = 2; i <= no_of_elements; i++) { if(A[i] - A[i - 1] > difference) { PQ.push(A[i] - A[i - 1]); } } while(new_additions > 0 && PQ.size() > 0) { long long current = PQ.top(); //cout << "Current = " << current << "\n"; long long required_new_additions = ceil(current,difference) - 1; long long possible_additions = min(required_new_additions, new_additions); if(possible_additions >= required_new_additions) { PQ.pop(); } new_additions -= possible_additions; //cout << "Operations = " << new_additions << "\n"; } int groups = PQ.size() + 1; cout << groups << "\n"; return 0; } ================================================ FILE: 2021/Div 2/727/Programs/Contest Start.cpp ================================================ #include #include using namespace std; long long get_sum(long long n) { return (n*(n + 1))/2; } void solve() { int no_of_contestants, start_time, duration; cin >> no_of_contestants >> start_time >> duration; long long answer; long long batch_1 = min(no_of_contestants, duration/start_time); answer = get_sum(batch_1 - 1); no_of_contestants -= batch_1; long long one_contestant_intersections = duration/start_time; answer += no_of_contestants*(one_contestant_intersections); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/727/Programs/Love Song.cpp ================================================ #include #include using namespace std; int main() { int length, no_of_queries; string S; cin >> length >> no_of_queries >> S; const int NO_OF_ALPHABETS = 26; vector > frequency(NO_OF_ALPHABETS, vector (length + 1, 0)); for(int i = 1; i <= length; i++) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { frequency[alpha][i] = frequency[alpha][i - 1]; } frequency[S[i - 1] - 'a'][i]++; } for(int i = 1; i <= no_of_queries; i++) { int left, right; cin >> left >> right; long long length = 0; for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { long long frequency_here = frequency[alpha][right] - frequency[alpha][left - 1]; length += (alpha + 1)*frequency_here; } cout << length << "\n"; } return 0; } ================================================ FILE: 2021/Div 2/727/Programs/PriceFixed.cpp ================================================ #include #include #include using namespace std; int sort_by_second(pair &P, pair &Q) { if(P.second == Q.second) { return (P.first > Q.first); } return (P.second > Q.second); } int main() { int no_of_elements; cin >> no_of_elements; vector > A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i].first >> A[i].second; } sort(A.begin() + 1, A.end(), sort_by_second); /*for(int i = 1; i <= no_of_elements; i++) { cout << A[i].first << " " << A[i].second << "\n"; }*/ long long total = 0, cost = 0; for(int left = 1, right = no_of_elements; left <= right; ) { if(total >= A[right].second) { cost += A[right].first; total += A[right].first; //cout << "Buying R = " << right << " Cost = " << cost << " Total = " << total << "\n"; right--; continue; } if(total + A[left].first < A[right].second) { cost += 2*A[left].first; total += A[left].first; //cout << "Buying L = " << left << " Cost = " << cost << " Total = " << total << "\n"; left++; continue; } long long remaining_2 = A[right].second - total; cost += 2*remaining_2; total += remaining_2; //cout << "Buying L = " << left << " Cost = " << cost << " Total = " << total; A[left].first -= remaining_2; //cout << " New Left = " << A[left].first << "\n"; } cout << cost << "\n"; return 0; } ================================================ FILE: 2021/Div 2/727/Programs/Stable Groups.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long ceil(long long numerator, long long denominator) { return (numerator/denominator) + (numerator%denominator != 0); } int main() { int no_of_elements; long long new_additions, difference; cin >> no_of_elements >> new_additions >> difference; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); priority_queue , greater > PQ; for(int i = 2; i <= no_of_elements; i++) { if(A[i] - A[i - 1] > difference) { PQ.push(A[i] - A[i - 1]); } } while(new_additions > 0 && PQ.size() > 0) { long long current = PQ.top(); //cout << "Current = " << current << "\n"; long long required_new_additions = ceil(current,difference) - 1; long long possible_additions = min(required_new_additions, new_additions); if(possible_additions >= required_new_additions) { PQ.pop(); } new_additions -= possible_additions; //cout << "Operations = " << new_additions << "\n"; } int groups = PQ.size() + 1; cout << groups << "\n"; return 0; } ================================================ FILE: 2021/Div 2/740/Programs/Deep Down Below Binary Search.cpp ================================================ #include #include #include using namespace std; int possible(vector > &L, long long x) { for(int i = 0; i < L.size(); i++) { if(x < L[i].first) { return false; } x += L[i].second; } return true; } void solve() { int no_of_levels; cin >> no_of_levels; vector > level; for(int i = 1; i <= no_of_levels; i++) { int no_of_monsters; cin >> no_of_monsters; long long power = 0, increment = no_of_monsters; for(int j = 1; j <= no_of_monsters; j++) { long long x; cin >> x; power = max(power, x + 1 - (j - 1)); } level.push_back(make_pair(power, increment)); } sort(level.begin(), level.end()); long long left = 0, right = 1e18; while(right - left > 1) { long long mid = (left + right)/2; if(possible(level, mid)) { right = mid; } else { left = mid; } } cout << right << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/740/Programs/Deep Down Below.cpp ================================================ #include #include #include using namespace std; int possible(vector > &L, long long x) { for(int i = 0; i < L.size(); i++) { if(x < L[i].first) { return false; } x += L[i].second; } return true; } void solve() { int no_of_levels; cin >> no_of_levels; vector > level; for(int i = 1; i <= no_of_levels; i++) { int no_of_monsters; cin >> no_of_monsters; long long power = 0, increment = no_of_monsters; for(int j = 1; j <= no_of_monsters; j++) { long long x; cin >> x; power = max(power, x + 1 - (j - 1)); } level.push_back(make_pair(power, increment)); } sort(level.begin(), level.end()); long long total_increment = 0, power_required = 0; for(int i = 0; i < no_of_levels; i++) { power_required = max(power_required, level[i].first - total_increment); total_increment += level[i].second; } cout << power_required << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/742/Explanations/Carrying Conundrum Explanation.txt ================================================ We are performing regular addition on the odd and even digits seperately . ----- #include using namespace std; void solve() { string n; cin >> n; long long odd_places = 0, even_places = 0; for(int i = 0; i < n.size(); i++) { int digit = n[i] - '0'; switch(i%2) { case 1 : odd_places = odd_places*10 + digit; break; case 0 : even_places = even_places*10 + digit; break; } } long long total_ways = (odd_places + 1)*(even_places + 1) - 2; cout << total_ways << "\n"; } ================================================ FILE: 2021/Div 2/742/Programs/Carrying Conundrum.cpp ================================================ #include using namespace std; void solve() { string n; cin >> n; long long odd_places = 0, even_places = 0; for(int i = 0; i < n.size(); i++) { int digit = n[i] - '0'; switch(i%2) { case 1 : odd_places = odd_places*10 + digit; break; case 0 : even_places = even_places*10 + digit; break; } } long long total_ways = (odd_places + 1)*(even_places + 1) - 2; cout << total_ways << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 2/750/Explanations/Pchelyonok and Segments Explanation.txt ================================================ How to use smaller subproblems to build the solution $?$ - In order to know if we can make the $P$-th partition here, we need to know if it is possible to make $P - 1, P - 2, \dots , 1$ partitions from $[i + P]$. - Let $f(i, P)$ be the maximum sum that the $P$-th partition can have if it begins anywhere on or after $i$ and is followed by all the smaller partitions. - $f(i, P) = \max\{f(i + 1, P), S[i, i + P - 1]\}$ - We need to be careful and first check that $S[i, i + P - 1] < f(i + P, P - 1)$ in order to maintain the decreasing sum condition. --- ## Why are we taking the maximum sum $?$ - We need to ensure that the sum of the $P$-th segment should be smaller than the $P - 1$ segment. - Since, we are going from right to left, we might as well choose the maximum possible sum for each segment greedily. - We can use an exchange argument to show that the number of segments will never decrease by choosing a greater sum segment beginning on or after the same index. - The answer is the largest $k$ for which $f(1, k) > 0$ --- ## Why is this not $O(n^2)$ $?$ - The maximum $k$ is such that $\frac{k(k + 1)}{2} \le n \implies k(k + 1) \le 2n \implies k^2 < 2n$ - So, $k < \sqrt{2n}$ - This is actually $O(n \sqrt{n})$ because of how quickly the triangular numbers grow. ----- ```cpp void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 5, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector sum_from(no_of_elements + 5, 0); for(int i = no_of_elements; i >= 1; i--) { sum_from[i] = A[i] + sum_from[i + 1]; } long long max_k = get_largest_k(no_of_elements); vector > max_segment_sum(no_of_elements + 5, vector (max_k + 1)); for(int i = no_of_elements; i >= 1; i--) { for(int segment_size = 1; segment_size <= max_k; segment_size++) { max_segment_sum[i][segment_size] = max_segment_sum[i + 1][segment_size]; if(i + segment_size - 1 > no_of_elements) { continue; } long long sum_here = sum_from[i] - sum_from[i + segment_size]; if(segment_size == 1 || sum_here < max_segment_sum[i + segment_size][segment_size - 1]) { max_segment_sum[i][segment_size] = max(max_segment_sum[i][segment_size], sum_here); } } } int answer = 0; for(int segment_size = max_k; segment_size >= 1; segment_size--) { if(max_segment_sum[1][segment_size] > 0) { answer = segment_size; break; } } cout << answer << "\n"; } ``` ================================================ FILE: 2021/Div 2/750/Programs/Pchelyonok and Segments.cpp ================================================ #include #include using namespace std; long long get_largest_k(long long n) { long long right = n, left = 1; while(right - left > 1) { long long mid = (left + right)/2; if(mid*1LL*(mid + 1) <= 2*n) { left = mid; } else { right = mid; } } return left; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 5, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector sum_from(no_of_elements + 5, 0); for(int i = no_of_elements; i >= 1; i--) { sum_from[i] = A[i] + sum_from[i + 1]; } long long max_k = get_largest_k(no_of_elements); vector > max_segment_sum(no_of_elements + 5, vector (max_k + 1)); for(int i = no_of_elements; i >= 1; i--) { for(int segment_size = 1; segment_size <= max_k; segment_size++) { max_segment_sum[i][segment_size] = max_segment_sum[i + 1][segment_size]; if(i + segment_size - 1 > no_of_elements) { continue; } long long sum_here = sum_from[i] - sum_from[i + segment_size]; if(segment_size == 1 || sum_here < max_segment_sum[i + segment_size][segment_size - 1]) { max_segment_sum[i][segment_size] = max(max_segment_sum[i][segment_size], sum_here); } } } int answer = 0; for(int segment_size = max_k; segment_size >= 1; segment_size--) { if(max_segment_sum[1][segment_size] > 0) { answer = segment_size; break; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/710/Explanations/Double Ended Strings Explanation.txt.txt ================================================ Let f(La, Ra, Lb, Rb) be true if A[La][Ra] = B[Lb][Rb] f(La, Ra, Lb, Rb) = (A[La] = B[Lb]) + f(La + 1, Ra, Lb + 1, Rb) Find out the length of the maximum matching string ----- void solve() { string A, B; cin >> A >> B; memset(matches, false, sizeof(matches)); int max_length = 0, changes = A.size() + B.size(); for(int length = 1; length <= min(A.size(), B.size()); length++) { for(int a_left = 0, a_right = a_left + length - 1; a_right < A.size(); a_left++, a_right++) { for(int b_left = 0, b_right = b_left + length - 1; b_right < B.size(); b_left++, b_right++) { if(length == 1) { matches[a_left][a_right][b_left][b_right] = (A[a_left] == B[b_left]); } else { matches[a_left][a_right][b_left][b_right] = ( (A[a_left] == B[b_left]) && (matches[a_left + 1][a_right][b_left + 1][b_right]) ); } if(matches[a_left][a_right][b_left][b_right]) { max_length = length; changes = (a_left) + (A.size() - 1 - a_right) + (b_left) + (B.size() - 1 - b_right); } } } } cout << changes << "\n"; } ================================================ FILE: 2021/Div 3/710/Explanations/Epic Transformation Explanation.txt.txt ================================================ If any pile has > N/2 stones, that pile will remain standing even at the end. Otherwise, we are reducing the piles by 2 at each step. Let us take a stone from the two highest piles. Since the largest pile has < N/2 stones in the beginning, it will always have < N/2 stones at every step. When the game ends, it cannot have 2 stones In the end, there will be either 0 or 1 stones depending on the parity, which is invariant. ----- void solve() { int no_of_elements; cin >> no_of_elements; map frequency; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; } vector pile; for(auto it = frequency.begin(); it != frequency.end(); it++) { pile.push_back(it->second); } sort(pile.begin(), pile.end()); if(2*pile.back() > no_of_elements) { int remaining = no_of_elements - pile.back(); cout << no_of_elements - 2*remaining << "\n"; return; } cout << no_of_elements%2 << "\n"; } ================================================ FILE: 2021/Div 3/710/Explanations/Maximize the Remaining String Explanation.txt ================================================ - We will keep track of the suffix frequency of each alphabet. - We will iterate over every character in the string. - We will append $S[i]$ to the answer if it is not currently present in the answer. - Before appending it, we will remove all characters in the suffix of the answer that are $< S[i]$ and have suffix frequency $> 0$, which means that the alphabet occurs later in the string too and we will get a larger string by choosing it's next occurrence. ----- void solve() { string S; cin >> S; const int NO_OF_ALPHABETS = 26; vector < vector > suffix_frequency(S.size() + 1, vector (NO_OF_ALPHABETS, 0)); for(int i = S.size() - 1; i >= 0; i--) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { suffix_frequency[i][alpha] = suffix_frequency[i + 1][alpha]; } suffix_frequency[i][S[i] - 'a']++; } string answer; vector used(NO_OF_ALPHABETS, false); for(int i = 0; i < S.size(); i++) { if(used[S[i] - 'a']) { continue; } while(answer.size() > 0 && suffix_frequency[i][answer.back() - 'a'] > 0 && answer.back() < S[i]) { used[answer.back() - 'a'] = false; answer.pop_back(); } answer += S[i]; used[S[i] - 'a'] = true; } cout << answer << "\n"; } ================================================ FILE: 2021/Div 3/710/Explanations/Partial Replacement.txt.txt ================================================ We will be greedy. We will try to keep the x's as far as possible but not more than K. The question says that it is always guarnateed that no to X's are more than K apart. Store the indices of all the X's in a vector and then greedily perform the changes. ----- void solve() { int length, k; cin >> length >> k; string S; cin >> S; vector positions; for(int i = 0; i < S.size(); i++) { if(S[i] == '*') { positions.push_back(i); } } vector changes; changes.push_back(positions[0]); for(int i = 0; i < positions.size(); i++) { if(positions[i] - changes.back() > k) { changes.push_back(positions[i - 1]); } if(i + 1 == positions.size()) { if(positions[i] != changes.back()) { changes.push_back(positions[i]); } } } cout << changes.size() << "\n"; } ================================================ FILE: 2021/Div 3/710/Explanations/Strange Table Explanation.txt.txt ================================================ When they are numbered 'column' wise, the number for cell (r, c) is R(c - 1) + r When, they are numbered 'row' wise, the number for cell (r, c) is C(r - 1) + c First, find out (r, c) and then the other number. ----- void solve() { long long rows, columns, x; cin >> rows >> columns >> x; long long column_no = (x/rows) + (x%rows != 0); long long row_no = x - rows*(column_no - 1); long long new_no = columns*(row_no - 1) + column_no; cout << new_no << "\n"; } ================================================ FILE: 2021/Div 3/710/Explanations/Triangular Paths Explanation.txt.txt ================================================ - It is always possible to travel through the points so let us travel in ascending order of $r$ since we can never go backwards. - Let us look at the quantity $D = r - c$ for each node. - When we move from an even cell to an odd cell, $D$ increases by $1$ - When we move from an odd cell to an odd cell, $D$ remains the same. - Let $D_1$ be the difference of the source and $D_2$ the difference of the target. - If $D_1 = D_2$, then - If we are on an odd cell, we just keep sliding till we hit the target. No additional edges. - If we are on an even cell, we have to keep making a new edge to $(r + 1, c + 1)$, which will also be even. So it will cost $r_2 - r_1$ --- - If $D_1 < D_2$, then - We can only increase the value of $D$ by moving from $(r, c) \to (r + 1, c)$ - This is the normal even transition. - So, we will go along the following path till $D_1 = D_2$ - $E \to O \to E \to O \to \dots \to O$ - We don't have to make any edge from $E \to O$ but have to make half the edges from $O \to E$ - Keep in mind that we can add in any number of legal $O \to O$ transitions in between so that we finish our path on the destination cell $(r_2 - c_2)$ - If $D_1 - D_2$ is odd, then - We will be making exactly half the number of new edges if we begin on an even cell. - We will be making one more than half new edges if we begin on an odd cell. --- - Make sure that the path ends on an odd cell so we have the situation $D_1 = D_2$ on an odd cell as discussed above so cost is $0$. --- - If $D_1 > D_2$, then the answer is not possible because - Either $r_1 > r_2$ or $c_1 > c_2$ and we can never go backwards ------ int is_even(long long r, long long c) { return ( (r + c)%2 == 0 ); } void solve() { int no_of_elements; cin >> no_of_elements; vector < pair > P(no_of_elements + 1, make_pair(1, 1)); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i].first; } for(int i = 1; i <= no_of_elements; i++) { cin >> P[i].second; } sort(P.begin(), P.end()); long long distance = 0; for(int i = 0; i + 1 <= no_of_elements; i++) { int source_difference = P[i].first - P[i].second; int target_difference = P[i + 1].first - P[i + 1].second; int extra_difference = target_difference - source_difference; if(extra_difference == 0) { distance += (is_even(P[i].first, P[i].second) ? P[i + 1].first - P[i].first : 0); continue; } if(is_even(P[i].first, P[i].second)) { distance += ( extra_difference/2 ); } else { distance += extra_difference/2 + extra_difference%2; } } cout << distance << "\n"; } ================================================ FILE: 2021/Div 3/710/Programs/Double Ended Strings.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 21; int matches[MAX_N][MAX_N][MAX_N][MAX_N]; void solve() { string A, B; cin >> A >> B; memset(matches, false, sizeof(matches)); int max_length = 0, changes = A.size() + B.size(); for(int length = 1; length <= min(A.size(), B.size()); length++) { for(int a_left = 0, a_right = a_left + length - 1; a_right < A.size(); a_left++, a_right++) { for(int b_left = 0, b_right = b_left + length - 1; b_right < B.size(); b_left++, b_right++) { if(length == 1) { matches[a_left][a_right][b_left][b_right] = (A[a_left] == B[b_left]); } else { matches[a_left][a_right][b_left][b_right] = ( (A[a_left] == B[b_left]) && (matches[a_left + 1][a_right][b_left + 1][b_right]) ); } if(matches[a_left][a_right][b_left][b_right]) { max_length = length; changes = (a_left) + (A.size() - 1 - a_right) + (b_left) + (B.size() - 1 - b_right); } } } } cout << changes << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/710/Programs/Epic Transformation.cpp ================================================ #include #include #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; map frequency; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; frequency[A[i]]++; } vector pile; for(auto it = frequency.begin(); it != frequency.end(); it++) { pile.push_back(it->second); } sort(pile.begin(), pile.end()); if(2*pile.back() > no_of_elements) { int remaining = no_of_elements - pile.back(); cout << no_of_elements - 2*remaining << "\n"; return; } cout << no_of_elements%2 << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/710/Programs/Maximize the Remaining String.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { string S; cin >> S; const int NO_OF_ALPHABETS = 26; vector < vector > suffix_frequency(S.size() + 1, vector (NO_OF_ALPHABETS, 0)); for(int i = S.size() - 1; i >= 0; i--) { for(int alpha = 0; alpha < NO_OF_ALPHABETS; alpha++) { suffix_frequency[i][alpha] = suffix_frequency[i + 1][alpha]; } suffix_frequency[i][S[i] - 'a']++; } string answer; vector used(NO_OF_ALPHABETS, false); for(int i = 0; i < S.size(); i++) { if(used[S[i] - 'a']) { continue; } while(answer.size() > 0 && suffix_frequency[i][answer.back() - 'a'] > 0 && answer.back() < S[i]) { used[answer.back() - 'a'] = false; answer.pop_back(); } answer += S[i]; used[S[i] - 'a'] = true; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/710/Programs/Partial Replacement.cpp ================================================ #include #include using namespace std; void solve() { int length, k; cin >> length >> k; string S; cin >> S; vector positions; for(int i = 0; i < S.size(); i++) { if(S[i] == '*') { positions.push_back(i); } } vector changes; changes.push_back(positions[0]); for(int i = 0; i < positions.size(); i++) { if(positions[i] - changes.back() > k) { changes.push_back(positions[i - 1]); } if(i + 1 == positions.size()) { if(positions[i] != changes.back()) { changes.push_back(positions[i]); } } } cout << changes.size() << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/710/Programs/Strange Table.cpp ================================================ #include using namespace std; void solve() { long long rows, columns, x; cin >> rows >> columns >> x; long long column_no = (x/rows) + (x%rows != 0); long long row_no = x - rows*(column_no - 1); long long new_no = columns*(row_no - 1) + column_no; cout << new_no << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/710/Programs/Triangular Paths.cpp ================================================ #include #include #include #include #include using namespace std; int is_even(long long r, long long c) { return ( (r + c)%2 == 0 ); } void solve() { int no_of_elements; cin >> no_of_elements; vector < pair > P(no_of_elements + 1, make_pair(1, 1)); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i].first; } for(int i = 1; i <= no_of_elements; i++) { cin >> P[i].second; } sort(P.begin(), P.end()); long long distance = 0; for(int i = 0; i + 1 <= no_of_elements; i++) { int source_difference = P[i].first - P[i].second; int target_difference = P[i + 1].first - P[i + 1].second; int extra_difference = target_difference - source_difference; if(extra_difference == 0) { distance += (is_even(P[i].first, P[i].second) ? P[i + 1].first - P[i].first : 0); continue; } if(is_even(P[i].first, P[i].second)) { distance += ( extra_difference/2 ); } else { distance += extra_difference/2 + extra_difference%2; } } cout << distance << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Explanations/A-B Palindrome Explanation.txt.txt ================================================ In the first pass, make S[i] = S[n - i] for all i These moves are forced The central characters can be either 0 or 1 so don't choose it yet. The pairs where both are ? can also be both 0 or 1 so don't choose it yet. In the second pass, make the pairs = 0, 1, whichever is available At last, choose the central character based on availability. ------ void solve() { vector target(2, 0), frequency(2, 0); string S; cin >> target[0] >> target[1] >> S; for(int i = 0; i < S.size(); i++) { if(S[i] != '?') { frequency[S[i] - '0']++; } } int palindrome = true; for(int front_i = 0, back_i = S.size() - 1; front_i < back_i; front_i++, back_i--) { if(S[front_i] != '?' && S[back_i] == '?') { S[back_i] = S[front_i]; frequency[S[back_i] - '0']++; } else if(S[back_i] != '?' && S[front_i] == '?') { S[front_i] = S[back_i]; frequency[S[front_i] - '0']++; } if(S[front_i] != S[back_i]) { palindrome = false; } } for(int front_i = 0, back_i = S.size() - 1; front_i <= back_i; front_i++, back_i--) { if(front_i == back_i) { if(S[front_i] == '?') { if(frequency[0] != target[0]) { S[front_i] = '0'; } else if(frequency[1] != target[1]) { S[front_i] = '1'; } frequency[S[front_i] - '0']++; } continue; } if(S[front_i] == '?' && S[back_i] == '?') { if(target[0] - frequency[0] >= 2) { S[front_i] = S[back_i] = '0'; frequency[0] += 2; } else { S[front_i] = S[back_i] = '1'; frequency[1] += 2; } } } if(frequency[0] != target[0] || frequency[1] != target[1] || !palindrome) { cout << "-1\n"; return; } cout << S << "\n"; } ================================================ FILE: 2021/Div 3/713/Explanations/Almost Rectange Explanation.txt.txt ================================================ If the two dots are not on the same row or column, we can complete the rectangle by making new dots on A(r1, c2) and A(r2, c1) If they are in the same row or column, we will just an adjacent row or column to make the two dots ------ void solve() { int no_of_elements; cin >> no_of_elements; vector grid(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> grid[i]; } int r_1 = -1, c_1 = -1, r_2 = -1, c_2 = -1; for(int i = 0; i < no_of_elements; i++) { for(int j = 0; j < no_of_elements; j++) { if(grid[i][j] == '*') { if(r_1 == -1) { r_1 = i; c_1 = j; } else { r_2 = i; c_2 = j; } } } } grid[r_1][c_2] = grid[r_2][c_1] = '*'; if(r_1 == r_2) { int r = (r_1 == 0 ? 1 : 0); grid[r][c_1] = grid[r][c_2] = '*'; } else if(c_1 == c_2) { int c = (c_1 == 0 ? 1 : 0); grid[r_1][c] = grid[r_2][c] = '*'; } for(int i = 0; i < no_of_elements; i++) { cout << grid[i] << "\n"; } } ================================================ FILE: 2021/Div 3/713/Explanations/Corrupted Array Explanation.txt.txt ================================================ Let us sort A. B[n + 1] must either be the last element or the second last element. Check if it is the second last element. If not, iterate over every possibility for x as it is the last element. ------ void solve() { int no_of_elements; cin >> no_of_elements; vector B(no_of_elements + 3); for(int i = 1; i <= no_of_elements + 2; i++) { cin >> B[i]; } sort(B.begin(), B.end()); vector sum_till(no_of_elements + 3, 0); for(int i = 1; i <= no_of_elements + 2; i++) { sum_till[i] = sum_till[i - 1] + B[i]; } int found = false; int x = no_of_elements + 1; if(sum_till[no_of_elements] == B[no_of_elements + 1]) { found = true; } for(int i = 1; i <= no_of_elements + 1; i++) { if(sum_till[no_of_elements + 1] - B[i] == B[no_of_elements + 2]) { x = i; found = true; break; } } if(!found) { cout << "-1\n"; return; } for(int i = 1; i <= no_of_elements + 1; i++) { if(i == x) { continue; } cout << B[i] << " "; } cout << "\n"; } ================================================ FILE: 2021/Div 3/713/Explanations/Education Explanation.txt.txt ================================================ Calculate the cost for buying the computer on each day. 1. Calculate the minimum number of days to reach salary i 2. Keep track of savings 3. Calculate the number of days to buy the computer if this is the final salary (Use savings too) ----- void solve() { int no_of_elements, computer_cost; cin >> no_of_elements >> computer_cost; vector A(no_of_elements + 1), B(no_of_elements); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements - 1; i++) { cin >> B[i]; } vector savings(no_of_elements + 1); //Savings on reaching day i vector minimum_days_to_reach(no_of_elements + 1); //Days to reach i. Earn on day f(i) + 1 for(int i = 1; i <= no_of_elements; i++) { long long days_here = ceil(B[i - 1] - savings[i - 1], A[i - 1]); savings[i] = days_here*A[i - 1] - (B[i - 1] - savings[i - 1]); minimum_days_to_reach[i] = minimum_days_to_reach[i - 1] + days_here + (i > 1); } long long no_of_days = 1e15; for(int i = 1; i <= no_of_elements; i++) { long long days_for_this_last_salary = ceil(computer_cost - savings[i], A[i]); no_of_days = min(no_of_days, days_for_this_last_salary + minimum_days_to_reach[i]); } cout << no_of_days << "\n"; } ================================================ FILE: 2021/Div 3/713/Explanations/Short Task Explanation.txt ================================================ We will use a sieve to precompute the sum of divisors of each integer And then precompute the smallest integer with X factors for each X in [1, 10^7] ----- #include #include using namespace std; const int MAX_N = 1e7 + 5; int divisor_sum[MAX_N], answer[MAX_N]; void sieve() { memset(divisor_sum, 0, sizeof(divisor_sum)); memset(answer, -1, sizeof(answer)); for(int i = 1; i < MAX_N; i++) { for(int multiple = i; multiple < MAX_N; multiple += i) { divisor_sum[multiple] += i; } if(divisor_sum[i] < MAX_N && answer[divisor_sum[i]] == -1) { answer[divisor_sum[i]] = i; } } } void solve() { int n; cin >> n; cout << answer[n] << "\n"; } int main() { sieve(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Explanations/Spy Detected Explanation.txt.txt ================================================ Sort the array A. The unique element is either the first element or the last. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector < pair > A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i].first; A[i].second = i; } sort(A.begin(), A.end()); int index = (A[1].first == A[2].first ? A[no_of_elements].second : A[1].second); cout << index << "\n"; } ================================================ FILE: 2021/Div 3/713/Programs/A-B Palindrome.cpp ================================================ #include #include #include using namespace std; void solve() { vector target(2, 0), frequency(2, 0); string S; cin >> target[0] >> target[1] >> S; for(int i = 0; i < S.size(); i++) { if(S[i] != '?') { frequency[S[i] - '0']++; } } int palindrome = true; for(int front_i = 0, back_i = S.size() - 1; front_i < back_i; front_i++, back_i--) { if(S[front_i] != '?' && S[back_i] == '?') { S[back_i] = S[front_i]; frequency[S[back_i] - '0']++; } else if(S[back_i] != '?' && S[front_i] == '?') { S[front_i] = S[back_i]; frequency[S[front_i] - '0']++; } if(S[front_i] != S[back_i]) { palindrome = false; } } for(int front_i = 0, back_i = S.size() - 1; front_i <= back_i; front_i++, back_i--) { if(front_i == back_i) { if(S[front_i] == '?') { if(frequency[0] != target[0]) { S[front_i] = '0'; } else if(frequency[1] != target[1]) { S[front_i] = '1'; } frequency[S[front_i] - '0']++; } continue; } if(S[front_i] == '?' && S[back_i] == '?') { if(target[0] - frequency[0] >= 2) { S[front_i] = S[back_i] = '0'; frequency[0] += 2; } else { S[front_i] = S[back_i] = '1'; frequency[1] += 2; } } } if(frequency[0] != target[0] || frequency[1] != target[1] || !palindrome) { cout << "-1\n"; return; } cout << S << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Programs/Almost Rectangle.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector grid(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> grid[i]; } int r_1 = -1, c_1 = -1, r_2 = -1, c_2 = -1; for(int i = 0; i < no_of_elements; i++) { for(int j = 0; j < no_of_elements; j++) { if(grid[i][j] == '*') { if(r_1 == -1) { r_1 = i; c_1 = j; } else { r_2 = i; c_2 = j; } } } } grid[r_1][c_2] = grid[r_2][c_1] = '*'; if(r_1 == r_2) { int r = (r_1 == 0 ? 1 : 0); grid[r][c_1] = grid[r][c_2] = '*'; } else if(c_1 == c_2) { int c = (c_1 == 0 ? 1 : 0); grid[r_1][c] = grid[r_2][c] = '*'; } for(int i = 0; i < no_of_elements; i++) { cout << grid[i] << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Programs/Corrupted Array.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector B(no_of_elements + 3); for(int i = 1; i <= no_of_elements + 2; i++) { cin >> B[i]; } sort(B.begin(), B.end()); vector sum_till(no_of_elements + 3, 0); for(int i = 1; i <= no_of_elements + 2; i++) { sum_till[i] = sum_till[i - 1] + B[i]; } int found = false; int x = no_of_elements + 1; if(sum_till[no_of_elements] == B[no_of_elements + 1]) { found = true; } for(int i = 1; i <= no_of_elements + 1; i++) { if(sum_till[no_of_elements + 1] - B[i] == B[no_of_elements + 2]) { x = i; found = true; break; } } if(!found) { cout << "-1\n"; return; } for(int i = 1; i <= no_of_elements + 1; i++) { if(i == x) { continue; } cout << B[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Programs/Education.cpp ================================================ #include #include using namespace std; long long ceil(long long n, long long d) { if(d == 0 || n <= 0) { return 0; } return (n/d) + (n%d != 0); } void solve() { int no_of_elements, computer_cost; cin >> no_of_elements >> computer_cost; vector A(no_of_elements + 1), B(no_of_elements); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements - 1; i++) { cin >> B[i]; } vector savings(no_of_elements + 1); //Savings on reaching day i vector minimum_days_to_reach(no_of_elements + 1); //Days to reach i. Earn on day f(i) + 1 for(int i = 1; i <= no_of_elements; i++) { long long days_here = ceil(B[i - 1] - savings[i - 1], A[i - 1]); savings[i] = days_here*A[i - 1] - (B[i - 1] - savings[i - 1]); minimum_days_to_reach[i] = minimum_days_to_reach[i - 1] + days_here + (i > 1); } long long no_of_days = 1e15; for(int i = 1; i <= no_of_elements; i++) { long long days_for_this_last_salary = ceil(computer_cost - savings[i], A[i]); no_of_days = min(no_of_days, days_for_this_last_salary + minimum_days_to_reach[i]); } cout << no_of_days << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Programs/Short Task.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e7 + 5; int divisor_sum[MAX_N], answer[MAX_N]; void sieve() { memset(divisor_sum, 0, sizeof(divisor_sum)); memset(answer, -1, sizeof(answer)); for(int i = 1; i < MAX_N; i++) { for(int multiple = i; multiple < MAX_N; multiple += i) { divisor_sum[multiple] += i; } if(divisor_sum[i] < MAX_N && answer[divisor_sum[i]] == -1) { answer[divisor_sum[i]] = i; } } } void solve() { int n; cin >> n; cout << answer[n] << "\n"; } int main() { sieve(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/713/Programs/Spy Detected.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector < pair > A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i].first; A[i].second = i; } sort(A.begin(), A.end()); int index = (A[1].first == A[2].first ? A[no_of_elements].second : A[1].second); cout << index << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Div 3/744/Programs/Array Optimization by Deque.cpp ================================================ #include #include #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; const int MAX_N = 2e5 + 5; int sum_tree[3*MAX_N]; void build(int n, int left, int right) { if(left == right) { sum_tree[n] = 0; return; } int mid = (left + right)/2; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } void update(int n, int left, int right, int position, int value) { if(position < left || right < position) { return; } if(left == right) { sum_tree[n] += value; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int get_sum(int n, int left, int right, int query_left, int query_right) { if(right < left || query_right < left || right < query_left) { return 0; } if(query_left <= left && right <= query_right) { return sum_tree[n]; } int mid = (left + right)/2; int left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); int right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } void compress_coordinates(int no_of_elements, vector &A) { vector sorted_A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sorted_A[i] = A[i]; } sort(sorted_A.begin() + 1, sorted_A.end()); map label; label[sorted_A[1]] = 1; for(int i = 2; i <= no_of_elements; i++) { label[sorted_A[i]] = (sorted_A[i] == sorted_A[i - 1] ? label[sorted_A[i - 1]] : label[sorted_A[i - 1]] + 1); } for(int i = 1; i <= no_of_elements; i++) { A[i] = label[A[i]]; } } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } compress_coordinates(no_of_elements, A); build(1, 1, no_of_elements); long long inversions = 0; for(int i = 1; i <= no_of_elements; i++) { //cout << "Currently " << A[i] << "\n"; int prefix_sum = get_sum(1, 1, no_of_elements, 1, A[i] - 1); int suffix_sum = get_sum(1, 1, no_of_elements, A[i] + 1, no_of_elements); update(1, 1, no_of_elements, A[i], 1); //cout << "Prefix = " << prefix_sum << " Suffix = " << suffix_sum << "\n"; inversions += min(prefix_sum, suffix_sum); } cout << inversions << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2021/Educational Round 109/Explanations/Permutation Sort Explanation.txt ================================================ 1. If the array is already sorted, we need 0 moves. 2. Suppose A[1] = 1, then we can apply the operation to [2, N] and sort the array in 1 move 3. In most other cases 2 moves should be enough [1, n - 1] and [2, n] 3. If A[1] = n or A[n] = 1, then this will not be enough. We need to do another move to bring 1 or n out of the extreme positions as we are not allowed to apply the operation on the entire array. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int sorted = true; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != i) { sorted = false; } } int steps; if(sorted) { steps = 0; } else if(A[1] == 1 || A[no_of_elements] == no_of_elements) { steps = 1; } else if(A[no_of_elements] == 1 && A[1] == no_of_elements) { steps = 3; } else { steps = 2; } cout << steps << "\n"; } ================================================ FILE: 2021/Educational Round 109/Programs/Permutation Sort.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int sorted = true; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != i) { sorted = false; } } int steps; if(sorted) { steps = 0; } else if(A[1] == 1 || A[no_of_elements] == no_of_elements) { steps = 1; } else if(A[no_of_elements] == 1 && A[1] == no_of_elements) { steps = 3; } else { steps = 2; } cout << steps << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; }   ================================================ FILE: 2021/Practice/Explanations/Anton and Making Potions Explanation.txt ================================================ 1. We can use at most 1 spell of each type. 2. We will iterate over the reduction spells and find out the best creation spell. 3. Suppose our current reduction spell costs X and we have M money in total. We can buy a creation spell of cost at most (M - X) 4. We need to know the best creation spell of cost at most (M - X). We can binary search to find the index i, such that creation cost <= (M - X) and find the prefix maximum of the array. ----- Calculate the prefix maximum of the sorted creation array Iterate over each reduction With the remaining money, choose the best creation spell This will minimize time. ----- I faced an error when I used lower_bound but got AC when I implemented the binary search myself. We also want to test the case where we use 0 reduction spells and 1 creation spell so make an extra reduction spell of cost 0 and value 'X' (The original Time) ----- int main() { int no_of_potions, no_of_spells_1, no_of_spells_2; cin >> no_of_potions >> no_of_spells_1 >> no_of_spells_2; long long time, money; cin >> time >> money; vector < pair > reduction(no_of_spells_1 + 1); for(int i = 1; i <= no_of_spells_1; i++) { cin >> reduction[i].second; } for(int i = 1; i <= no_of_spells_1; i++) { cin >> reduction[i].first; } reduction[0].first = 0, reduction[0].second = time; sort(reduction.begin(), reduction.end()); vector < pair > creation(no_of_spells_2 + 1); vector creation_cost(no_of_spells_2 + 1); for(int i = 1; i <= no_of_spells_2; i++) { cin >> creation[i].second; } for(int i = 1; i <= no_of_spells_2; i++) { cin >> creation[i].first; creation_cost[i] = creation[i].first; } sort(creation.begin(), creation.end()); sort(creation_cost.begin(), creation_cost.end()); vector prefix_max(no_of_spells_2 + 1); for(int i = 1; i <= no_of_spells_2; i++) { prefix_max[i] = max(prefix_max[i - 1], creation[i].second); //cout << "At i = " << i << " Creation Cost = " << creation[i].first << " Creation = " << creation[i].second << " Best = " << prefix_max[i] << "\n"; } long long best_time = time*no_of_potions; for(int i = 0; i <= no_of_spells_1; i++) { if(reduction[i].first > money) { break; } long long remaining_money = max(0LL, money - reduction[i].first); int index; int left = 0, right = creation_cost.size() - 1; if(creation_cost[right] <= remaining_money) { index = right; } else { while(right - left > 1) { int mid = (left + right)/2; if(creation_cost[mid] > remaining_money) { right = mid; } else { left = mid; } } index = left; } long long new_potions = prefix_max[index], new_time = reduction[i].second; long long remaining_potions = max(0LL, no_of_potions - new_potions); long long time_here = (remaining_potions*new_time); best_time = min(best_time, time_here); } cout << best_time << "\n"; return 0; } ================================================ FILE: 2021/Practice/Explanations/Anton and Tree Explanation.txt.txt ================================================ Let us compress consecutive vertices of the same colour into one vertex. After this transformation, we have a tree where every pair of consecutive vertices have a different colour. Let us look at the diameter of the tree - The longest distance between two nodes. - Let us look at the diameter of this tree. The length of the diameter reduces by at most $2$ in each step and stops when it is $0$ - Let us make sure that it reduces by exactly $2$ at each step. - There might be multiple diameters so choose the 'center' of the diameter. Find a vertex $v$ such that the distance to any vertex does not exceed $\lceil d/2 \rceil$ - When we perform the operation on $v$ $\lceil d/2 \rceil$ times, the distance from $v$ to any other vertex will be $0$ since it moves one step closer to it's leaves at every step. - So, we have shown that it is possible in $\lceil d/2 \rceil$ steps and also shown that it cannot happen faster. ------ int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1; i <= no_of_vertices; i++) { cin >> colour[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } int component_no = 0; for(int i = 1; i <= no_of_vertices; i++) { if(component[i] == 0) { dfs_component(i, 0, ++component_no); } } for(int i = 1; i <= no_of_vertices; i++) { for(int child : graph[i]) { int child_component = component[child], this_component = component[i]; if(child_component != this_component) { component_graph[this_component].push_back(child_component); component_graph[child_component].push_back(this_component); } } } int diameter = get_component_graph_diameter(component_no); int answer = ceil(diameter, 2); cout << answer << "\n"; return 0; } ------ To find the diameter, we 1. Root the tree arbitrarily and find the furthest node from it u 2. Calculate the distance of the furthest node from u (v) 3. The diameter is u-v ------ int get_component_graph_diameter(int n) { const int oo = 1e9; int root = 1; vector distance(n + 1, oo); distance[root] = 0; queue Q; Q.push(root); while(Q.size() > 0) { int v = Q.front(); Q.pop(); for(int child_v : component_graph[v]) { if(distance[v] + 1 < distance[child_v]) { distance[child_v] = distance[v] + 1; Q.push(child_v); } } } for(int i = 1; i <= n; i++) { if(distance[i] > distance[root]) { root = i; } } for(int i = 1; i <= n; i++) { distance[i] = oo; } distance[root] = 0; Q.push(root); while(Q.size() > 0) { int v = Q.front(); Q.pop(); for(int child_v : component_graph[v]) { if(distance[v] + 1 < distance[child_v]) { distance[child_v] = distance[v] + 1; Q.push(child_v); } } } int diameter = 0; for(int i = 1; i <= n; i++) { diameter = max(diameter, distance[i]); } return diameter; } ================================================ FILE: 2021/Practice/Explanations/Counter Attack Explanation.txt.txt ================================================ We have to count the number of components in the complement graph. We also need a way to query if two vertices are connected. We will also maintain a set of all unvisited vertices. Pick up the first vertex in the unvisited set. Erase it Keep traversing the unvisited set till there is a vertex with which there is no edge and then repeat ----- Why does this work ? It looks like it should time out since we are going through the whole unvisited set for each vertex. Let us count the number of times we will pick a vertex from the unvisited set. We perform two operations 1. Pick up a vertex 2. Skip it and go to next element in the set There are N vertices in the set and each will be picked one time, after which it will be erased. How many times do we pick a vertex and skip it ? We will skip a vertex only if it has an edge with the current vertex. Since there are M edges, we can perform at most M skips. So the number of 'touches' we do to the unvisited set is O(N + M) We do N steps of Type 1 and at most M steps of Type 2 Each has a O(log N) factor Had to optimise the constant factor so used an adjacency vector instead of adjacency set. ----- set unvisited; vector graph[MAX_N]; vector > components; void dfs(int v) { unvisited.erase(v); //C.push_back(v); components.back().push_back(v); for(auto it = unvisited.begin(); it != unvisited.end(); ) { if(binary_search(graph[v].begin(), graph[v].end(), (*it))) { it++; } else { int child = *it; dfs(child); it = unvisited.lower_bound(child); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } for(int i = 1; i <= no_of_vertices; i++) { unvisited.insert(i); sort(graph[i].begin(), graph[i].end()); } while(unvisited.size() > 0) { int v = *(unvisited.begin()); vector C; components.push_back(C); dfs(v); } cout << components.size() << "\n"; for(int c = 0; c < components.size(); c++) { cout << components[c].size() << " "; for(int v : components[c]) { cout << v << " "; } cout << "\n"; } return 0; } ================================================ FILE: 2021/Practice/Explanations/Game of Stones Explanation.txt.txt ================================================ ## Grundy Revision - The grundy number of a state from which we cannot make a move is $0$. - The grundy number of a state is the $mex$ of the grundy numbers of the states it can transition to. - The reason is that it is similar to a pile with that many stones. We can either take some stones or add stones but not leave it as it is. - NIM does not change if we are allowed to add stones. --- ## Grundy Number of $(N, Mask)$ - Let $g(n, m)$ be the grundy number of a pile with $n$ stones and $m$ represents a bitmask where the $i$-th bit is set if we are allowed to take $i$ stones from the pile - When we take $i$ stones from a pile, the size of the pile becomes $(n - i)$ and the mask also does not have the $i$-th bit set anymore. - We can find out the $g(n, 111 ... 1)$ and find the answer by taking the XOR of all the piles. ## Why is this practical $?$ - The bitmasks can be as large as $2^{60}$ so how can we compute them $?$ - We will do it recursively and only evaluate those states which we need. - Suppose we take a stone of size $25$ from $60$, not only does the size of the pile reduce to $35$, the eligible moves is also at most $35$, so all bits in $[36, 60]$ will be removed. - This is a great optimisation and allows us to find the grundy of the states quickly. ----- map < pair , int > grundy; int is_bit_set(long long n, int bit) { return ( (n & (1LL << bit)) != 0); } long long unset(long long n, int bit) { n ^= (1LL << bit); return n; } int get_grundy(int n, long long mask) { //Not possible to take more than N from this pile - Bits are 0 indexed for(int higher_bit = n; higher_bit < MAX_BIT; higher_bit++) { if(is_bit_set(mask, higher_bit)) { mask = unset(mask, higher_bit); } } //cout << "State(" << n << "," << mask << ")\n"; pair pair_here = make_pair(n, mask); if(grundy.find(pair_here) != grundy.end()) { return grundy[pair_here]; } vector visited(MAX_BIT, false); for(int bit = 0; bit < n; bit++) { if(is_bit_set(mask, bit)) { long long new_mask = unset(mask, bit); int new_state = get_grundy(n - bit - 1, new_mask); //cout << "Visited " << new_state << "\n"; visited[new_state] = true; } } int mex = 0; for(int bit = 0; bit < MAX_BIT; bit++) { if( visited[bit]) { continue; } mex = bit; break; } grundy[pair_here] = mex; return grundy[pair_here]; } int main() { int no_of_piles; cin >> no_of_piles; grundy[make_pair(0, 0)] = 0; int pile_xor = 0; for(int i = 1; i <= no_of_piles; i++) { int x; cin >> x; pile_xor ^= get_grundy(x, (1LL << x) - 1); } int second_player_win = (pile_xor == 0); cout << (second_player_win ? "YES" : "NO") << "\n"; return 0; } ================================================ FILE: 2021/Practice/Explanations/Lost Tree Explanation.txt.txt ================================================ Let us root the tree at 1. There will be some vertices at an odd distance from 1 and some at an even distance No 2 vertices of the same parity are connected. Otherwise, it would lead to a cycle. If we know the neighbours of any one parity (odd or even), we know the neighbours of the other parity too. One of these sets will have <= N/2 elements. We will choose the set with lower cardinality. ----- The reason this works is because trees are bipartite due to the absence of any cycle (of odd length, particularly). We are partitioning it into 2 sets and asking questions with the smaller set. ----- void ask(int v, vector &D, int n) { cout << "? " << v << "\n"; cout.flush(); for(int i = 1; i <= n; i++) { cin >> D[i]; } } void add_neighbours(int v, vector &D, vector > &T) { for(int i = 2; i < D.size(); i++) { if(D[i] == 1) { T[v].push_back(i); } } } int main() { int no_of_vertices; cin >> no_of_vertices; vector > tree(no_of_vertices + 1); vector > parity(2); vector distance(no_of_vertices + 1); ask(1, distance, no_of_vertices); add_neighbours(1, distance, tree); for(int i = 2; i <= no_of_vertices; i++) { parity[distance[i]%2].push_back(i); } vector chosen = (parity[0].size() < parity[1].size() ? parity[0] : parity[1]); for(int v : chosen) { ask(v, distance, no_of_vertices); add_neighbours(v, distance, tree); } cout << "!\n"; for(int i = 1; i <= no_of_vertices; i++) { for(int v : tree[i]) { cout << i << " " << v << "\n"; } } return 0; } ================================================ FILE: 2021/Practice/Explanations/Maximum Absurdity Explanation.txt.txt ================================================ Let us first solve the problem for 1 segment. Let f1(i) be the maximum segment of length i ending on or before i f1(i) = max{f1(i - 1), sum[i - k + 1, i]} ---- Now, we will iterate over every possible beginning of the second segment. If the second segment starts at i, the value is sum[i, i + k - 1] We will match it with f1(i - 1) Best_value(i) = f1(i - 1) + sum[i, i + k - 1] ----- We will choose the maximum of Best_value through the array Since we need to give a and b and not just the maximum value, store the best possible a in another array parallelly best_a(i) holds the best a for any segment ending on or before i ----- int main() { int no_of_elements, segment_length; cin >> no_of_elements >> segment_length; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector sum_till(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = A[i] + sum_till[i - 1]; } vector best_segment_1_till(no_of_elements + 1); vector best_a(no_of_elements + 1); for(int i = segment_length; i <= no_of_elements; i++) { long long this_segment = sum_till[i] - sum_till[i - segment_length]; best_segment_1_till[i] = best_segment_1_till[i - 1]; best_a[i] = best_a[i - 1]; if(this_segment > best_segment_1_till[i - 1]) { best_a[i] = i - segment_length + 1; best_segment_1_till[i] = this_segment; } } long long answer = 0, a, b; for(int i = segment_length + 1; i + segment_length - 1 <= no_of_elements; i++) { long long segment_2 = sum_till[i + segment_length - 1] - sum_till[i - 1]; //cout << "i = " << i << " 1 = " << best_segment_1_till[i - 1] << " 2 = " << segment_2 << "\n"; if(best_segment_1_till[i - 1] + segment_2 > answer) { answer = best_segment_1_till[i - 1] + segment_2; a = best_a[i - 1]; b = i; } } cout << a << " " << b << "\n"; return 0; } ================================================ FILE: 2021/Practice/Programs/Anton and Making Potions.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_potions, no_of_spells_1, no_of_spells_2; cin >> no_of_potions >> no_of_spells_1 >> no_of_spells_2; long long time, money; cin >> time >> money; vector < pair > reduction(no_of_spells_1 + 1); for(int i = 1; i <= no_of_spells_1; i++) { cin >> reduction[i].second; } for(int i = 1; i <= no_of_spells_1; i++) { cin >> reduction[i].first; } reduction[0].first = 0, reduction[0].second = time; sort(reduction.begin(), reduction.end()); vector < pair > creation(no_of_spells_2 + 1); vector creation_cost(no_of_spells_2 + 1); for(int i = 1; i <= no_of_spells_2; i++) { cin >> creation[i].second; } for(int i = 1; i <= no_of_spells_2; i++) { cin >> creation[i].first; creation_cost[i] = creation[i].first; } sort(creation.begin(), creation.end()); sort(creation_cost.begin(), creation_cost.end()); vector prefix_max(no_of_spells_2 + 1); for(int i = 1; i <= no_of_spells_2; i++) { prefix_max[i] = max(prefix_max[i - 1], creation[i].second); //cout << "At i = " << i << " Creation Cost = " << creation[i].first << " Creation = " << creation[i].second << " Best = " << prefix_max[i] << "\n"; } long long best_time = time*no_of_potions; for(int i = 0; i <= no_of_spells_1; i++) { if(reduction[i].first > money) { break; } long long remaining_money = max(0LL, money - reduction[i].first); int index; int left = 0, right = creation_cost.size() - 1; if(creation_cost[right] <= remaining_money) { index = right; } else { while(right - left > 1) { int mid = (left + right)/2; if(creation_cost[mid] > remaining_money) { right = mid; } else { left = mid; } } index = left; } long long new_potions = prefix_max[index], new_time = reduction[i].second; long long remaining_potions = max(0LL, no_of_potions - new_potions); long long time_here = (remaining_potions*new_time); best_time = min(best_time, time_here); } cout << best_time << "\n"; return 0; } ================================================ FILE: 2021/Practice/Programs/Anton and Tree.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 2e5 + 5; vector graph[MAX_N]; vector colour(MAX_N); vector component(MAX_N); vector component_graph[MAX_N]; int ceil(int n, int d) { return (n/d) + (n%d != 0); } void dfs_component(int v, int parent_v, int component_no) { component[v] = component_no; for(int child_v : graph[v]) { if(child_v != parent_v && colour[child_v] == colour[v]) { dfs_component(child_v, v, component_no); } } } int get_component_graph_diameter(int n) { const int oo = 1e9; /*for(int i = 1; i <= n; i++) { cout << "Children of " << i << " : "; for(int child_v : component_graph[i]) { cout << child_v << " "; } cout << "\n"; }*/ int root = 1; vector distance(n + 1, oo); distance[root] = 0; queue Q; Q.push(root); while(Q.size() > 0) { int v = Q.front(); Q.pop(); for(int child_v : component_graph[v]) { if(distance[v] + 1 < distance[child_v]) { distance[child_v] = distance[v] + 1; Q.push(child_v); } } } for(int i = 1; i <= n; i++) { if(distance[i] > distance[root]) { root = i; } } for(int i = 1; i <= n; i++) { distance[i] = oo; } distance[root] = 0; Q.push(root); while(Q.size() > 0) { int v = Q.front(); Q.pop(); for(int child_v : component_graph[v]) { //cout << child_v << " is a child of " << v << "\n"; if(distance[v] + 1 < distance[child_v]) { distance[child_v] = distance[v] + 1; Q.push(child_v); } } } int diameter = 0; for(int i = 1; i <= n; i++) { diameter = max(diameter, distance[i]); //cout << "Component " << i << " has distance " << distance[i] << "\n"; } return diameter; } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1; i <= no_of_vertices; i++) { cin >> colour[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } int component_no = 0; for(int i = 1; i <= no_of_vertices; i++) { if(component[i] == 0) { dfs_component(i, 0, ++component_no); } } for(int i = 1; i <= no_of_vertices; i++) { for(int child : graph[i]) { int child_component = component[child], this_component = component[i]; if(child_component != this_component) { //cout << "Edge " << child_component << " and " << this_component << "\n"; component_graph[this_component].push_back(child_component); component_graph[child_component].push_back(this_component); } } } int diameter = get_component_graph_diameter(component_no); int answer = ceil(diameter, 2); cout << answer << "\n"; return 0; } ================================================ FILE: 2021/Practice/Programs/Counter Attack.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 5e5 + 5; set unvisited; vector graph[MAX_N]; vector > components; void dfs(int v) { unvisited.erase(v); //C.push_back(v); components.back().push_back(v); for(auto it = unvisited.begin(); it != unvisited.end(); ) { if(binary_search(graph[v].begin(), graph[v].end(), (*it))) { it++; } else { int child = *it; dfs(child); it = unvisited.lower_bound(child); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } for(int i = 1; i <= no_of_vertices; i++) { unvisited.insert(i); sort(graph[i].begin(), graph[i].end()); } while(unvisited.size() > 0) { int v = *(unvisited.begin()); vector C; components.push_back(C); dfs(v); } cout << components.size() << "\n"; for(int c = 0; c < components.size(); c++) { cout << components[c].size() << " "; for(int v : components[c]) { cout << v << " "; } cout << "\n"; } return 0; } ================================================ FILE: 2021/Practice/Programs/Game of Stones.cpp ================================================ #include #include #include using namespace std; const int MAX_BIT = 63; map < pair , int > grundy; int is_bit_set(long long n, int bit) { return ( (n & (1LL << bit)) != 0); } long long unset(long long n, int bit) { n ^= (1LL << bit); return n; } int get_grundy(int n, long long mask) { //Not possible to take more than N from this pile - Bits are 0 indexed for(int higher_bit = n; higher_bit < MAX_BIT; higher_bit++) { if(is_bit_set(mask, higher_bit)) { mask = unset(mask, higher_bit); } } //cout << "State(" << n << "," << mask << ")\n"; pair pair_here = make_pair(n, mask); if(grundy.find(pair_here) != grundy.end()) { return grundy[pair_here]; } vector visited(MAX_BIT, false); for(int bit = 0; bit < n; bit++) { if(is_bit_set(mask, bit)) { long long new_mask = unset(mask, bit); int new_state = get_grundy(n - bit - 1, new_mask); //cout << "Visited " << new_state << "\n"; visited[new_state] = true; } } int mex = 0; for(int bit = 0; bit < MAX_BIT; bit++) { if( visited[bit]) { continue; } mex = bit; break; } grundy[pair_here] = mex; return grundy[pair_here]; } int main() { int no_of_piles; cin >> no_of_piles; grundy[make_pair(0, 0)] = 0; int pile_xor = 0; for(int i = 1; i <= no_of_piles; i++) { int x; cin >> x; pile_xor ^= get_grundy(x, (1LL << x) - 1); } int second_player_win = (pile_xor == 0); cout << (second_player_win ? "YES" : "NO") << "\n"; return 0; } ================================================ FILE: 2021/Practice/Programs/Lost Tree.cpp ================================================ #include #include using namespace std; void ask(int v, vector &D, int n) { cout << "? " << v << "\n"; cout.flush(); for(int i = 1; i <= n; i++) { cin >> D[i]; } } void add_neighbours(int v, vector &D, vector > &T) { for(int i = 2; i < D.size(); i++) { if(D[i] == 1) { T[v].push_back(i); } } } int main() { int no_of_vertices; cin >> no_of_vertices; vector > tree(no_of_vertices + 1); vector > parity(2); vector distance(no_of_vertices + 1); ask(1, distance, no_of_vertices); add_neighbours(1, distance, tree); for(int i = 2; i <= no_of_vertices; i++) { parity[distance[i]%2].push_back(i); } vector chosen = (parity[0].size() < parity[1].size() ? parity[0] : parity[1]); for(int v : chosen) { ask(v, distance, no_of_vertices); add_neighbours(v, distance, tree); } cout << "!\n"; for(int i = 1; i <= no_of_vertices; i++) { for(int v : tree[i]) { cout << i << " " << v << "\n"; } } return 0; } ================================================ FILE: 2021/Practice/Programs/Maximum Absurdity.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, segment_length; cin >> no_of_elements >> segment_length; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector sum_till(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = A[i] + sum_till[i - 1]; } vector best_segment_1_till(no_of_elements + 1); vector best_a(no_of_elements + 1); for(int i = segment_length; i <= no_of_elements; i++) { long long this_segment = sum_till[i] - sum_till[i - segment_length]; best_segment_1_till[i] = best_segment_1_till[i - 1]; best_a[i] = best_a[i - 1]; if(this_segment > best_segment_1_till[i - 1]) { best_a[i] = i - segment_length + 1; best_segment_1_till[i] = this_segment; } } long long answer = 0, a, b; for(int i = segment_length + 1; i + segment_length - 1 <= no_of_elements; i++) { long long segment_2 = sum_till[i + segment_length - 1] - sum_till[i - 1]; //cout << "i = " << i << " 1 = " << best_segment_1_till[i - 1] << " 2 = " << segment_2 << "\n"; if(best_segment_1_till[i - 1] + segment_2 > answer) { answer = best_segment_1_till[i - 1] + segment_2; a = best_a[i - 1]; b = i; } } cout << a << " " << b << "\n"; return 0; } ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Explanations/Good Pairs Explanation.txt.txt ================================================ Let us take the minimum and maximum elements of this array A[i] - A[1] + A[n] - A[i] = A[n] - A[i] ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int minimum = 1, maximum = 1; for(int i = 1; i <= no_of_elements; i++) { if(A[i] >= A[maximum]) { maximum = i; } else if(A[i] < A[minimum]) { minimum = i; } } cout << minimum << " " << maximum << "\n"; } ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Explanations/Make Equal with Mod Explanation.txt.txt ================================================ Notice that we can never change a 0 or 1 If there is a 0 or 1, it will remain 0 or 1 throughout all the operations that we do. The next observation to make is that we can set every element = 0 We can start with the largest element and make all elements = 0 by choosing x = max of the current array This works, except when there is a 1 in the array ----- When there is a 1 in the array, we can follow a similar algorithm and set all elements = 1, by choosing X = Array Max - 1 at each step The only exception is when we have 2 consecutive elements. When we have 2 consecutive elements, we can never make both elements = 1 We will finish at a situation where m = 1 and m + 1 = 2 or m = 0 and m + 1 = 2 In both cases, we can not make 0 or 2 = 1 by any operation Now, it is impossible. ------ It is impossible when there is a 1 in the array and there are consecutive elements in the array Otherwise, we can make all elements = 0 or 1 depending on whether the array has a 1 or not. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector present(3, false); for(int i = 1; i <= no_of_elements; i++) { if(A[i] <= 2) { present[A[i]] = true; } } int possible = true; if(present[1]) { sort(A.begin(), A.end()); for(int i = 1; i + 1 <= no_of_elements; i++) { if(A[i] + 1 == A[i + 1]) { possible = false; break; } } } cout << (possible ? "Yes" : "No") << "\n"; } ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Explanations/Subtract Operations Explanation.txt ================================================ Suppose we subtract the whole array by X in the first step Each A2[i] = A[i] - x Suppose we subtract the whole array by Y = A2[j] in the second step Each A3[i] = A2[i] - Y = (A[i] - X) - (A[j] - X) Where A[i], A2[i] and A3[i] represent the state of A[i] at time 1, 2, 3 respectively X gets cancelled out twice. Every operation cancels out everything that was subtracted in the previous step. What we will be left with in the end is the difference of 2 elements A[i] - A[j] We have to check if there is a pair who's difference is K in the original array. ------ void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map present; for(int i = 1; i <= no_of_elements; i++) { present[A[i]] = true; } int possible = false; for(int i = 1; i <= no_of_elements; i++) { if(present[A[i] - k] || present[A[i] + k]) { possible = true; break; } } cout << (possible ? "Yes" : "No") << "\n"; } ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Programs/Good Pairs.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int minimum = 1, maximum = 1; for(int i = 1; i <= no_of_elements; i++) { if(A[i] >= A[maximum]) { maximum = i; } else if(A[i] < A[minimum]) { minimum = i; } } cout << minimum << " " << maximum << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Programs/K-good.cpp ================================================ #include #include #include using namespace std; long long get_odd_part(long long n) { while(n%2 == 0) { n = n >> 1; } return n; } void solve() { long long n; cin >> n; if(n%2 == 1) { cout << "2\n"; return; } long long original_n = n; long long odd_part = 1, even_part = 1; while(n%2 != 1) { n = n >> 1; even_part *= 2; } odd_part = n; //cout << "E = " << even_part << " O = " << odd_part << "\n"; if(odd_part == 1) { cout << "-1\n"; return; } cout << min(2*even_part, odd_part) << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Programs/Make Equal With Mod.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector present(3, false); for(int i = 1; i <= no_of_elements; i++) { if(A[i] <= 2) { present[A[i]] = true; } } int possible = true; if(present[1]) { sort(A.begin(), A.end()); for(int i = 1; i + 1 <= no_of_elements; i++) { if(A[i] + 1 == A[i + 1]) { possible = false; break; } } } cout << (possible ? "Yes" : "No") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; }   ================================================ FILE: 2022/Contests/Combined Divisions/CodeTON/Programs/Subtract Operation.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, k; cin >> no_of_elements >> k; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map present; for(int i = 1; i <= no_of_elements; i++) { present[A[i]] = true; } int possible = false; for(int i = 1; i <= no_of_elements; i++) { if(present[A[i] - k] || present[A[i] + k]) { possible = true; break; } } cout << (possible ? "Yes" : "No") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/766/Programs/Not Adding.cpp ================================================ #include #include #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_N = 1e6 + 5; vector is_present(MAX_N, false); for(int i = 1; i <= no_of_elements; i++) { is_present[A[i]] = true; } vector multiple_gcd(MAX_N, 0); for(int i = 1; i < MAX_N; i++) { for(int multiple = i; multiple < MAX_N; multiple += i) { if(is_present[multiple]) { multiple_gcd[i] = __gcd(multiple_gcd[i], multiple); } } } int new_elements = 0; for(int i = 1; i < MAX_N; i++) { if(!is_present[i] && multiple_gcd[i] == i) { new_elements++; } } cout << new_elements << "\n"; return 0; } ================================================ FILE: 2022/Contests/Div 2/766/Programs/Not Assigning.cpp ================================================ #include #include #include #include using namespace std; int other(int p) { return (p + 1)%2; } void dfs(vector < vector > &T, int parent_v, int v, map , int> &weight, int parity) { for(int child_v : T[v]) { if(child_v == parent_v) { continue; } int x = v, y = child_v; if(x > y) { swap(x, y); } weight[make_pair(x, y)] = (parity == 0 ? 2 : 3); dfs(T, v, child_v, weight, other(parity)); } } void solve() { int no_of_vertices; cin >> no_of_vertices; int no_of_edges = no_of_vertices - 1; vector > edges; vector > tree(no_of_vertices + 1); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); if(u > v) { swap(u, v); } edges.push_back(make_pair(u, v)); } int possible = true; int root = 1; for(int i = 1; i <= no_of_vertices; i++) { if(tree[i].size() >= 3) { possible = false; break; } if(tree[i].size() == 1) { root = i; } } if(!possible) { cout << "-1\n"; return; } map , int > edge_weight; dfs(tree, 0, root, edge_weight, 0); for(pair edge : edges) { cout << edge_weight[edge] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/766/Programs/Not Shading.cpp ================================================ #include #include using namespace std; void solve() { int rows, columns, x, y; cin >> rows >> columns >> x >> y; vector grid(rows); for(int i = 0; i < rows; i++) { cin >> grid[i]; } x--; y--; int answer = -1; int black_count = 0, black_row_count = 0, black_column_count = 0; for(int r = 0; r < rows; r++) { for(int c = 0; c < columns; c++) { if(grid[r][c] == 'B') { black_count++; if(r == x) { black_row_count++; } if(c == y) { black_column_count++; } } } } if(grid[x][y] == 'B') { answer = 0; } else if(black_row_count > 0 || black_column_count > 0) { answer = 1; } else if(black_count > 0) { answer = 2; } else { answer = -1; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/766/Programs/Not Sitting.cpp ================================================ #include #include #include using namespace std; void solve() { int rows, columns; cin >> rows >> columns; vector distances; int row_distance = 0, column_distance = 0; for(int r = 1; r <= rows; r++) { for(int c = 1; c <= columns; c++) { row_distance = max(rows - r, r - 1); column_distance = max(columns - c, c - 1); distances.push_back(row_distance + column_distance); } } sort(distances.begin(), distances.end()); for(int d : distances) { cout << d << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Explanations/Meximum Array Explanation.txt ================================================ We need the lexicographically maximum sequence. This means that we must be choosing the largest element whenever possible. We will choose the Mex of the entire array at every given point in time. If there are multiple MEX, we will look at the ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector frequency(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } int array_mex = 0; for(int i = 0; i <= no_of_elements; i++) { if(frequency[i] == 0) { array_mex = i; break; } } set all_elements, unseen; for(int i = 0; i <= array_mex; i++) { all_elements.insert(i); } unseen = all_elements; vector answer; int mex_after_here = array_mex; for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]--; if(unseen.find(A[i]) != unseen.end()) { unseen.erase(A[i]); } if(frequency[A[i]] == 0) { mex_after_here = min(mex_after_here, A[i]); } if(*(unseen.begin()) == array_mex) { answer.push_back(array_mex); array_mex = mex_after_here; unseen = all_elements; } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i] << " "; } cout << "\n"; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/Download More RAM.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, present_RAM; cin >> no_of_elements >> present_RAM; vector > ram(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> ram[i].first; } for(int i = 0; i < no_of_elements; i++) { cin >> ram[i].second; } sort(ram.begin(), ram.end()); int answer = present_RAM; for(int i = 0; i < no_of_elements; i++) { if(ram[i].first <= answer) { answer += ram[i].second; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/GCD Arrays.cpp ================================================ #include #include #include using namespace std; int odd_till(int n) { return (n/2) + n%2; } void solve() { int left, right, no_of_operations; cin >> left >> right >> no_of_operations; int odd_integers = odd_till(right) - odd_till(left - 1); cout << (no_of_operations >= odd_integers || (left == right && left != 1) ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/Game On Sum Easy Version.cpp ================================================ #include #include using namespace std; long long power_mod(long long x, long long power, long long m) { long long result = 1; while(power > 0) { if(power%2 == 1) result = (result*x)%m; x = (x*x)%m; power = power >> 1; } return result; } long long inverse(long long x, long long m) { return power_mod(x, m - 2, m); } void solve() { long long no_of_moves, add_moves, range; cin >> no_of_moves >> add_moves >> range; const int MOD = 1e9 + 7; vector > score(no_of_moves + 1, vector (add_moves + 1, 0)); for(int i = 0; i <= no_of_moves; i++) { for(int j = 0; j <= add_moves; j++) { if(i == 0 || j == 0) { score[i][j] = 0; continue; } if(j == i) { score[i][j] = (range*j)%MOD; continue; } score[i][j] = (score[i - 1][j - 1] + score[i - 1][j])%MOD; score[i][j] *= inverse(2, MOD); score[i][j] %= MOD; //cout << "F(" << i << "," << j << ") = " << score[i][j] << "\n"; } } cout << score[no_of_moves][add_moves] << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/Game on Sum Hard Version.cpp ================================================ #include #include using namespace std; const int MOD = 1e9 + 7, MAX_N = 1e6 + 5; long long factorial[MAX_N], inverse_factorial[MAX_N]; long long power_mod(long long x, long long power, long long m) { long long result = 1; while(power > 0) { if(power%2 == 1) result = (result*x)%m; x = (x*x)%m; power = power >> 1; } return result; } long long inverse(long long x, long long m) { return power_mod(x, m - 2, m); } void precompute() { factorial[0] = 1; for(int i = 1; i < MAX_N; i++) { factorial[i] = (i*factorial[i - 1])%MOD; } inverse_factorial[MAX_N - 1] = inverse(factorial[MAX_N - 1], MOD); for(int i = MAX_N - 2; i >= 0; i--) { inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } } long long choose(long long n, long long r) { long long numerator = factorial[n]; long long inverse_denominator = (inverse_factorial[r]*inverse_factorial[n - r])%MOD; return (numerator*inverse_denominator)%MOD; } void solve() { long long no_of_moves, add_moves, range; cin >> no_of_moves >> add_moves >> range; const int MOD = 1e9 + 7; long long score = 0; if(add_moves == no_of_moves) { cout << (range*add_moves)%MOD << "\n"; return; } for(int i = 1; i <= add_moves; i++) { long long base_case = (i*range)%MOD; long long total_moves = no_of_moves - i; long long total_free_moves = total_moves - 1; long long total_side_moves = add_moves - i; base_case *= choose(total_free_moves, total_side_moves); base_case %= MOD; long long power_2 = power_mod(2, total_moves, MOD); //cout << "i = " << i << " Number of paths = C(" << total_free_moves <<"," << total_side_moves << ") = " << choose(total_free_moves, total_side_moves) << " 2^i = " << power_2 << "\n"; long long contribution = (base_case*inverse(power_2, MOD))%MOD; score += contribution; score %= MOD; } cout << score << "\n"; } int main() { precompute(); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/Grid XOR.cpp ================================================ #include #include using namespace std; const int BLACK = 0, WHITE = 1; int get_colour(int x, int y) { return (x + y)%2; } int is_inside(int i, int j, int rows, int columns) { return (1 <= i && i <= rows && 1 <= j && j <= columns); } int get_xor_sum(vector > &G, int n, int colour) { vector > counted(n + 1, vector (n + 1, false)); const int NO_OF_NEIGHBOURS = 4; int next_x[NO_OF_NEIGHBOURS] = {-1, 0, 0, 1}, next_y[NO_OF_NEIGHBOURS] = {0, 1, -1, 0}; int xor_sum = 0; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(get_colour(i, j) != colour) { continue; } int counted_neighbours = 0; for(int k = 0; k < NO_OF_NEIGHBOURS; k++) { int next_i = i + next_x[k], next_j = j + next_y[k]; if(is_inside(next_i, next_j, n, n) && counted[next_i][next_j]) { counted_neighbours++; } } if(counted_neighbours == 0) { xor_sum ^= G[i][j]; for(int k = 0; k < NO_OF_NEIGHBOURS; k++) { int next_i = i + next_x[k], next_j = j + next_y[k]; if(is_inside(next_i, next_j, n, n)) { counted[next_i][next_j] = true; } } } } } return xor_sum; } void solve() { int n; cin >> n; vector > grid(n + 1, vector (n + 1, 0)); for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { cin >> grid[i][j]; } } int answer = get_xor_sum(grid, n, BLACK)^get_xor_sum(grid, n, WHITE); cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/Meximum Array.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector frequency(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } int array_mex = 0; for(int i = 0; i <= no_of_elements; i++) { if(frequency[i] == 0) { array_mex = i; break; } } set all_elements, unseen; for(int i = 0; i <= array_mex; i++) { all_elements.insert(i); } unseen = all_elements; vector answer; int mex_after_here = array_mex; for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]--; if(unseen.find(A[i]) != unseen.end()) { unseen.erase(A[i]); } if(frequency[A[i]] == 0) { mex_after_here = min(mex_after_here, A[i]); } if(*(unseen.begin()) == array_mex) { answer.push_back(array_mex); array_mex = mex_after_here; unseen = all_elements; } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/767/Programs/Peculiar Movie Preferences.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int is_palindrome(string &S) { for(int i = 0; i < S.size(); i++) { if(S[i] != S[S.size() - 1 - i]) { return false; } } return true; } int check_self(vector &S, int n) { for(int i = 1; i <= n; i++) { if(is_palindrome(S[i])) { return true; } } return false; } int check_full_concatenation(vector &S, int n) { map is_present; for(int i = 1; i <= n; i++) { string reverse_s = S[i]; reverse(all(reverse_s)); if(is_present[reverse_s]) { return true; } is_present[S[i]] = true; } return false; } int check_length_3(vector &S, int n) { map is_present; for(int i = 1; i <= n; i++) { if(S[i].size() == 3) { continue; } if(S[i].size() == 1) { is_present[S[i]] = true; continue; } string last; last += S[i][1]; if(is_present[last]) { return true; } } is_present.clear(); for(int i = n; i >= 1; i--) { if(S[i].size() == 3) { continue; } if(S[i].size() == 1) { is_present[S[i]] = true; continue; } string last; last += S[i][0]; if(is_present[last]) { return true; } } return false; } int check_length_4(vector &S, int n) { map is_present; for(int i = 1; i <= n; i++) { if(S[i].size() == 2) { continue; } if(S[i].size() == 1) { is_present[S[i]] = true; continue; } if(S[i][0] == S[i][1]) { string last; last += S[i][2]; if(is_present[last]) { return true; } } } is_present.clear(); for(int i = n; i >= 1; i--) { if(S[i].size() == 2) { continue; } if(S[i].size() == 1) { is_present[S[i]] = true; continue; } if(S[i][1] == S[i][2]) { string last; last += S[i][0]; if(is_present[last]) { return true; } } } return false; } int check_length_5(vector &S, int n) { map is_present; for(int i = 1; i <= n; i++) { if(S[i].size() == 1) { continue; } if(S[i].size() == 2) { is_present[S[i]] = true; continue; } string last; last += S[i][2]; last += S[i][1]; if(is_present[last]) { return true; } } is_present.clear(); for(int i = n; i >= 1; i--) { if(S[i].size() == 1) { continue; } if(S[i].size() == 2) { is_present[S[i]] = true; continue; } string last; last += S[i][1]; last += S[i][0]; if(is_present[last]) { return true; } } return false; } void solve() { int no_of_elements; cin >> no_of_elements; vector S(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> S[i]; } int has_awesome_sequence = check_self(S, no_of_elements) || check_full_concatenation(S, no_of_elements) || check_length_3(S, no_of_elements) || check_length_4(S, no_of_elements) || check_length_5(S, no_of_elements); cout << (has_awesome_sequence ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/777/Programs/Madoka and Math Dad.cpp ================================================ #include #include using namespace std; void solve() { int sum; cin >> sum; string answer; for(int i = 0, s = 0; i + 3 <= sum; i += 3, s += 3) { answer += "21"; } switch(sum%3) { case 2 : answer += "2"; break; case 1 : if(sum == 1) { answer = "1"; } else { answer = "1" + answer; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; }   ================================================ FILE: 2022/Contests/Div 2/777/Programs/Makoda and Childish Pranks.cpp ================================================ #include #include using namespace std; const int NO_OF_NEIGHBOURS = 4; const char BLACK = '1', WHITE = '0'; int X[NO_OF_NEIGHBOURS] = {-1, 0, 0, 1}, Y[NO_OF_NEIGHBOURS] = {0, 1, -1, 0}; struct rectangle { int x1, y1, x2, y2; rectangle(int X1, int Y1, int X2, int Y2) { x1 = X1 + 1; y1 = Y1 + 1; x2 = X2 + 1; y2 = Y2 + 1; } }; void solve() { int no_of_rows, no_of_columns; cin >> no_of_rows >> no_of_columns; vector grid(no_of_rows); for(int i = 0; i < no_of_rows; i++) { cin >> grid[i]; } if(grid[0][0] == BLACK) { cout << "-1\n"; return; } vector moves; for(int i = no_of_rows - 1; i >= 0; i--) { for(int j = no_of_columns - 1; j >= 0; j--) { if(grid[i][j] == BLACK) { if(j > 0) { moves.push_back(rectangle(i, j - 1, i, j)); } else if(i > 0) { moves.push_back(rectangle(i - 1, j, i, j)); } } } } cout << moves.size() << "\n"; for(rectangle current_rectangle : moves) { cout << current_rectangle.x1 << " " << current_rectangle.y1 << " " << current_rectangle.x2 << " " << current_rectangle.y2 << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/778/Explanations/Alice and the Cake Explanation.txt.txt ================================================ Notice that the sum of the whole set remains invariant through the process. Begin at the initial cake, and perform the operation on the largest piece presently in the set. If the largest element is already present in the original, then discard it and move on to the next greatest element. If the largest element in our set is smaller than the largest element we have not yet reached in the given array, it is not possible. ---- Please note that it is not possible to begin with the final array and greedily merge the smallest two elements and see if we finish at the final array Here is the counter example - 6 1 1 1 1 1 1 Step 1 - 2 1 1 1 1 Step 2 - 2 2 1 1 Step 3 - 2 2 2 Step 4 - 4 2 Step 5 - Not possible But, actually Step 1 - 2 1 1 1 1 Step 2 - 3 1 1 1 Step 3 - 3 2 1 Step 4 - 3 3 Step 5 - 6 It is possible It is not always optimal to merge smallest 2 ------ void solve() { int no_of_elements; cin >> no_of_elements; long long sum = 0, minimum = 1e12, maximum = 0; multiset S, original_S; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; original_S.insert(A[i]); sum += A[i]; minimum = min(minimum, A[i]); maximum = max(maximum, A[i]); } S.insert(sum); int possible = true; while(S.size() > 0 && *(S.begin()) >= minimum && *(S.rbegin()) >= *(original_S.rbegin())) { auto it1 = (S.rbegin()); long long x = *it1; if(original_S.count(x) > 0) { original_S.erase(original_S.find(x)); S.erase(S.find(x)); continue; } S.erase(S.find(x)); long long new_x = x/2, new_y = x/2 + (x%2 != 0); S.insert(new_x); S.insert(new_y); } possible = (S.size() == 0); cout << (possible ? "YES" : "NO") << "\n"; } ================================================ FILE: 2022/Contests/Div 2/778/Explanations/Maximum Cake Tastiness Explanation.txt ================================================ We can always perform an operation to make any two elements adjacent. It is always better to make the greatest 2 elements neighbours The answer is the sum of the 2 largest elements. ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin() + 1, A.end()); reverse(A.begin() + 1, A.end()); long long sum = A[1] + A[2]; cout << sum << "\n"; } ================================================ FILE: 2022/Contests/Div 2/778/Explanations/Prefix Removals Explanation.txt.txt ================================================ Let us look at the first element, which does not occur again in the string. This element can never be removed. Every element before can be removed by continuously performing operations of length 1. ----- void solve() { string S; cin >> S; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS + 1, 0); for(int i = 0; i < S.size(); i++) { frequency[S[i] - 'a']++; } int start = 0; for(int i = 0; i < S.size(); i++) { if(frequency[S[i] - 'a'] == 1) { start = i; break; } frequency[S[i] - 'a']--; } string answer; for(int i = start; i < S.size(); i++) { answer += S[i]; } cout << answer << "\n"; } ================================================ FILE: 2022/Contests/Div 2/778/Programs/Alice and the Cake.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; long long sum = 0, minimum = 1e12, maximum = 0; multiset S, original_S; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; original_S.insert(A[i]); sum += A[i]; minimum = min(minimum, A[i]); maximum = max(maximum, A[i]); } S.insert(sum); int possible = true; while(S.size() > 0 && *(S.begin()) >= minimum && *(S.rbegin()) >= *(original_S.rbegin())) { auto it1 = (S.rbegin()); long long x = *it1; if(original_S.count(x) > 0) { original_S.erase(original_S.find(x)); S.erase(S.find(x)); continue; } S.erase(S.find(x)); long long new_x = x/2, new_y = x/2 + (x%2 != 0); S.insert(new_x); S.insert(new_y); } possible = (S.size() == 0); cout << (possible ? "YES" : "NO") << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/778/Programs/Maximum Cake Tastiness.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin() + 1, A.end()); reverse(A.begin() + 1, A.end()); long long sum = A[1] + A[2]; cout << sum << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/778/Programs/Prefix Removals.cpp ================================================ #include #include #include using namespace std; void solve() { string S; cin >> S; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS + 1, 0); for(int i = 0; i < S.size(); i++) { frequency[S[i] - 'a']++; } int start = 0; for(int i = 0; i < S.size(); i++) { if(frequency[S[i] - 'a'] == 1) { start = i; break; } frequency[S[i] - 'a']--; } string answer; for(int i = start; i < S.size(); i++) { answer += S[i]; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/789/Explanation/Tokitsukaze and All Zero Sequence Explanation.txt.txt ================================================ If there is even one 0 in the array, we can make all non-0 elements = 0 in 1 move each. If there is at least one pair of equal elements, we can create a 0 in 1 move and make the other elements 0 in (n - 1) moves. Otherwise, we will two elements, make them equal in one move and then use n moves from the case above. Total = (n + 1) moves here. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); int non_zero = 0, equal_pairs = 0; for(int i = 1; i <= no_of_elements; i++) { if(A[i] > 0) { non_zero++; } if(i < no_of_elements && A[i] == A[i + 1]) { equal_pairs++; } } int answer = 0; if(non_zero < no_of_elements) { answer = non_zero; } else if(equal_pairs > 0) { answer = no_of_elements; } else { answer = no_of_elements + 1; } cout << answer << "\n"; } ================================================ FILE: 2022/Contests/Div 2/789/Explanation/Tokitsukaze and Good 01-String (easy version) Explanation.txt.txt ================================================ Keep track of the length of the current segment. If the segment size is odd, then flip the border element. ----- void solve() { int no_of_elements; cin >> no_of_elements; string S; cin >> S; int minimum_changes = 0; int current_segment = 1; for(int i = 1; i < S.size(); i++) { if(S[i] != S[i - 1]) { if(current_segment%2 == 1) { S[i] = flip(S[i]); minimum_changes++; current_segment = 2; } else { current_segment = 1; } } else { current_segment++; } } cout << minimum_changes << "\n"; } ================================================ FILE: 2022/Contests/Div 2/789/Explanation/Tokitsukaze and Strange Inequality Explanation.txt ================================================ Whenever we have to count tuples or triplets, the main idea is to fix the middle and then find each half. In this, let us try to fix the pair [b, c] How do we count the number of tuples (a, b, c, d) when [b, c] is fixed ? ----- To do this, let us see the candidates for a and d ? All elements in [1, b - 1] which are smaller than A[c] can be 'a'. All elements in [c + a, d] which are smaller than A[b] can be 'd'. The number of tuples here is a_candidates x d_candidates. ----- Now, how do we calculate the number of elements in [1, b - 1] smaller than A[c] for every pair (b, c) ? Let us imagine that we have an empty array - B We will insert the elements of A in B in their index, one by one - in ascending order. For example, if A = {5, 3, 6, 1, 4, 2} B = {0, 0, 0, 0, 0, 0} {0, 0, 0, 1, 0, 0} {0, 0, 0, 1, 0, 2} {0, 3, 0, 1, 0, 2} {0, 3, 0, 1, 4, 2} {5, 3, 0, 1, 4, 2} {5, 3, 6, 1, 4, 2} We will insert the elements one by one and use it to precalculate Prefix_smaller(b, c) and Suffix_smaller(b, c) for every pair (b, c) in the array. ---- Suppose we insert A[i] at position i We will do the following - 1. First, let c = i Then iterate over all b in [1, i - 1] and count the number of inserted elements. 2. Then, let b = i Then iterate over all c in [i + 1, n] and count the number of inserted elements. ----- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); vector index(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; index[A[i]] = i; } for(int b = 1; b <= no_of_elements; b++) { for(int c = b + 1; c <= no_of_elements; c++) { prefix_smaller[b][c] = suffix_smaller[b][c] = 0; } } vector prefix_insertions(no_of_elements + 1, 0); for(int element = 1; element <= no_of_elements; element++) { for(int i = index[element]; i <= no_of_elements; i++) { prefix_insertions[i]++; } for(int c = index[element], b = 1; b < c; b++) { prefix_smaller[b][c] = prefix_insertions[b - 1]; } for(int b = index[element], c = b + 1; c <= no_of_elements; c++) { suffix_smaller[b][c] = prefix_insertions[no_of_elements] - prefix_insertions[c]; } } long long answer = 0; for(int b = 2; b + 2 <= no_of_elements; b++) { for(int c = b + 1; c + 1 <= no_of_elements; c++) { long long no_of_a = prefix_smaller[b][c], no_of_d = suffix_smaller[b][c]; answer += no_of_a*no_of_d; } } cout << answer << "\n"; } ================================================ FILE: 2022/Contests/Div 2/789/Programs/Tokitsukaze and Good 01-String (easy version).cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; char flip(char ch) { return (ch == '0' ? '1' : '0'); } void solve() { int no_of_elements; cin >> no_of_elements; string S; cin >> S; int minimum_changes = 0; int current_segment = 1; for(int i = 1; i < S.size(); i++) { if(S[i] != S[i - 1]) { if(current_segment%2 == 1) { S[i] = flip(S[i]); minimum_changes++; current_segment = 2; } else { current_segment = 1; } } else { current_segment++; } } cout << minimum_changes << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/789/Programs/Tokitsukaze and Strange Inequality.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 5005; int prefix_smaller[MAX_N][MAX_N], suffix_smaller[MAX_N][MAX_N]; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); vector index(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; index[A[i]] = i; } for(int b = 1; b <= no_of_elements; b++) { for(int c = b + 1; c <= no_of_elements; c++) { prefix_smaller[b][c] = suffix_smaller[b][c] = 0; } } vector prefix_insertions(no_of_elements + 1, 0); for(int element = 1; element <= no_of_elements; element++) { for(int i = index[element]; i <= no_of_elements; i++) { prefix_insertions[i]++; } for(int c = index[element], b = 1; b < c; b++) { prefix_smaller[b][c] = prefix_insertions[b - 1]; } for(int b = index[element], c = b + 1; c <= no_of_elements; c++) { suffix_smaller[b][c] = prefix_insertions[no_of_elements] - prefix_insertions[c]; } } long long answer = 0; for(int b = 2; b + 2 <= no_of_elements; b++) { for(int c = b + 1; c + 1 <= no_of_elements; c++) { long long no_of_a = prefix_smaller[b][c], no_of_d = suffix_smaller[b][c]; answer += no_of_a*no_of_d; } } cout << answer << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/792/Explanations/AvtoBus Explanation.txt ================================================ When we want to maximize the number of buses, we will try to maximise the number of 4's. While trying to minimize, we will try to maximize the number of 6's. There is no answer possible if N = 1, 3 (mod 4). There are only 2 cases where an answer exists. N = 0, 2 (mod 4) ----- void solve() { long long no_of_wheels; cin >> no_of_wheels; long long minimum, maximum; switch(no_of_wheels%4) { case 0: maximum = no_of_wheels/4; minimum = 2*(no_of_wheels/12) + (no_of_wheels%12 == 6 ? (no_of_wheels%12)/6 : (no_of_wheels%12)/4); break; case 2: if(no_of_wheels == 2) { cout << "-1\n"; return; } maximum = 1 + (no_of_wheels - 6)/4; no_of_wheels -= 6; minimum = 1 + 2*(no_of_wheels/12) + (no_of_wheels%12 == 6 ? (no_of_wheels%12)/6 : (no_of_wheels%12)/4); break; default: cout << "-1\n"; return; } cout << minimum << " " << maximum << "\n"; } ================================================ FILE: 2022/Contests/Div 2/792/Explanations/Rooks Defenders Explanation.txt.txt ================================================ When a rook is placed on cell (x, y) it covers the whole row x and column y. For every cell (x, y) in X1 < x < X and Y1 < y < Y2 to be covered, either 1. All the rows should be covered. 2. All the columns should be covered. Suppose both these conditions are not true, then there is at least one cell (x, y) such that row x and column c are not covered. ----- Maintain 2 Arrays of length N representing - 1. R[i] - Is row i covered 2. C[j] - Is column j covered We will update and find the sums of these ranges using segment trees. Each query is answers in O(log n) time. ---- void update(int n, int left, int right, int index, int value, int tree_index) { if(index < left || right < index) { return; } if(left == right) { sum_tree[n][tree_index] = value; //cout << (tree_index == 0 ? "Row" : "Column") << " Sum Tree [" << left << "," << right << "] = " << sum_tree[n][tree_index] << "\n"; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, index, value, tree_index); update(RIGHT(n), mid + 1, right, index, value, tree_index); sum_tree[n][tree_index] = sum_tree[LEFT(n)][tree_index] + sum_tree[RIGHT(n)][tree_index]; //cout << (tree_index == 0 ? "Row" : "Column") << " Sum Tree [" << left << "," << right << "] = " << sum_tree[n][tree_index] << "\n"; } int get_sum(int n, int left, int right, int query_left, int query_right, int tree_index) { if(query_right < left || right < query_left) { return 0; } if(query_left <= left && right <= query_right) { return sum_tree[n][tree_index]; } int mid = (left + right)/2; int left_sum = get_sum(LEFT(n), left, mid, query_left, query_right, tree_index); int right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right, tree_index); return (left_sum + right_sum); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n, no_of_queries; cin >> n >> no_of_queries; memset(sum_tree, 0, sizeof(sum_tree)); const int ROW = 0, COLUMN = 1; vector row_attackers(n + 1, 0), column_attackers(n + 1, 0); for(int i = 1; i <= no_of_queries; i++) { const int ADD = 1, REMOVE = 2, RECTANGLE = 3; int query; cin >> query; switch(query) { case ADD: { int x, y; cin >> x >> y; row_attackers[x]++; if(row_attackers[x] == 1) { update(1, 1, n, x, 1, ROW); } column_attackers[y]++; if(column_attackers[y] == 1) { update(1, 1, n, y, 1, COLUMN); } } break; case REMOVE : { int x, y; cin >> x >> y; row_attackers[x]--; if(row_attackers[x] == 0) { update(1, 1, n, x, 0, ROW); } column_attackers[y]--; if(column_attackers[y] == 0) { update(1, 1, n, y, 0, COLUMN); } } break; case RECTANGLE :{ int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2; if(x1 > x2) { swap(x1, x2); } if(y1 > y2) { swap(y1, y2); } int attacked_rows = get_sum(1, 1, n, x1, x2, ROW); int attacked_columns = get_sum(1, 1, n, y1, y2, COLUMN); //cout << "Rows attacked = " << attacked_rows << " Columns attacked = " << attacked_columns << "\n"; int every_cell_attacked = ( (attacked_rows == x2 - x1 + 1) || (attacked_columns == y2 - y1 + 1) ); cout << (every_cell_attacked ? "Yes" : "No") << "\n"; } } } return 0; } ================================================ FILE: 2022/Contests/Div 2/792/Explanations/Stone Age Problem Explanation.txt.txt ================================================ The trick to this problem is to keep track of time. Keep an array T, recording the time that an element was touched. Also keep track of the last bulk update. When doing a point update, check whether - 1. T[i] > last_bulk_update_time If yes, then the value at A[i], is A[i] 2. Else, the value at A[i] is the last bulk_update_value ----- int main() { int no_of_elements, no_of_queries; cin >> no_of_elements >> no_of_queries; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long sum = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; } int last_replace_all_time = -1, last_replace_all_value = 0; vector last_touched(no_of_elements + 1, 0); for(int i = 1; i <= no_of_queries; i++) { const int REPLACE_ONE = 1, REPLACE_ALL = 2; int query, index, value; cin >> query; switch(query) { case REPLACE_ONE: cin >> index >> value; if(last_touched[index] > last_replace_all_time) { sum += (value - A[index]); } else { sum += (value - last_replace_all_value); } A[index] = value; last_touched[index] = i; break; case REPLACE_ALL: cin >> value; sum = no_of_elements*1LL*value; last_replace_all_value = value; last_replace_all_time = i; } cout << sum << "\n"; } return 0; } ================================================ FILE: 2022/Contests/Div 2/792/Programs/AvtoBus.cpp ================================================ #include #include using namespace std; void solve() { long long no_of_wheels; cin >> no_of_wheels; long long minimum, maximum; switch(no_of_wheels%4) { case 0: maximum = no_of_wheels/4; minimum = 2*(no_of_wheels/12) + (no_of_wheels%12 == 6 ? (no_of_wheels%12)/6 : (no_of_wheels%12)/4); break; case 2: if(no_of_wheels == 2) { cout << "-1\n"; return; } maximum = 1 + (no_of_wheels - 6)/4; no_of_wheels -= 6; minimum = 1 + 2*(no_of_wheels/12) + (no_of_wheels%12 == 6 ? (no_of_wheels%12)/6 : (no_of_wheels%12)/4); break; default: cout << "-1\n"; return; } cout << minimum << " " << maximum << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 2/792/Programs/Rooks Defenders.cpp ================================================ #include #include #include using namespace std; #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 1e5 + 5; int sum_tree[3*MAX_N][2]; void update(int n, int left, int right, int index, int value, int tree_index) { if(index < left || right < index) { return; } if(left == right) { sum_tree[n][tree_index] = value; //cout << (tree_index == 0 ? "Row" : "Column") << " Sum Tree [" << left << "," << right << "] = " << sum_tree[n][tree_index] << "\n"; return; } int mid = (left + right)/2; update(LEFT(n), left, mid, index, value, tree_index); update(RIGHT(n), mid + 1, right, index, value, tree_index); sum_tree[n][tree_index] = sum_tree[LEFT(n)][tree_index] + sum_tree[RIGHT(n)][tree_index]; //cout << (tree_index == 0 ? "Row" : "Column") << " Sum Tree [" << left << "," << right << "] = " << sum_tree[n][tree_index] << "\n"; } int get_sum(int n, int left, int right, int query_left, int query_right, int tree_index) { if(query_right < left || right < query_left) { return 0; } if(query_left <= left && right <= query_right) { return sum_tree[n][tree_index]; } int mid = (left + right)/2; int left_sum = get_sum(LEFT(n), left, mid, query_left, query_right, tree_index); int right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right, tree_index); return (left_sum + right_sum); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int n, no_of_queries; cin >> n >> no_of_queries; memset(sum_tree, 0, sizeof(sum_tree)); const int ROW = 0, COLUMN = 1; vector row_attackers(n + 1, 0), column_attackers(n + 1, 0); for(int i = 1; i <= no_of_queries; i++) { const int ADD = 1, REMOVE = 2, RECTANGLE = 3; int query; cin >> query; switch(query) { case ADD: { int x, y; cin >> x >> y; row_attackers[x]++; if(row_attackers[x] == 1) { update(1, 1, n, x, 1, ROW); } column_attackers[y]++; if(column_attackers[y] == 1) { update(1, 1, n, y, 1, COLUMN); } } break; case REMOVE : { int x, y; cin >> x >> y; row_attackers[x]--; if(row_attackers[x] == 0) { update(1, 1, n, x, 0, ROW); } column_attackers[y]--; if(column_attackers[y] == 0) { update(1, 1, n, y, 0, COLUMN); } } break; case RECTANGLE :{ int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2; if(x1 > x2) { swap(x1, x2); } if(y1 > y2) { swap(y1, y2); } int attacked_rows = get_sum(1, 1, n, x1, x2, ROW); int attacked_columns = get_sum(1, 1, n, y1, y2, COLUMN); //cout << "Rows attacked = " << attacked_rows << " Columns attacked = " << attacked_columns << "\n"; int every_cell_attacked = ( (attacked_rows == x2 - x1 + 1) || (attacked_columns == y2 - y1 + 1) ); cout << (every_cell_attacked ? "Yes" : "No") << "\n"; } } } return 0; }   ================================================ FILE: 2022/Contests/Div 2/792/Programs/Stone Age Problem.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, no_of_queries; cin >> no_of_elements >> no_of_queries; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long sum = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; } int last_replace_all_time = -1, last_replace_all_value = 0; vector last_touched(no_of_elements + 1, 0); for(int i = 1; i <= no_of_queries; i++) { const int REPLACE_ONE = 1, REPLACE_ALL = 2; int query, index, value; cin >> query; switch(query) { case REPLACE_ONE: cin >> index >> value; if(last_touched[index] > last_replace_all_time) { sum += (value - A[index]); } else { sum += (value - last_replace_all_value); } A[index] = value; last_touched[index] = i; break; case REPLACE_ALL: cin >> value; sum = no_of_elements*1LL*value; last_replace_all_value = value; last_replace_all_time = i; } cout << sum << "\n"; } return 0; } ================================================ FILE: 2022/Contests/Div 2/809/Programs/Qpwoeirut And The City.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const long long oo = 1e18; vector minimum_cost(no_of_elements + 1, oo), maximum_coverage(no_of_elements + 1, 0); for(int i = 2; i <= no_of_elements - 1; i++) { long long amount_here = max(0, max(A[i - 1], A[i + 1]) + 1 - A[i]); if(i < 4) { minimum_cost[i] = amount_here; maximum_coverage[i] = 1; } else if(i >= 4) { //minimum_cost[i] = amount_here + min(minimum_cost[i - 2], minimum_cost[i - 3]); if(maximum_coverage[i - 3] == maximum_coverage[i - 2] && minimum_cost[i - 3] < minimum_cost[i - 2]) { minimum_cost[i] = amount_here + minimum_cost[i - 3]; maximum_coverage[i] = maximum_coverage[i - 3] + 1; } else { minimum_cost[i] = amount_here + minimum_cost[i - 2]; maximum_coverage[i] = maximum_coverage[i - 2] + 1; } } //cout << "F(" << i << ") = " << minimum_cost[i] << "\n"; } long long answer; if(maximum_coverage[no_of_elements - 1] == maximum_coverage[no_of_elements - 2]) { answer = min(minimum_cost[no_of_elements - 1], minimum_cost[no_of_elements - 2]); } else { answer = (maximum_coverage[no_of_elements - 1] > maximum_coverage[no_of_elements - 2] ? minimum_cost[no_of_elements - 1] : minimum_cost[no_of_elements - 2]); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; }   ================================================ FILE: 2022/Contests/Div 3/828/Programs/Divisibility by 2^n.cpp ================================================ #include #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; int power_2(int n) { int power = 0; while(n%2 == 0 && n > 0) { power++; n /= 2; } return power; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector index_power(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { index_power[i] = power_2(i); } sort(all(index_power)); reverse(all(index_power)); int total_power = 0; for(int i = 1; i <= no_of_elements; i++) { total_power += power_2(A[i]); } int no_of_operations = 0; for(int i = 1; i <= no_of_elements && total_power < no_of_elements && index_power[i] > 0; i++) { total_power += index_power[i]; no_of_operations++; } const int NOT_POSSIBLE = -1; cout << (total_power < no_of_elements ? NOT_POSSIBLE : no_of_operations) << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 3/828/Programs/Divisible Numbers Easy Version.cpp ================================================ #include #include #include #include using namespace std; void solve() { long long a, b, c, d; cin >> a >> b >> c >> d; long long answer_x = -1, answer_y = -1; for(long long x = a + 1; x <= c; x++) { long long complement = (a*b)/__gcd(a*b, x); //cout << "X = " << x << " Complement = " << complement << "\n"; long long y = complement; for(int i = 1; y <= b; i++) { y = i*complement; } //cout << "Y = " << y << "\n"; if(y <= d) { answer_x = x, answer_y = y; break; } } cout << answer_x << " " << answer_y << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 3/828/Programs/Even-Odd Increments.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements, no_of_queries; cin >> no_of_elements >> no_of_queries; long long even_sum = 0, odd_sum = 0; long long even_count = 0, odd_count = 0; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; if(A[i]%2 == 0) { even_sum += A[i]; even_count++; } else if(A[i]%2 == 1) { odd_sum += A[i]; odd_count++; } } for(int i = 1; i <= no_of_queries; i++) { const int ADD_EVEN = 0, ADD_ODD = 1; long long query, value; cin >> query >> value; switch(query) { case ADD_EVEN : { if(value%2 == 0) { even_sum += even_count*value; } else { even_sum += even_count*value; odd_sum += even_sum; even_sum = 0; odd_count += even_count; even_count = 0; } break; } case ADD_ODD : { if(value%2 == 0) { odd_sum += odd_count*value; } else { odd_sum += odd_count*value; even_sum += odd_sum; odd_sum = 0; even_count += odd_count; odd_count = 0; } break; } } cout << even_sum + odd_sum << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 3/828/Programs/Number Replacement.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { cin >> A[i]; } string S; cin >> S; map dictionary; int possible = true; for(int i = 0; i < S.size(); i++) { if(dictionary[A[i]] != 0) { if(dictionary[A[i]] != S[i]) { possible = false; break; } } dictionary[A[i]] = S[i]; } cout << (possible ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Div 3/828/Programs/Traffic Light.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements; char symbol; cin >> no_of_elements >> symbol; string S; cin >> S; const char GREEN = 'g'; int first_green = 0; for(int i = 0; i < no_of_elements; i++) { if(S[i] == GREEN) { first_green = i; break; } } const int NO_GREEN_TO_RIGHT = -1; vector nearest_green(no_of_elements + 1, NO_GREEN_TO_RIGHT); for(int i = no_of_elements - 1; i >= 0; i--) { nearest_green[i] = (S[i] == GREEN ? i : nearest_green[i + 1]); if(nearest_green[i] == NO_GREEN_TO_RIGHT) { nearest_green[i] = first_green; } //cout << "nearest green " << i << " = " << nearest_green[i] << "\n"; } int answer = 0; for(int i = 0; i < no_of_elements; i++) { if(S[i] == symbol) { int distance = (nearest_green[i] >= i ? nearest_green[i] - i : S.size() - i + first_green); answer = max(answer, distance); } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Round 125/Explanations/By Gamers For Gamers Explanation.txt ================================================ Let us consider a monster (D, H) and a unit (d, h). Time taken by monster to kill 1 unit = h/D Time taken by unit to kill monster = H/d We need to ensure that the time taken by the monster is strictly more than the time we take to kill the monster h/D > H/d h*d > H*D We can treat all the monsters as products (D x H) For a given unit, we need to find the minimum integer c, such that h x (c x d) > H x D ----- Another condition is that c <= C/C[i] ----- Now, instead of checking the amount of damage a monster can take, let us try to calculate the maximum product we can reach with C[i] coins Maximum_product[C[i]] = max(H[i] x D[i]) initially The key insight to propagate this DP is that we can buy multiple sets of the same unit If we buy C coin sets of the i-th unit Maximum_product[C[i] x C] = max(C x H[i] X D[i]) ----- We can then binary search the answer for each query ----- int main() { int no_of_elements, max_cost; cin >> no_of_elements >> max_cost; vector cost(no_of_elements + 1), damage(no_of_elements + 1), health(no_of_elements + 1); vector max_product(max_cost + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> cost[i] >> damage[i] >> health[i]; max_product[cost[i]] = max(max_product[cost[i]], damage[i]*health[i]); } for(int c = 1; c <= max_cost; c++) { for(int coin_sets = 1; c*1LL*coin_sets <= max_cost; coin_sets++) { max_product[c*coin_sets] = max(max_product[c*coin_sets], max_product[c]*coin_sets); } } vector max_product_till(max_cost + 1); for(int i = 1; i <= max_cost; i++) { max_product_till[i] = max(max_product[i], max_product_till[i - 1]); } int no_of_monsters; cin >> no_of_monsters; for(int i = 1; i <= no_of_monsters; i++) { long long damage_here, health_here; cin >> damage_here >> health_here; long long product = damage_here*health_here; int minimum_coins = upper_bound(all(max_product_till), product) - max_product_till.begin(); cout << (minimum_coins <= max_cost ? minimum_coins : -1) << "\n"; } return 0; } ================================================ FILE: 2022/Contests/Educational Round 125/Explanations/Integer Moves Explanation.txt.txt ================================================ We can always reach (x, y) in at most 2 moves If we are at the origin, then we need 0 moves If (x^2 + y^2) is a perfect square, then we need only 1 move Otherwise, we will go from (0, 0) -> (x, 0) -> (y, 0) in 2 moves ! We will always need at most 2 moves ! ------ int is_square(int n) { for(int i = 1; i*i <= n; i++) { if(i*i == n) { return true; } } return false; } void solve() { int x, y; cin >> x >> y; int answer = 0; if(x == 0 && y == 0) { answer = 0; } else if(is_square(x*x + y*y)) { answer = 1; } else { answer = 2; } cout << answer << "\n"; } ================================================ FILE: 2022/Contests/Educational Round 125/Explanations/XY Sequence Explanation.txt.txt ================================================ Be greedy and Set A[i] = A[i] + X, unless it exceeds the limit ------ void solve() { int no_of_elements, x, y, max_limit; cin >> no_of_elements >> max_limit >> x >> y; long long sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { if(A[i - 1] + x <= max_limit) { A[i] = A[i - 1] + x; } else { A[i] = A[i - 1] - y; } sum += A[i]; } cout << sum << "\n"; } ================================================ FILE: 2022/Contests/Educational Round 125/Programs/Bracket Sequence Deletion.cpp ================================================ #include #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; int minimum_moves = 0, remaining = length; for(int i = 0; i + 1 < length; i++) { if(S[i] == '(') { minimum_moves++; remaining -= 2; i++; } else if(S[i] == ')') { int j = i + 1; while(j < length && S[j] != ')') { j++; } if(j == length) { break; } minimum_moves++; remaining -= (j - i + 1); //cout << "i = " << i << " j = " << j << "\n"; i = j; } } cout << minimum_moves << " " << remaining << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Round 125/Programs/By Gamers For Gamers.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, max_cost; cin >> no_of_elements >> max_cost; vector cost(no_of_elements + 1), damage(no_of_elements + 1), health(no_of_elements + 1); vector max_product(max_cost + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> cost[i] >> damage[i] >> health[i]; max_product[cost[i]] = max(max_product[cost[i]], damage[i]*health[i]); } for(int c = 1; c <= max_cost; c++) { for(int coin_sets = 1; c*1LL*coin_sets <= max_cost; coin_sets++) { max_product[c*coin_sets] = max(max_product[c*coin_sets], max_product[c]*coin_sets); } } vector max_product_till(max_cost + 1); for(int i = 1; i <= max_cost; i++) { max_product_till[i] = max(max_product[i], max_product_till[i - 1]); } int no_of_monsters; cin >> no_of_monsters; for(int i = 1; i <= no_of_monsters; i++) { long long damage_here, health_here; cin >> damage_here >> health_here; long long product = damage_here*health_here; int minimum_coins = upper_bound(all(max_product_till), product) - max_product_till.begin(); cout << (minimum_coins <= max_cost ? minimum_coins : -1) << "\n"; } return 0; } ================================================ FILE: 2022/Contests/Educational Round 125/Programs/Integer Moves.cpp ================================================ #include using namespace std; int is_square(int n) { for(int i = 1; i*i <= n; i++) { if(i*i == n) { return true; } } return false; } void solve() { int x, y; cin >> x >> y; int answer = 0; if(x == 0 && y == 0) { answer = 0; } else if(is_square(x*x + y*y)) { answer = 1; } else { answer = 2; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Round 125/Programs/XY Sequence.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements, x, y, max_limit; cin >> no_of_elements >> max_limit >> x >> y; long long sum = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { if(A[i - 1] + x <= max_limit) { A[i] = A[i - 1] + x; } else { A[i] = A[i - 1] - y; } sum += A[i]; } cout << sum << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 125/EExplanations/Bracket Sequence Deletion Explanation.txt ================================================ If we meet a ( Then () is a regular balanced string And (( is a palindrome No matter what, (x is always a good string and we will extract it ----- If we meet a ) Then, we cannot get a balanced string since it starts with ) We can only get a palindrome All we need to do is find the next closed bracket ! ) ((((( ... ( ) is a palindrome ! ----- void solve() { int length; string S; cin >> length >> S; int minimum_moves = 0, remaining = length; for(int i = 0; i + 1 < length; i++) { if(S[i] == '(') { minimum_moves++; remaining -= 2; i++; } else if(S[i] == ')') { int j = i + 1; while(j < length && S[j] != ')') { j++; } if(j == length) { break; } minimum_moves++; remaining -= (j - i + 1); //cout << "i = " << i << " j = " << j << "\n"; i = j; } } cout << minimum_moves << " " << remaining << "\n"; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Explanations/Consecutive Points Segment Explanation.txt.txt ================================================ The beginning element is either A[i] - 1, A[i], A[i] + 1 Let us notice that the first element uniquely determines the whole sequence. We will check if any of these 3 options leads to a consecutive segment. ----- int is_possible(vector &A, int n) { for(int i = 1, current = n; i < A.size(); i++, current++) { if(abs(A[i] - current) > 1) { return false; } } return true; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int possible = false; for(int beginning = A[1] - 1; beginning <= A[1] + 1; beginning++) { if(is_possible(A, beginning)) { possible = true; } } cout << (possible ? "Yes" : "No") << "\n"; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Explanations/Dolce Vita Explanation.txt.txt ================================================ Let us keep an array which will tell us the maximum number of times we can buy a prefix of length i Let P[i] be the perfix sum of A[1, ... i] We can buy the prefix for i days if P[i] + (x - 1)i <= Budget We can binary search for the value of x for each array element. ------ After that, we will try to find out the number of times we have bought a segment ending at i, exactly In order to do this, we will notice that we can buy the prefix ending at i no_of_days[i] - no_of_days[i + 1] times. ----- void solve() { int no_of_elements, budget; cin >> no_of_elements >> budget; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin(), A.end()); vector prefix_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = prefix_sum[i - 1] + A[i]; } vector no_of_days_used(no_of_elements + 2, 0); for(int i = 1; i <= no_of_elements; i++) { if(prefix_sum[i] > budget) { break; } long long low = 1, high = 1e9 + 1; while(high - low > 1) { long long mid = (low + high)/2; if(( prefix_sum[i] + (mid - 1)*i ) > budget) { high = mid; } else { low = mid; } } no_of_days_used[i] = low; //cout << "i = " << i << " Days = " << no_of_days_used[i] << "\n"; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer += (no_of_days_used[i] - no_of_days_used[i + 1])*i; } cout << answer << "\n"; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Explanations/Insert a Progression Explanation.txt ================================================ Let the value of the original array be |A[1] - A[2]| + |A[2] - A[3]| + ... + |A[n - 1] - A[n]| Let the smallest and largest element of the array be L and R respectively. ----- Let us notice that if we have an integer x, A[i] < x < A[i + 1], we can place x in between A[i] and A[i + 1] with no change in the cost. (A[i + 1] - x) + (x - A[i]) = A[i + 1] - A[i] ----- We can place all integers in the range [L, R] within the array in such a way that it does not increase the cost. Now, we only need to deal with the prefix [1, L - 1] and the suffix [R + 1, X] There are 3 options for both of these 1. Before the first number 2. After the last number 3. In between two numbers. Suppose we place 1, 2, 3, ... , L - 1 in between A[i - 1] and A[i + 1], let us count the total difference in cost Old Cost = A[i] - A[i - 1] New Cost = A[i] - (L - 1) + (L - 1) - (L - 1) ... - 1 + (A[i - 1] - 1) = (A[i] - 1) + (A[i - 1] - 1) Difference = 2(A[i] - 1) ----- void solve() { int no_of_elements, extra; cin >> no_of_elements >> extra; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long value = 0; long long minimum = A[1], maximum = A[1]; for(int i = 2; i <= no_of_elements; i++) { minimum = min(minimum, A[i]); maximum = max(maximum, A[i]); value += abs(A[i] - A[i - 1]); } if(minimum > 1) { long long minimum_contribution = min(A[1] - 1, A[no_of_elements] - 1); for(int i = 2; i <= no_of_elements; i++) { minimum_contribution = min(minimum_contribution, (A[i] - 1)*2); } value += minimum_contribution; } if(maximum < extra) { long long maximum_contribution = min(extra - A[1], extra - A[no_of_elements]); for(int i = 2; i <= no_of_elements; i++) { maximum_contribution = min(maximum_contribution, (extra - A[i])*2); } value += maximum_contribution; } cout << value << "\n"; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Explanations/String Building Explanation.txt.txt ================================================ If the length of the segment is even, we can just keep using blocks of 2 If the length of the segment is odd, we can use one blocks of 3, after which it is even and reduced to the case above. The only time it is impossible is when the length of the segment is 1. ----- void solve() { string S; cin >> S; int possible = (S.size() == 1 ? false : true); for(int i = 0; i < S.size(); i++) { if(i == 0) { if(S[i] != S[i + 1]) { possible = false; } continue; } if(i + 1 == S.size()) { if(S[i] != S[i - 1]) { possible = false; } break; } if(S[i - 1] != S[i] && S[i] != S[i + 1]) { possible = false; break; } } cout << (possible ? "YES" : "NO") << "\n"; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Programs/Consecutive Points Segment.cpp ================================================ #include #include #include using namespace std; int is_possible(vector &A, int n) { for(int i = 1, current = n; i < A.size(); i++, current++) { if(abs(A[i] - current) > 1) { return false; } } return true; } void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int possible = false; for(int beginning = A[1] - 1; beginning <= A[1] + 1; beginning++) { if(is_possible(A, beginning)) { possible = true; } } cout << (possible ? "Yes" : "No") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Programs/Dolce Vita.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, budget; cin >> no_of_elements >> budget; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(A.begin(), A.end()); vector prefix_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = prefix_sum[i - 1] + A[i]; } vector no_of_days_used(no_of_elements + 2, 0); for(int i = 1; i <= no_of_elements; i++) { if(prefix_sum[i] > budget) { break; } long long low = 1, high = 1e9 + 1; while(high - low > 1) { long long mid = (low + high)/2; if(( prefix_sum[i] + (mid - 1)*i ) > budget) { high = mid; } else { low = mid; } } no_of_days_used[i] = low; //cout << "i = " << i << " Days = " << no_of_days_used[i] << "\n"; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer += (no_of_days_used[i] - no_of_days_used[i + 1])*i; } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Programs/Insert a Progression.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, extra; cin >> no_of_elements >> extra; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } long long value = 0; long long minimum = A[1], maximum = A[1]; for(int i = 2; i <= no_of_elements; i++) { minimum = min(minimum, A[i]); maximum = max(maximum, A[i]); value += abs(A[i] - A[i - 1]); } if(minimum > 1) { long long minimum_contribution = min(A[1] - 1, A[no_of_elements] - 1); for(int i = 2; i <= no_of_elements; i++) { minimum_contribution = min(minimum_contribution, (A[i] - 1)*2); } value += minimum_contribution; } if(maximum < extra) { long long maximum_contribution = min(extra - A[1], extra - A[no_of_elements]); for(int i = 2; i <= no_of_elements; i++) { maximum_contribution = min(maximum_contribution, (extra - A[i])*2); } value += maximum_contribution; } cout << value << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2022/Contests/Educational Rounds/Educational Round 127/Programs/String Building.cpp ================================================ #include using namespace std; void solve() { string S; cin >> S; int possible = (S.size() == 1 ? false : true); for(int i = 0; i < S.size(); i++) { if(i == 0) { if(S[i] != S[i + 1]) { possible = false; } continue; } if(i + 1 == S.size()) { if(S[i] != S[i - 1]) { possible = false; } break; } if(S[i - 1] != S[i] && S[i] != S[i + 1]) { possible = false; break; } } cout << (possible ? "YES" : "NO") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2023/Contests/Div 2/810/Explanations/XOR Triangle Explanation.txt ================================================ 1. Fact - A triangle is good only if the pairwise AND is non-0. Proof - x+y = x^y + 2(x&y) x^y counts all bits which are set either in x or y. x&y counts all bits which are set in both x and y and therefore needs to be multiplied by 2. We also know that if x, y and z form a triangle, then x + y > z Let the integers we choose be (a, b, c) (a^b) + (b^c) = (a^b^b^c) + 2[(a^b)&(b^c)] = (a^b) + (b^c) = (a^c) + 2[(a^b)&(b^c)] (a^b) + (b^c) > (a^c) => (a^b)&(b^c) > 0 We can prove this cyclically for all 3 variables. ----- We have an easier task now. We now have to count the nummber of integers (a, b, c) such that 1 <= a, b, c <= n and 1. (a^b)&(b^c) > 0 2. (b^c)&(c^a) > 0 3. (c^a)&(a^b) > 0 We will use Digit DP with the observation that all of a, b and c will match some prefix of n (possibly of length 0). ----- We will represent the triplet as T[0], T[1], T[2] for convenience instead of (a, b, c). The state of the DP is f(i, prefix_mask, condition_mask). This represents the number of triplets of consisting of the bits [0, i - 1] of N satsifying the two masks. The reason we are using i to represent the triplets ending with [i - 1] bits is because the string is 0-indexed. It might have been more intuitive if it were 1-indexed. Here is the elaborate meaning of each variable. 1. i represents the bit of n where we are at now. 2. prefix_mask is a mask of 3 bits represnting whether each member of the triplet is either = or less than the prefix of [0, i - 1] 3. condition_mask is a mask of 3 bits reprsenting which of 3 conditions is already true in the prefix of length [0, i - 1] Elaborating on how the masks are created. Let us suppose 1. The first [0, i - 1] of T[0] match the first [0, i - 1] bits of N 2. The first [0, i - 1] of T[1] is smaller than N 3. The first [0, i - 1] of T[2] match the first [0, i - 1] bits of N The prefix mask is 101 The condition mask is also similar. A mask of 110 means two of the conditions required for being a good triangle are satisfied. ----- This is a DP where it is easier to calculate the states f(i + 1, _, _) which f(i, _, _) will contribute to then build f(i, _, _) from f(i - 1, _, _) We will iterate over all possibilities of the i-th bit of T[0], T[1], T[2] If the first [0, i - 1] bits of N are equal to the first [0, i - 1] bits of T[0], the i-th bit of T[0] can only be [0, N[i]] If the first [0, i - 1] bits of N are smaller than the first [0, i - 1] bits of T[0], the i-th bit of T[0] can be both 0 or 1. Recalculate the new prefix_mask and new condition_mask and accordingly do f(i + 1, new_prefix_mask, new_condition_mask) += f(i, prefix_mask, condition_mask) ----- Let us discuss the base case and the final answer Let the base case be f(0, 111, 0) = 1 When we consider the empty string, it is not possible for a, b, c to be < N so the prefix mask has to be 111 only. None of the conditions are met so the condition mask be 0 The empty string N corresponds to prefix 111 and condition 0. f(0, _, _) = 0 for all other values. ---- The final answer is when all the bits are used so i = N.size() The prefix mask can be any legal value The condition mask is 111 Answer = Sum f(N.size(), p, 111) over all legal values of prefix_mask ------ Time limit is tight so do some language level optimizations like global arrays. ------ int is_bit_set(int n, int bit) { return ( (n&(1 << bit)) != 0 ); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string S; cin >> S; no_of_triplets[0][MAX_MASK][0] = 1; for(int i = 0; i < S.size(); i++) { int prefix = i - 1; for(int prefix_match = 0; prefix_match <= MAX_MASK; prefix_match++) { for(int condition_met = 0; condition_met <= MAX_MASK; condition_met++) { for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { limit[bit] = (is_bit_set(prefix_match, bit) ? S[i] : '1') - '0'; } for(next_bit[0] = 0; next_bit[0] <= limit[0]; next_bit[0]++) { for(next_bit[1] = 0; next_bit[1] <= limit[1]; next_bit[1]++) { for(next_bit[2] = 0; next_bit[2] <= limit[2]; next_bit[2]++) { for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { triangle_sides[bit] = next_bit[bit]^next_bit[(bit + 1)%NO_OF_TRIANGLE_SIDES]; } int next_prefix_match = 0; for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { if(is_bit_set(prefix_match, bit) && next_bit[bit] == S[i] - '0') { next_prefix_match |= (1 << bit); } } int next_condition_met = 0; for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { int condition_here = (triangle_sides[bit]&triangle_sides[(bit + 1)%NO_OF_TRIANGLE_SIDES] != 0); if(is_bit_set(condition_met, bit) || condition_here) { next_condition_met |= (1 << bit); } } no_of_triplets[i + 1][next_prefix_match][next_condition_met] += no_of_triplets[i][prefix_match][condition_met]; no_of_triplets[i + 1][next_prefix_match][next_condition_met] %= MOD; /*cout << "F(" << i + 1 << "," << next_prefix_match << "," << next_condition_met << ") = " << no_of_triplets[i + 1][next_prefix_match][next_condition_met] << " added " << "F(" << i << "," << prefix_match << "," << condition_met << ") = " << no_of_triplets[i][prefix_match][condition_met] << " Current " << next_bit[0] << " " << next_bit[1] << " " << next_bit[2] << "\n";*/ } } } } } } long long answer = 0; for(int prefix_match = 0, all_conditions_met = MAX_MASK; prefix_match <= MAX_MASK; prefix_match++) { answer += no_of_triplets[S.size()][prefix_match][all_conditions_met]; answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2023/Contests/Div 2/810/Programs/XOR Triangle.cpp ================================================ #include #include using namespace std; const int MOD = 998244353, MAX_N = 2e5 + 5, MAX_MASK = 7, NO_OF_TRIANGLE_SIDES = 3; long long no_of_triplets[MAX_N][MAX_MASK + 1][MAX_MASK + 1]; int limit[NO_OF_TRIANGLE_SIDES], next_bit[NO_OF_TRIANGLE_SIDES], triangle_sides[NO_OF_TRIANGLE_SIDES]; int is_bit_set(int n, int bit) { return ( (n&(1 << bit)) != 0 ); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string S; cin >> S; no_of_triplets[0][MAX_MASK][0] = 1; for(int i = 0; i < S.size(); i++) { int prefix = i - 1; for(int prefix_match = 0; prefix_match <= MAX_MASK; prefix_match++) { for(int condition_met = 0; condition_met <= MAX_MASK; condition_met++) { for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { limit[bit] = (is_bit_set(prefix_match, bit) ? S[i] : '1') - '0'; } for(next_bit[0] = 0; next_bit[0] <= limit[0]; next_bit[0]++) { for(next_bit[1] = 0; next_bit[1] <= limit[1]; next_bit[1]++) { for(next_bit[2] = 0; next_bit[2] <= limit[2]; next_bit[2]++) { for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { triangle_sides[bit] = next_bit[bit]^next_bit[(bit + 1)%NO_OF_TRIANGLE_SIDES]; } int next_prefix_match = 0; for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { if(is_bit_set(prefix_match, bit) && next_bit[bit] == S[i] - '0') { next_prefix_match |= (1 << bit); } } int next_condition_met = 0; for(int bit = 0; bit < NO_OF_TRIANGLE_SIDES; bit++) { int condition_here = (triangle_sides[bit]&triangle_sides[(bit + 1)%NO_OF_TRIANGLE_SIDES] != 0); if(is_bit_set(condition_met, bit) || condition_here) { next_condition_met |= (1 << bit); } } no_of_triplets[i + 1][next_prefix_match][next_condition_met] += no_of_triplets[i][prefix_match][condition_met]; no_of_triplets[i + 1][next_prefix_match][next_condition_met] %= MOD; /*cout << "F(" << i + 1 << "," << next_prefix_match << "," << next_condition_met << ") = " << no_of_triplets[i + 1][next_prefix_match][next_condition_met] << " added " << "F(" << i << "," << prefix_match << "," << condition_met << ") = " << no_of_triplets[i][prefix_match][condition_met] << " Current " << next_bit[0] << " " << next_bit[1] << " " << next_bit[2] << "\n";*/ } } } } } } long long answer = 0; for(int prefix_match = 0, all_conditions_met = MAX_MASK; prefix_match <= MAX_MASK; prefix_match++) { answer += no_of_triplets[S.size()][prefix_match][all_conditions_met]; answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: 2023/Contests/Div 2/857/Programs/Buying Gifts.cpp ================================================ #include #include #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1), B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i] >> B[i]; } vector > prices (no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prices[i].first = A[i]; prices[i].second = B[i]; } sort(prices.begin() + 1, prices.end()); reverse(prices.begin() + 1, prices.end()); vector prefix_max(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_max[i] = max(prefix_max[i - 1], prices[i].second); } const int oo = 2e9 + 9; int answer = oo; set suffix; vector suffix_next_greater(no_of_elements + 1, oo), suffix_next_lesser(no_of_elements + 1, oo); for(int i = no_of_elements; i >= 1; i--) { auto it = suffix.lower_bound(prices[i].first); if(it != suffix.end()) { suffix_next_greater[i] = *it; } if(it != suffix.begin()) { it--; } suffix_next_lesser[i] = *it; suffix.insert(prices[i].second); } for(int i = no_of_elements; i >= 1; i--) { int answer_here = oo; if(i > 1) { answer_here = abs(prices[i].first - prefix_max[i - 1]); } if(suffix_next_greater[i] >= prefix_max[i - 1]) { answer_here = min(answer_here, abs(prices[i].first - suffix_next_greater[i])); } if(suffix_next_lesser[i] >= prefix_max[i - 1]) { answer_here = min(answer_here, abs(prices[i].first - suffix_next_lesser[i])); } answer = min(answer, answer_here); } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; }   ================================================ FILE: 2023/Contests/Div 2/857/Programs/Likes.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int likes = 0, unlikes = 0; for(int i = 1; i <= no_of_elements; i++) { likes += (A[i] > 0); unlikes += (A[i] < 0); } vector maximum_likes(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { if(i <= likes) { maximum_likes[i] = maximum_likes[i - 1] + 1; } else { maximum_likes[i] = maximum_likes[i - 1] - 1; } } vector minimum_likes(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { if( (i + 1)/2 <= unlikes ) { minimum_likes[i] = 1; minimum_likes[i + 1] = 0; i = i + 1; } else { minimum_likes[i] = minimum_likes[i - 1] + 1; } } for(int i = 1; i <= no_of_elements; i++) { cout << maximum_likes[i] << " "; } cout << "\n"; for(int i = 1; i <= no_of_elements; i++) { cout << minimum_likes[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2023/Contests/Div 2/857/Programs/Settlement of Guinea Pigs.cpp ================================================ #include #include using namespace std; void solve() { int no_of_days; cin >> no_of_days; vector event(no_of_days + 1); for(int i = 1; i <= no_of_days; i++) { cin >> event[i]; } const int ADOPT = 1, DOCTOR = 2; int bought_avaries = 0, half_avaries = 0, free_avaries = 0; for(int i = 1; i <= no_of_days; i++) { switch(event[i]) { case ADOPT : { if(free_avaries > 0) { free_avaries--; } else { bought_avaries++; } half_avaries++; break; } case DOCTOR : { int pairs = 0; if(half_avaries%2 == 0) { pairs = (half_avaries - 2)/2; } else { pairs = (half_avaries - 1)/2; } free_avaries += pairs; half_avaries -= 2*pairs; break; } } } cout << bought_avaries << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: 2023/Contests/Div 2/857/Programs/The Very Beautiful Blanket.cpp ================================================ #include #include #include using namespace std; void solve() { int rows, columns; cin >> rows >> columns; vector > M(rows + 1, vector (columns + 1)); for(int i = 1, cell_no = 0; i <= rows; i++) { M[i][1] = cell_no++; M[i][2] = cell_no++; } for(int i = 1; i <= rows; i++) { for(int j = 3; j <= columns; j++) { long long offset = (j << 9); int reference_column = (j%2 == 1 ? 1 : 2); M[i][j] = M[i][reference_column]^offset; M[i][j] = M[i][reference_column]^offset; } } cout << rows*columns << "\n"; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { cout << M[i][j] << " "; } cout << "\n"; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: C Programs/C Programs - 1/Bear_and_Big_Brother.c ================================================ #include int main() { int limak_weight, bob_weight; int year; scanf("%d %d",&limak_weight, &bob_weight); /*Find the first year in which (limak_weight) > (bob_weight). In other words, the first time the condition, limak <= bob fails Counting starts from 0 because we first check the weight of brother at the current moment.*/ for(year = 0; limak_weight <= bob_weight ; year++) { limak_weight = 3*limak_weight; bob_weight = 2*bob_weight; } printf("%d\n",year); return 0; } ================================================ FILE: C Programs/C Programs - 1/Beautiful_Matrix.c ================================================ #include #include #define NO_OF_ROWS 5 #define NO_OF_COLUMNS 5 void read_matrix(short[][NO_OF_COLUMNS],short*, short*); short find_no_of_moves_to_centralise_1(short, short, short, short); int main() { short matrix[NO_OF_ROWS][NO_OF_COLUMNS], row_of_1, column_of_1, no_of_moves_to_centralise_1; read_matrix(matrix, &row_of_1, &column_of_1); //Passing row of 1 and columns of 1 by reference no_of_moves_to_centralise_1 = find_no_of_moves_to_centralise_1(NO_OF_ROWS, NO_OF_COLUMNS,row_of_1, column_of_1); printf("%hu\n",no_of_moves_to_centralise_1); return 0; } void read_matrix(short matrix[][NO_OF_COLUMNS], short *row_of_1, short *column_of_1) //Here, row of 1 and column of 1 are pointers { short i, j; for(i = 0; i #include #define MAXIMUM_DISTINCT_LETTERS 27 //26 + 1 #define USERNAME_SIZE_LIMIT 101 #define ADVICE_SIZE_LIMIT 14 //13+1 #define true 1 #define false 0 void prepare_advisory_message(char[], short); short check_if_username_is_female(char[]); int main() { char message_of_advice[ADVICE_SIZE_LIMIT], username[USERNAME_SIZE_LIMIT]; short is_a_girl; scanf("%s",username); is_a_girl = check_if_username_is_female(username); prepare_advisory_message(message_of_advice, is_a_girl); printf("%s\n",message_of_advice); return 0; } short check_if_username_is_female(char username[]) { char distinct_letters[MAXIMUM_DISTINCT_LETTERS], current_char; short i, j, distinct_count = 0, already_counted; for(i = 0; username[i] != '\0';i++) { current_char = username[i]; already_counted = false; for(j = 0; j < distinct_count; j++) { if(current_char == distinct_letters[j]) { already_counted = true; } } if(already_counted == false) { distinct_letters[distinct_count++] = current_char; } } if(distinct_count %2 == 0) { return true; //It is a girl } else { return false; //It is a boy } } void prepare_advisory_message(char message_of_advice[], short is_a_girl) { if(is_a_girl == true) { strcpy(message_of_advice, "CHAT WITH HER!"); } else { strcpy(message_of_advice, "IGNORE HIM!"); } } ================================================ FILE: C Programs/C Programs - 1/Complicated_GCD.c ================================================ #include #include #define SIZE_LIMIT 102 //100 + 2 extra characters int main() { char first_number[SIZE_LIMIT], last_number[SIZE_LIMIT], gcd[SIZE_LIMIT]; scanf("%s %s",first_number, last_number); if(strcmp(first_number, last_number) == 0)//Stcmp return 0 if both strings are equal { strcpy(gcd,first_number); //gcd(n,n) = n } else { strcpy(gcd, "1"); //Answer is always 1 if there are atleast two numbers. Since any consecutive numbers are coprime. gcd(n, n+1) = 1 } printf("%s\n", gcd); return 0; } ================================================ FILE: C Programs/C Programs - 1/Compote.c ================================================ #include unsigned int min(unsigned int, unsigned int, unsigned int); int main() { unsigned int lemons, apples, pears, answer; scanf("%u %u %u", &lemons, &apples, &pears); /*Lemons, apples and pears have to be in the ratio 1:2:4. There will be k lemons, 2k apples and 4k pears. k = min(lemons, apples/2, pears/4) k is assigned the least of those quantities to ensure we are able to pick k, 2k and 4k from the boxes. Otherwise, the class may not have k, 2k or 4k elements to get chosen for the wrong choice of k. answer = k + 2k + 4k = 7k */ answer = 7*min(lemons, apples>>1, pears>>2); printf("%u\n" ,answer); return 0; } unsigned int min(unsigned int a, unsigned int b, unsigned int c) { if(a < b) { if(a < c) { return a; } else { return c; } } else { if(b < c) { return b; } else { return c; } } } ================================================ FILE: C Programs/C Programs - 1/Dasha_and_Stairs.c ================================================ #include #include #define ANSWER_SIZE 4 int main() { char answer[ANSWER_SIZE]; short no_of_odd_steps, no_of_even_steps; scanf("%hu %hu",&no_of_even_steps, &no_of_odd_steps); if( (no_of_odd_steps - no_of_even_steps <= 1) && (no_of_odd_steps - no_of_even_steps >= -1) ) { if( (no_of_odd_steps == 0) && (no_of_even_steps == 0)) //If both are zero, then the answer is no { strcpy(answer, "NO"); } else { strcpy(answer, "YES"); } } else { strcpy(answer, "NO"); } printf("%s\n",answer); } ================================================ FILE: C Programs/C Programs - 1/Elephant.c ================================================ #include int main() { unsigned long distance, no_of_steps; scanf("%lu", &distance); if(distance%5 == 0) { no_of_steps = distance/5; } else { no_of_steps = (distance/5 + 1); } printf("%lu\n",no_of_steps); return 0; } ================================================ FILE: C Programs/C Programs - 1/Even_Odds.c ================================================ #include int main() { unsigned long long no_of_numbers, position_of_last_odd_number, desired_position, number_at_desired_position; scanf("%I64d %I64d",&no_of_numbers, &desired_position); //The first ceil(n/2) positions are filled with odd numbers and the remaining spots by even numbers if(no_of_numbers%2 == 0) { position_of_last_odd_number = no_of_numbers >> 1; //n/2 } else { position_of_last_odd_number = (no_of_numbers >> 1) + 1;//n/2 + 1 } if(desired_position <= position_of_last_odd_number) //kth position has kth odd number = 2k - 1 { number_at_desired_position = 2*desired_position - 1; } else //kth position has k - ceil(n/2) th even number { number_at_desired_position = 2*(desired_position - position_of_last_odd_number ); } printf("%I64d\n",number_at_desired_position); return 0; } ================================================ FILE: C Programs/C Programs - 1/Fancy_Fence.c ================================================ #include #include #define ANSWER_SIZE 4 void check_if_regular_polygon_exists(int, char [][ANSWER_SIZE], int); int main() { int no_of_test_cases, i, angle; char answers[180][ANSWER_SIZE]; scanf("%d",&no_of_test_cases); for(i = 0; i < no_of_test_cases; i++) { scanf("%d",&angle); check_if_regular_polygon_exists(angle, answers, i); } for(i = 0; i < no_of_test_cases; i++) { printf("%s\n",answers[i]); } return 0; } /* theta = {1 - 2/n}*180, then if n = 360/{180-n} is an integer, a regular polygon exists*/ void check_if_regular_polygon_exists(int angle, char answers[][ANSWER_SIZE], int answer_no) { if(360%(180 - angle) == 0) { strcpy(answers[answer_no], "YES"); } else { strcpy(answers[answer_no], "NO"); } } ================================================ FILE: C Programs/C Programs - 1/Holiday_of_Equality.c ================================================ #include #include unsigned int find_maximum_wealth(unsigned int *, short); unsigned int sum_of_amount_given_to_everyone(unsigned int *, unsigned int, short); int main() { short no_of_citizens, i; unsigned int *wealth_of_citizen, maximum_wealth, amount_distributed; scanf("%hu",&no_of_citizens); wealth_of_citizen = malloc(no_of_citizens*sizeof(unsigned int)); for(i = 0; i < no_of_citizens; i++) { scanf("%u",(wealth_of_citizen + i)); } maximum_wealth = find_maximum_wealth(wealth_of_citizen, no_of_citizens); amount_distributed = sum_of_amount_given_to_everyone(wealth_of_citizen,maximum_wealth, no_of_citizens); printf("%u\n",amount_distributed); free(wealth_of_citizen); return 0; } unsigned int find_maximum_wealth(unsigned int *wealth_of_citizen, short no_of_citizens) { short i; unsigned int max = *(wealth_of_citizen + 0); //First element for(i = 1; i < no_of_citizens; i++) { if(max < *(wealth_of_citizen + i)) { max = *(wealth_of_citizen + i); } } return max; } unsigned int sum_of_amount_given_to_everyone(unsigned int *wealth_of_citizen, unsigned int max, short no_of_citizens) { unsigned int money_given_away = 0; short i; for(i = 0; i < no_of_citizens; i++) { money_given_away += (max - *(wealth_of_citizen + i)); } return money_given_away; } ================================================ FILE: C Programs/C Programs - 1/I_Love_Username.c ================================================ #include #include short find_no_of_amazing_performances(unsigned int *,short); int main() { short no_of_coding_competitions, i, no_of_amazing_performances; scanf("%hu",&no_of_coding_competitions); unsigned int *coder_score_list = malloc(no_of_coding_competitions*sizeof(unsigned int)); for(i = 0; i < no_of_coding_competitions; i++) { scanf("%u",(coder_score_list + i)); } no_of_amazing_performances = find_no_of_amazing_performances(coder_score_list, no_of_coding_competitions); printf("%u\n", no_of_amazing_performances); free(coder_score_list); return 0; } //Go through the array linearly and count the number of times there is a new maxima or minima short find_no_of_amazing_performances(unsigned int *coder_score_list,short no_of_coding_competitions) { unsigned int minimum = *(coder_score_list + 0); unsigned int maximum = *(coder_score_list + 0); short i, no_time_best_or_worst_record_broken = 0; for(i = 0; i < no_of_coding_competitions; i++) { if( *(coder_score_list + i) < minimum) { minimum = *(coder_score_list + i); no_time_best_or_worst_record_broken++; } else if( *(coder_score_list + i) > maximum) { maximum = *(coder_score_list + i); no_time_best_or_worst_record_broken++; } } return no_time_best_or_worst_record_broken ; } ================================================ FILE: C Programs/C Programs - 1/Ilya_Bank_Account.c ================================================ #include #include #define MAXIMUM_NUMBER_SIZE 12 //9 digit number + a sign and then two extra characters just in case void copy_part_of_string(char[], char[], int, int); int main() { char bank_balance[MAXIMUM_NUMBER_SIZE], final_bank_balance[MAXIMUM_NUMBER_SIZE]; short length; scanf("%s",bank_balance); //Checking if balance is positive if(bank_balance[0] != '-') { strcpy(final_bank_balance, bank_balance); } else //Bank balance is negative { length = strlen(bank_balance); //Checking which character is greater among the last and second last and deleting the greater one and keeping the smaller one. if(bank_balance[length - 1] < bank_balance[length - 2]) //Deleting the second last digit { copy_part_of_string(final_bank_balance, bank_balance, 0, length - 3); final_bank_balance[length - 2] = bank_balance[length - 1]; final_bank_balance[length - 1] = '\0'; } else //Deleting the last digit { copy_part_of_string(final_bank_balance, bank_balance, 0, length - 2); final_bank_balance[length - 1] = '\0'; } //Incase, the bank balance becomes zero after deletion. For example, -10 becomes -0. We want it to be just zero. if((strlen(final_bank_balance) == 2) && (final_bank_balance[1] == '0')) { final_bank_balance[0] = '0'; final_bank_balance[1] = '\0'; } } printf("%s\n",final_bank_balance); return 0; } //Copies source{start_index .... end_index] to destination[0 .... end_index-start_index] void copy_part_of_string(char destination[], char source[], int start_index, int end_index) { int i; for(i = 0; i <= (end_index - start_index); i++) { destination[i] = source[start_index + i]; } } ================================================ FILE: C Programs/C Programs - 1/Little_Elephant_Rozdil.c ================================================ #include #include void read_time_taken_to_each_city(unsigned int,unsigned long *); void find_which_city_elephant_goes_to(unsigned int,unsigned long *, unsigned int *,unsigned int *); int main() { unsigned int no_of_cities, no_of_minima, city_with_minimum_time; scanf("%u",&no_of_cities); unsigned long *time_taken_to_city = malloc(no_of_cities*(sizeof(unsigned long))); read_time_taken_to_each_city(no_of_cities, time_taken_to_city); find_which_city_elephant_goes_to(no_of_cities, time_taken_to_city, &city_with_minimum_time, &no_of_minima); //Pass by reference if(no_of_minima > 1) //If there is more than one city with the same minimum time, stay in Rozdil { printf("Still Rozdil\n"); } else //Otherwise, tell the number of the city { printf("%u\n", city_with_minimum_time); } free(time_taken_to_city); return 0; } void read_time_taken_to_each_city(unsigned int no_of_cities,unsigned long *time_taken_to_city) { unsigned int i; for(i = 0; i < no_of_cities; i++) { scanf("%lu",(time_taken_to_city + i)); } } void find_which_city_elephant_goes_to(unsigned int no_of_cities,unsigned long *time_taken_to_city, unsigned int *city_with_minimum_time,unsigned int *no_of_minima) { unsigned int i; //First element is marked as minima initially *city_with_minimum_time = 0; *no_of_minima = 1; for(i = 1; i < no_of_cities; i++) { if( *(time_taken_to_city + i) < *(time_taken_to_city + *(city_with_minimum_time)))//If it is less than minima, change the minima { *city_with_minimum_time = i; *no_of_minima = 1; //Reseting the count of minima } else if( *(time_taken_to_city + i) == *(time_taken_to_city + *(city_with_minimum_time))) { *no_of_minima = *no_of_minima + 1; } } if(*no_of_minima == 1)//If there is only one minima, increment the value of city because we have started counting from 0 rather than 1 { *(city_with_minimum_time) = *(city_with_minimum_time) + 1; } } ================================================ FILE: C Programs/C Programs - 1/Lucky_Division.c ================================================ #include #include #define true 1 #define false 0 #define base 10 short check_if_num_is_lucky(unsigned int); short check_if_num_is_almost_lucky(unsigned int); int main() { unsigned int num; short is_almost_lucky; char answer[4]; scanf("%u",&num); is_almost_lucky = check_if_num_is_almost_lucky(num); if(is_almost_lucky == true) { strcpy(answer, "YES"); } else { strcpy(answer, "NO"); } printf("%s\n",answer); return 0; } short check_if_num_is_lucky(unsigned int num) { short last_digit; for( ;num != 0; num = num/base) //Running through all the digits of num, one by one { last_digit = num%base; if((last_digit != 4) && (last_digit != 7)) { return false; } } return true; } short check_if_num_is_almost_lucky(unsigned int num) { unsigned int i; //Checking if i is a lucky number and if i divides num. for(i = 4; (i <= num); i++) { if(check_if_num_is_lucky(i)) { if(num%i == 0) { return true; } } } return false; } ================================================ FILE: C Programs/C Programs - 1/Memory_and_Crow.c ================================================ #include #include void get_crow_answer(long *, long); void get_original_series(long *, long *, long); void display_original_series(long *,long); int main() { long no_of_numbers; scanf("%ld",&no_of_numbers); long *crow_answer = malloc(no_of_numbers*sizeof(long)); long *original_series = malloc(no_of_numbers*sizeof(long)); get_crow_answer(crow_answer, no_of_numbers); get_original_series(crow_answer, original_series, no_of_numbers); display_original_series(original_series, no_of_numbers); free(crow_answer); free(original_series); return 0; } void get_crow_answer(long *crow_answer, long no_of_numbers) { long i; for(i = 0; i < no_of_numbers; i++) { scanf("%lu",(crow_answer + i)); } } void get_original_series(long *crow_answer, long *original_series, long no_of_numbers) { long i; //B(n) = A(n) For all other i != n, B[i] = A[i] + A[i+1] *(original_series + no_of_numbers - 1) = *(crow_answer + no_of_numbers - 1); for(i = no_of_numbers - 2; i >= 0; i--) { *(original_series + i) = *(crow_answer + i) + *(crow_answer + i + 1); } } void display_original_series(long *original_series, long no_of_numbers) { long i; for(i = 0; i < no_of_numbers; i++) { printf("%ld\t",*(original_series + i)); } } ================================================ FILE: C Programs/C Programs - 1/Nearly_Lucky_Number.c ================================================ #include #include #define true 1 #define false 0 short check_if_nearly_lucky(char[]); int main() { char number[19]; short is_nearly_lucky; scanf("%s",number); is_nearly_lucky = check_if_nearly_lucky(number); if(is_nearly_lucky == true) { printf("YES\n"); } else { printf("NO\n"); } return 0; } short check_if_nearly_lucky(char number[]) { short i, count_of_lucky_digits = 0; for(i = 0; number[i] != '\0'; i++) { if( (number[i] == '4') || (number[i] == '7') ) { count_of_lucky_digits++; } } if( (count_of_lucky_digits == 4) || (count_of_lucky_digits == 7) )//Less than 18 digits are there so these are the only possibilities { return true; } return false; } ================================================ FILE: C Programs/C Programs - 1/Opponents.c ================================================ #include #include #define true 1 #define false 0 #define MAXIMUM_NO_OF_DAYS 100 #define MAXIIMUM_NO_OF_OPPONENTS 100 void make_list_of_aryan_wins(char[][100],short *, short, short); short check_if_aryan_wins_on_a_day(char[], short); void count_no_of_wins_after_last_defeat(short *, short *, short); short find_maximum_consecutive_wins(short *, short); int main() { char opponent_schedule[MAXIMUM_NO_OF_DAYS][MAXIIMUM_NO_OF_OPPONENTS]; short no_of_opponents, no_of_days, maximum_consecutive_wins, i; short *aryan_wins = NULL, *consecutive_wins_after_last_defeat = NULL; //Reading input scanf("%hu %hu ",&no_of_opponents, &no_of_days); aryan_wins = malloc(no_of_days*sizeof(short)); consecutive_wins_after_last_defeat = malloc(no_of_days*sizeof(short)); for(i = 0; i < no_of_days; i++) { scanf("%s",opponent_schedule[i]); } make_list_of_aryan_wins(opponent_schedule, aryan_wins,no_of_days,no_of_opponents); count_no_of_wins_after_last_defeat(consecutive_wins_after_last_defeat,aryan_wins, no_of_days); maximum_consecutive_wins = find_maximum_consecutive_wins(consecutive_wins_after_last_defeat,no_of_days); printf("%hu\n",maximum_consecutive_wins); free(aryan_wins); free(consecutive_wins_after_last_defeat); return 0; } //Aryan wins is a vector such that Win[i] = true if Aryan wins on day i and false otherwise void make_list_of_aryan_wins(char opponent_schedule[][100],short *aryan_wins, short no_of_days, short no_of_opponents) { short i, does_aryan_win; for(i = 0; i < no_of_days; i++) { does_aryan_win = check_if_aryan_wins_on_a_day(opponent_schedule[i], no_of_opponents); if(does_aryan_win == true) { *(aryan_wins + i) = true; } else { *(aryan_wins + i) = false; } } } //Takes the day number, looks at the opponent schedule and predicts if Aryan wins or loses,depending on how many opponents were absent short check_if_aryan_wins_on_a_day(char one_day_opponent_list[], short no_of_opponents) { short i; for(i = 0; i < no_of_opponents; i++) { if(one_day_opponent_list[i] == '0') //If even one of them is absent, Aryan wins { return true; } } return false; } /*A vector where C[i] = k, if on day i, Aryan has k consecutive wins after his most recent defeat. In other words C[i] is his winning Streak on day i*/ void count_no_of_wins_after_last_defeat(short *consecutive_wins_after_last_defeat, short *aryan_wins, short no_of_days) { short i; *(consecutive_wins_after_last_defeat + 0) = *(aryan_wins + 0); for(i = 1; i < no_of_days; i++) { if( *(aryan_wins + i) == true) //If he wins, add it to his winning streak { *(consecutive_wins_after_last_defeat + i) = *(consecutive_wins_after_last_defeat + i - 1) + 1; } else //If he loses, reset his winning streak { *(consecutive_wins_after_last_defeat + i) = 0; } } } short find_maximum_consecutive_wins(short *consecutive_wins_after_last_defeat, short no_of_days) { short i, maximum_consecutive_wins = *(consecutive_wins_after_last_defeat + 0); for(i = 1; i < no_of_days; i++) { if(*(consecutive_wins_after_last_defeat + i) > maximum_consecutive_wins) { maximum_consecutive_wins = *(consecutive_wins_after_last_defeat + i); } } return maximum_consecutive_wins; } ================================================ FILE: C Programs/C Programs - 1/Petr_and_Calendar.c ================================================ #include short find_no_of_calendar_columns(short, short); short find_no_of_days_in(short); int main() { short starting_day, month_no, no_of_days_in_month, answer; scanf("%hu %hu", &month_no, &starting_day); no_of_days_in_month = find_no_of_days_in(month_no); answer = find_no_of_calendar_columns(starting_day, no_of_days_in_month); printf("%u\n",answer); return 0; } short find_no_of_calendar_columns(short starting_day, short no_of_days_in_month) { short answer; /*answer = ceil(no_of_days + starting_day - 1). Since, integer division is performed, there will never be any value after the decimal point to round off. So, the standard function can't be used and 1 has to be added if it's not a multiple of 7.*/ if( (no_of_days_in_month + starting_day - 1) % 7 == 0) { answer = (no_of_days_in_month + starting_day - 1)/7; } else { answer = (no_of_days_in_month + starting_day - 1)/7 + 1; } return answer; } short find_no_of_days_in(short month_no) { short no_of_days; switch(month_no) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: no_of_days = 31; break; case 4: case 6: case 9: case 11: no_of_days = 30; break; case 2 : no_of_days = 28; } return no_of_days; } ================================================ FILE: C Programs/C Programs - 1/Shell_Game.c ================================================ #include short find_initial_position(short, short); int main() { unsigned long no_of_turns; short effective_no_of_turns, current_ball_position, initial_ball_position; scanf("%lu %hu",&no_of_turns, ¤t_ball_position); effective_no_of_turns = no_of_turns%6; //The same permutation repeats after every six permutations initial_ball_position = find_initial_position(current_ball_position, effective_no_of_turns); printf("%hu\n",initial_ball_position); return 0; } /*Recursive function to find the initial position. Notice the following abc bac bca cba cab acb abc The same permutation repeats after every six operations. After reducing it to this, we simply move one step back at a time till we reach the zeroeth permutation.*/ short find_initial_position(short current_ball_position, short turn_no) { if(turn_no == 0)//First permutation. It is the base case { return current_ball_position; } else { if(turn_no%2 == 0) //Even turn - middle and right interchanged. Left stays invariant { switch(current_ball_position)//A different operation must happen to each ball. We trace the path of the ball up to the original permutation { case 0: return find_initial_position(current_ball_position, turn_no - 1); break; case 1: return find_initial_position(current_ball_position+1, turn_no - 1); break; case 2: return find_initial_position(current_ball_position-1, turn_no - 1); break; } } else //It was an odd turn - middle and left interchange. Right stays invariant { switch(current_ball_position) { case 0: return find_initial_position(current_ball_position + 1, turn_no - 1); break; case 1: return find_initial_position(current_ball_position - 1, turn_no - 1); break; case 2: return find_initial_position(current_ball_position, turn_no - 1); break; } } } } ================================================ FILE: C Programs/C Programs - 1/Sherlock_New_Girlfriend.c ================================================ #include #include #define limit 100000 void sunduram_sieve(unsigned int, short []); void make_prime_list(unsigned int, short [],short []); void initial_marking(unsigned int, short [], short); int main() { unsigned int n, i; short is_prime[limit], no_of_colours = 2; scanf("%d",&n); initial_marking( (n+1), is_prime, 2); //Initialising the array is_prime to 2. sunduram_sieve((n+1), is_prime); //If there are only 2 or 1 piece, the numbers are 2 and 3. One colour is sufficient to paint them. if(n <= 2) { no_of_colours = 1; } printf("%hu\n",no_of_colours); for(i = 2; i <= n + 1; i++) { if(is_prime[i] == 1) { printf("%u ",is_prime[i]); //Primes are painted with one colour - 1 } else { printf("%u ",is_prime[i]); //Composites are painted with another colour - 2 } } return 0; } //Initially, everything is marked 1 void initial_marking(unsigned int size, short array[], short initial_value) { unsigned int i; for(i = 1; i <= size; i++) { array[i] = initial_value; } } //Crossing out numbers of the form i + j + 2ij void sunduram_sieve(unsigned int target, short is_prime[]) { unsigned i, crossed_out_num, cross_limit, increment; //To avoid overflow short auxiliary_list[target/2]; initial_marking(target/2, auxiliary_list, 1); /*f(i,j) = i + j + 2ij For a given value of i, the minimum is when j = 1. Minimum is f(i,1) = 3i + 1 f(i, j + 1) = f(i,j) + 2i + 1 so we only need to increase the value of the crossed number by 2i + 1, instead of updating by one. i goes from 1 to target/2. But, f(i,j) starts from 3i + 1. If i is greater than target/6, then f(i,j) is out of range. So, the minimum Maximum occurs when j = i. f(i,j) = 2i(i+1). The last number to be crossed out for a given i is either 2i(i + 1) or the last f(i,j) before target/2, whichever comes first.*/ //All numbers of the form i + j + 2ij need to be marked out for(i = 1; i <= target/6; i++) { increment = 2*i + 1; cross_limit = 2*i*(i + 1); if(cross_limit > target/2) { cross_limit = target/2; } for(crossed_out_num = 3*i + 1;crossed_out_num <= cross_limit ; crossed_out_num += increment) { auxiliary_list[crossed_out_num] = 0; } } make_prime_list(target, is_prime, auxiliary_list); } //Making the list of primes void make_prime_list(unsigned int target, short is_prime[],short auxiliary_list[]) { int i = 0;; //We need to put 2 in ourselves because the algorithm 'only' generates all the odd primes is_prime[2] = 1; for(i = 1; i <= target/2; i++) { //Checking if the number is not crossed out and adding 2i + 1 to the list if it is unmarked. if(auxiliary_list[i] == 1) { is_prime[2*i + 1] = 1; } } } ================================================ FILE: C Programs/C Programs - 1/Taymr_is_Calling_You.c ================================================ #include unsigned int gcd(unsigned int,unsigned int); int main() { unsigned int time_at_which_calls_come, time_at_which_visits_come, total_minutes, no_of_clashes; unsigned int lcm; scanf("%u %u %u",&time_at_which_calls_come, &time_at_which_visits_come, &total_minutes); //gcd(a,b)*lcm(a,b) = a*b lcm = (time_at_which_calls_come*time_at_which_visits_come)/ gcd(time_at_which_calls_come,time_at_which_visits_come); no_of_clashes = total_minutes/lcm; printf("%u\n",no_of_clashes); return 0; } /*We use bitwise operations instead of multiply and divide simply because it is faster at the hardware level.*/ unsigned int gcd(unsigned int u,unsigned int v) { //Base Cases if(u == v) { return u; //Both are GCD } if(u == 0) { return v; } if(v == 0) { return u; } //If both are even, their GCD will also have a factor of 2 in it if(~u & 1) //If it is even, the last bit will be 0. Taking complement will make it 1. AND it with 1 and you get 1 if is even and 0 otherwise { if(v & 1)//v is odd. Removing the factor of 2 from u { return gcd(u >> 1, v); } else //Checking if both u and v are even gcd(u,v) = 2*gcd(u/2,v/2) { return 2*gcd(u >> 1 , v >> 1);//Dividing u and v by 2 } } if(~v & 1) //u is odd and v is even { return gcd(u,v>>1); } //Both are odd. gcd(u,v) = ( (u-v)/2, v) This is just one step ahead of the Euclidean algorithm //Any number that divides both u and v must also divide their difference. Here, the difference is even so we just remove //the fact of 2 //Determining the larger number if(u > v) { return gcd( (u - v) >> 1, v); } else { return gcd( (v - u) >> 1, u); } } ================================================ FILE: C Programs/C Programs - 1/The_Wall.c ================================================ #include unsigned int gcd(unsigned int,unsigned int); int main() { unsigned int lahub_bricks, floyd_bricks; unsigned long lahub_lucky_number, floyd_lucky_number, lcm, answer; scanf("%u %u %lu %lu",&lahub_bricks, &floyd_bricks, &lahub_lucky_number, &floyd_lucky_number); lcm = (lahub_bricks*floyd_bricks)/gcd(lahub_bricks,floyd_bricks); answer = floyd_lucky_number/lcm - (lahub_lucky_number-1)/lcm; //Not inclusive of Lahub's lucky number printf("%lu\n",answer); return 0; } /*We use bitwise operations instead of multiply and divide simply because it is faster at the hardware level.*/ unsigned int gcd(unsigned int u,unsigned int v) { //Base Cases if(u == v) { return u; //Both are GCD } if(u == 0) { return v; } if(v == 0) { return u; } //If both are even, their GCD will also have a factor of 2 in it if(~u & 1) //If it is even, the last bit will be 0. Taking complement will make it 1. AND it with 1 and you get 1 if is even and 0 otherwise { if(v & 1)//v is odd. Removing the factor of 2 from u { return gcd(u >> 1, v); } else //Checking if both u and v are even gcd(u,v) = 2*gcd(u/2,v/2) { return 2*gcd(u >> 1 , v >> 1);//Dividing u and v by 2 } } if(~v & 1) //u is odd and v is even { return gcd(u,v>>1); } //Both are odd. gcd(u,v) = ( (u-v)/2, v) This is just one step ahead of the Euclidean algorithm //Any number that divides both u and v must also divide their difference. Here, the difference is even so we just remove //the fact of 2 //Determining the larger number if(u > v) { return gcd( (u - v) >> 1, v); } else { return gcd( (v - u) >> 1, u); } } ================================================ FILE: C Programs/C Programs - 1/Translation.c ================================================ #include #include #define true 1 #define false 0 #define ANSWER_SIZE 4 //Yes or No #define WORD_SIZE_LIMIT 102 int main() { char word[WORD_SIZE_LIMIT], reversed_word[WORD_SIZE_LIMIT], answer[ANSWER_SIZE]; short correct_translation = true, i, length; scanf("%s %s",word, reversed_word); length = strlen(word); if(strlen(word) != strlen(reversed_word)) { correct_translation = false; } for(i = 0; i < length; i++) { if(word[i] != reversed_word[length - i - 1]) { correct_translation = false; break; } } if(correct_translation) { strcpy(answer, "YES"); } else { strcpy(answer, "NO"); } printf("%s\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 1/Vitya_in_the_Countryside.c ================================================ #include #include #include int main() { short no_of_observed_days, *size_of_moon, i; char answer[4]; scanf("%hu",&no_of_observed_days); //Allocating memory for and recording the observations size_of_moon = malloc(no_of_observed_days*sizeof(short)); for(i = 0; i < no_of_observed_days; i++) { scanf("%hu", (size_of_moon + i)); } if(*(size_of_moon + no_of_observed_days - 1) == 15) //Last observation is 15. Can only go down { strcpy(answer, "DOWN"); } else if(*(size_of_moon + no_of_observed_days - 1) == 0)//Last observation is 0. Can only go up { strcpy(answer, "UP"); } else if(no_of_observed_days == 1) //Unless the last observation is 0 or 15, 1 observation is insufficient { strcpy(answer, "-1"); } else { if(*(size_of_moon + no_of_observed_days - 1) > *(size_of_moon + no_of_observed_days - 2))//If a_n > a_{n-1}, moon goes up since a_n != 15 { strcpy(answer, "UP"); } else //a_n < a_{n-1}, moon goes down since a_n != 0 { strcpy(answer, "DOWN"); } } free(size_of_moon); printf("%s\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 1/Vladik_and_Flights.c ================================================ #include #include int main() { short cost; unsigned long no_of_airports, start_airport, destination_airport; scanf("%lu %lu %lu",&no_of_airports, &start_airport, &destination_airport); char *company_of_airport = malloc((no_of_airports+1)*sizeof(char)); //Allocating an extra character scanf("%s",company_of_airport); //If the airports are of the same company, cost is 0. Else it is 1. if( *(company_of_airport + start_airport - 1) == *(company_of_airport + destination_airport- 1) )//1 is subtracted because counting starts from 0 in the array { cost = 0; } else { cost = 1; } printf("%hu\n",cost); free(company_of_airport); return 0; } ================================================ FILE: C Programs/C Programs - 2/A_and_B_Chess.c ================================================ #include #include #define NO_OF_ROWS 8 void determine_stronger_colour(short, short, char[]); void read_chessboard(char [][NO_OF_ROWS + 1]); void find_strength_of_colour(short *, short *, char[][NO_OF_ROWS + 1]); short find_the_weight(char); int main() { char answer[6];//5 + 1. 5 is the maximum size of answer - White short white_strength, black_strength; char chessboard[NO_OF_ROWS][NO_OF_ROWS + 1]; //It is an array of strings. Each row of board is one string. So, we add 1. read_chessboard(chessboard); find_strength_of_colour(&white_strength, &black_strength, chessboard);//Pass by reference determine_stronger_colour(white_strength, black_strength, answer); printf("%s\n",answer); return 0; } void read_chessboard(char chessboard[][NO_OF_ROWS + 1]) { short i; //Chessboard is stored as 8 strings for(i = 0; i < NO_OF_ROWS; i++) { scanf("%s",chessboard[i]); } } void find_strength_of_colour(short *white_strength, short *black_strength, char chessboard[][NO_OF_ROWS + 1]) { short i, j; *(white_strength) = 0, *(black_strength) = 0; for(i = 0; i < NO_OF_ROWS; i++) { for(j = 0; j < NO_OF_ROWS; j++) { if(chessboard[i][j] == '.') { continue; } else if( ('A' <= chessboard[i][j]) && (chessboard[i][j] <= 'Z') ) { *(white_strength) = *(white_strength) + find_the_weight(chessboard[i][j]); } else { *(black_strength) = *(black_strength) + find_the_weight(chessboard[i][j]); } } } } short find_the_weight(char chess_piece) { short weight = 0; switch(chess_piece) { case 'p': case 'P': weight = 1; break; case 'N': case 'n': case 'B': case 'b': weight = 3; break; case 'R': case 'r': weight = 5; break; case 'Q': case 'q': weight = 9; break; default : weight = 0; } return weight; } void determine_stronger_colour(short white_strength, short black_strength, char answer[]) { //0 represents white and 1 represents black if(white_strength > black_strength) { strcpy(answer, "White"); } else if(white_strength < black_strength) { strcpy(answer,"Black"); } else { strcpy(answer, "Draw"); } } ================================================ FILE: C Programs/C Programs - 2/Again_Twenty_Five.c ================================================ #include #define MAX_NUMBER_SIZE 20 int main() { char power[MAX_NUMBER_SIZE]; short final_two_digits = 25; //From n > 2 (5^n mod 100 = 25) scanf("%s",power); printf("%hu\n",final_two_digits); return 0; } ================================================ FILE: C Programs/C Programs - 2/Anton_and_Danik.c ================================================ #include #include short find_who_won_more(char *, unsigned int); int main() { unsigned int no_of_games; short winner; scanf("%u",&no_of_games); char *results = malloc( (no_of_games + 1)*sizeof(char)); scanf("%s",results); winner = find_who_won_more(results, no_of_games);//Returns 1 if Anton is the winner and 2 if Danik wins and 0 for draw if(winner == 1) { printf("Anton\n"); } else if(winner == 2) { printf("Danik\n"); } else { printf("Friendship\n"); } free(results); return 0; } short find_who_won_more(char *results, unsigned int no_of_games) { unsigned int i, anton_win = 0, danik_win = 0; for(i = 0; i < no_of_games; i++) { if(*(results + i) == 'A') { anton_win++; } else if(*(results + i) == 'D') { danik_win++; } } if(anton_win > danik_win) { return 1; } else if(danik_win > anton_win) { return 2; } else //Both are equal { return 0; } } ================================================ FILE: C Programs/C Programs - 2/Bachgold_Problem.c ================================================ #include #include void get_prime_series_sum_to_n(short *, unsigned int); void fill_with_2(short *, short, unsigned int); void display_prime_series_that_sums_to_n(short *, unsigned int); int main() { unsigned int num, no_of_terms; scanf("%u",&num); //If n is even, there are n/2 terms. If n is odd, there are (n-3)/2 + 1 = (n/2 - 1) + 1 no_of_terms = num >> 1; short *prime_series_sum_n = malloc(no_of_terms*sizeof(short)); get_prime_series_sum_to_n(prime_series_sum_n, num); printf("%u\n", no_of_terms); display_prime_series_that_sums_to_n(prime_series_sum_n, no_of_terms); free(prime_series_sum_n); return 0; } void get_prime_series_sum_to_n(short *prime_series_sum_n, unsigned int n) { if(n%2 == 0) { //If a number is even, then the maximum number of prime terms that sum to it is n = 2 + 2 + 2 + ... fill_with_2(prime_series_sum_n,0, n >> 1); } else { //If a number is odd, then the maximum number of prime terms that sum to it is n = 3 + 2 + 2 + 2 + ... *(prime_series_sum_n) = 3; fill_with_2(prime_series_sum_n,1, (n - 3)>>1 ); } } void display_prime_series_that_sums_to_n(short *prime_series_sum_n, unsigned int no_of_terms) { unsigned int i; for(i = 0; i < no_of_terms; i++) { printf("%hu\t",*(prime_series_sum_n + i)); } } void fill_with_2(short *prime_series_sum_n, short start, unsigned int no_of_terms) { unsigned int i = start; for(i = start; i < no_of_terms + start; i++) { *(prime_series_sum_n + i) = 2; } } ================================================ FILE: C Programs/C Programs - 2/Bit++.c ================================================ #include #include int read_and_execute_program(unsigned int); int main() { unsigned int lines_of_code; int final_value_of_x; scanf("%u",&lines_of_code); final_value_of_x = read_and_execute_program(lines_of_code); printf("%d",final_value_of_x); return 0; } int read_and_execute_program(unsigned int lines_of_code) { char current_line_of_code[4]; //Each line of code has three characters unsigned int no_of_increments = 0, no_of_decrements = 0, i; int final_value; //Count the number of increment and decrement statements for(i = 0; i < lines_of_code; i++) { scanf("%s", current_line_of_code); if( (strcmp(current_line_of_code, "++X") == 0) || (strcmp(current_line_of_code, "X++") == 0) ) { no_of_increments++; } else if( (strcmp(current_line_of_code, "--X") == 0) || (strcmp(current_line_of_code, "X--") == 0) ) { no_of_decrements++; } } final_value = no_of_increments - no_of_decrements; //This is the final answer. return final_value; } ================================================ FILE: C Programs/C Programs - 2/Buy_a_Shovel.c ================================================ #include int main() { unsigned int price_of_a_shovel, total_money_spent; short change_available, no_of_shovels;; scanf("%u %hu",&price_of_a_shovel, &change_available); total_money_spent = price_of_a_shovel; for(no_of_shovels = 1; (total_money_spent)%10 != change_available && (total_money_spent % 10 != 0); no_of_shovels++) { total_money_spent = no_of_shovels*price_of_a_shovel; //printf("%u\n",total_money_spent); } //The number of shovels is incremented one time after the condition is broken. However, if the condition fails the first time, it is not incremented if(no_of_shovels != 1) { no_of_shovels--; } printf("%hu\n",no_of_shovels); return 0; } ================================================ FILE: C Programs/C Programs - 2/Chat_Room.c ================================================ #include #define true 1 #define false 0 #define MAX_MESSAGE_LENGTH 101 short is_hello_there(char[]); int main() { short if_hello_found; char message[MAX_MESSAGE_LENGTH]; scanf("%s",message); if_hello_found = is_hello_there(message); if(if_hello_found) { printf("YES\n"); } else { printf("NO\n"); } return 0; } short is_hello_there(char message[]) { char string_to_search[5] = "hello"; short string_to_search_index = 0, i, hello_found = false; for(i = 0; message[i] != '\0'; i++) { if(string_to_search[string_to_search_index] == message[i]) { string_to_search_index++; if(string_to_search_index == 5) { hello_found = true; return hello_found; } } } return hello_found; } ================================================ FILE: C Programs/C Programs - 2/Chips.c ================================================ #include short find_no_of_chips_at_end(short, unsigned int); int main() { short no_of_walruses, no_of_chips_left; unsigned int no_of_chips; scanf("%hu %u",&no_of_walruses, &no_of_chips); no_of_chips_left = find_no_of_chips_at_end(no_of_walruses, no_of_chips); printf("%hu\n",no_of_chips_left); return 0; } short find_no_of_chips_at_end(short no_of_walruses, unsigned int no_of_chips) { short i, no_of_chips_left = no_of_chips; for(i = 1; no_of_chips_left >= i; i = (i%no_of_walruses)+1) //The number of people goes from 1 to n. The residue class of n goes from 0 - n-1. So, we add 1 { no_of_chips_left = no_of_chips_left - i; //Giving i chips to person i //printf("%hu\t%hu\n",i, no_of_chips_left); } return no_of_chips_left; } ================================================ FILE: C Programs/C Programs - 2/Cinema_Line.c ================================================ #include #include #define true 1 #define false 0 short check_if_clerk_always_has_change(unsigned int,unsigned int *); void read_money_with_each_person(unsigned int,unsigned int *); int main() { short does_clerk_always_have_change; unsigned int no_of_people; scanf("%u",&no_of_people); unsigned int *price_paid_by_people = malloc(no_of_people*sizeof(unsigned int)); read_money_with_each_person(no_of_people, price_paid_by_people); does_clerk_always_have_change = check_if_clerk_always_has_change(no_of_people, price_paid_by_people); if(does_clerk_always_have_change) { printf("YES\n"); } else { printf("NO\n"); } free(price_paid_by_people); return 0; } void read_money_with_each_person(unsigned int no_of_people, unsigned int *price_paid_by_people) { unsigned int i; for(i = 0; i < no_of_people; i++) { scanf("%u",(price_paid_by_people + i)); } } short check_if_clerk_always_has_change(unsigned int no_of_people, unsigned int *price_paid_by_people) { short does_clerk_always_have_change = true; int no_of_25_bills = 0, no_of_50_bills = 0, i; //No need of keeping track of 100 because they can't they can't be used for change for(i = 0; i < no_of_people; i++) { if(*(price_paid_by_people + i) == 25) { no_of_25_bills++; } else if(*(price_paid_by_people + i) == 50) { //Check if he has change if(no_of_25_bills < 1) { does_clerk_always_have_change = false; break; } no_of_50_bills++; no_of_25_bills --; } else if(*(price_paid_by_people + i) == 100) { if((no_of_25_bills >= 1) && (no_of_50_bills >= 1)) { no_of_50_bills--; no_of_25_bills --; } else if(no_of_25_bills >= 3) { no_of_25_bills = no_of_25_bills - 3; } else //Change couldn't be paid { does_clerk_always_have_change = false; break; } } } return does_clerk_always_have_change; } ================================================ FILE: C Programs/C Programs - 2/Domino_Piling.c ================================================ #include int main() { short no_of_rows, no_of_columns; short no_of_dominos; scanf("%hu %hu", &no_of_rows, &no_of_columns); /*If there are m*n squares, and m*n is an even number, all the squares can be tiled. 2 squares for a domino, so m*n/2 If m*n is an odd number, then m*n-1 squares can be tiled. So, (m*n-1)/2. But, since m*n is an odd number - floor(m*n/2) In other words, simple integer division by 2.*/ no_of_dominos = (no_of_rows*no_of_columns) >> 1; printf("%hu\n",no_of_dominos); return 0; } ================================================ FILE: C Programs/C Programs - 2/Drazil_and_Date.c ================================================ #include #include #define true 1 #define false 0 short check_if_possible(long,long,unsigned long); int main() { short is_possible; long x_coordinate, y_coordinate; unsigned long distance_travelled; scanf("%ld %ld %lu",&x_coordinate, &y_coordinate, &distance_travelled); is_possible = check_if_possible(x_coordinate, y_coordinate, distance_travelled); if(is_possible) { printf("YES\n"); } else { printf("NO\n"); } return 0; } /*1. In a given move, either x or y changes by 1. To go from (0,0) to (a,b) it will take a minimum of (|a|+|b|) moves. 2. From a point (x,y), it is possible to return to (x,y) in an even number of moves only. If an odd number of moves have been made, it means that one of the coordinates has been changed more times than the other. So, it isn't possible to return to (x,y). A simple example is (x,y) - (x+1, y) - (x,y) and variations of this. It is possible to return only after an even number of moves.*/ short check_if_possible(long x_coordinate,long y_coordinate,unsigned long distance_travelled) { unsigned long minimum_distance_required = abs(x_coordinate) + abs(y_coordinate); if(distance_travelled < minimum_distance_required)//If the distance_travelled is less than the number of moves, then it is not possible { return false; } /*the same point can be returned to only in an even number of moves. In an odd number of moves, one coordinate gets changed more times than the other. So, it isn't possible*/ else if((distance_travelled - minimum_distance_required)%2 == 0) { return true; } else { return false; } } ================================================ FILE: C Programs/C Programs - 2/George_and_Accomodation.c ================================================ #include #include void get_room_details(short *, short *, short); short find_no_of_accomodating_rooms(short *, short *, short); int main() { short no_of_rooms, no_of_accomodating_rooms; scanf("%hu", &no_of_rooms); short *no_of_room_occupants = malloc(no_of_rooms*sizeof(short)); short *capacity_room = malloc(no_of_rooms*sizeof(short)); get_room_details(no_of_room_occupants,capacity_room,no_of_rooms); no_of_accomodating_rooms = find_no_of_accomodating_rooms(no_of_room_occupants,capacity_room,no_of_rooms); printf("%hu\n",no_of_accomodating_rooms); free(no_of_room_occupants); free(capacity_room); return 0; } void get_room_details(short *no_of_room_occupants, short *capacity_room, short no_of_rooms) { short i; for(i = 0; i < no_of_rooms ; i++) { scanf("%hu %hu",(no_of_room_occupants + i), (capacity_room + i)); } } short find_no_of_accomodating_rooms(short *no_of_room_occupants, short *capacity_room, short no_of_rooms) { short i, no_of_accomodating_rooms = 0; for(i = 0; i < no_of_rooms ; i++) { if( *(capacity_room + i) - *(no_of_room_occupants + i) >= 2) //Accomodate both George and his friend { no_of_accomodating_rooms++; } } return no_of_accomodating_rooms; } ================================================ FILE: C Programs/C Programs - 2/Gravity_Flip.c ================================================ #include #include void read(short *, short); void selection_sort(short *, short); void display(short *, short); int main() { short no_of_columns; scanf("%hu",&no_of_columns); short *blocks = malloc(no_of_columns*sizeof(short)); read(blocks, no_of_columns); selection_sort(blocks, no_of_columns); display(blocks, no_of_columns); free(blocks); return 0; } void read(short *blocks, short no_of_columns) { short i; for(i = 0; i < no_of_columns; i++) { scanf("%hu",(blocks + i)); } } void display(short *blocks, short no_of_columns) { short i; for(i = 0; i < no_of_columns; i++) { printf("%hu\t",*(blocks + i)); } } void selection_sort(short *blocks, short no_of_columns) { short i, j, smallest, smallest_index; //Every iteration finds the i-th minima. So, for n elements, we only need to sort n-1 elements. The last element is forced to be in it's correct position. for(i = 0; i < no_of_columns - 1; i++) { smallest = *(blocks + i); smallest_index = i; for(j = i + 1; j < no_of_columns; j++)//Go through the list from i to the end to search for a minima { if(*(blocks + j) < smallest) { smallest = *(blocks + j); smallest_index = j; } } //Place the i-th minima in the i-th position, and the element at the i-th position where the minima was *(blocks + smallest_index) = *(blocks + i); *(blocks + i) = smallest; } } ================================================ FILE: C Programs/C Programs - 2/Infinite_Sequence.c ================================================ #include #define true 1 #define false 0 short check_if_term_falls_in_sequence(long,long,long); int main() { short does_term_fall_in_sequence; long first_term, term_to_be_checked, common_difference; scanf("%ld %ld %ld",&first_term, &term_to_be_checked, &common_difference); does_term_fall_in_sequence = check_if_term_falls_in_sequence(first_term, term_to_be_checked, common_difference); if(does_term_fall_in_sequence) { printf("YES\n"); } else { printf("NO\n"); } return 0; } short check_if_term_falls_in_sequence(long first_term,long term_to_be_checked,long common_difference) { //Prevent division by zero. If difference = 0, then the sequence consists of one term only, term lies in the sequence iff it is the start term if(common_difference == 0) { if(first_term == term_to_be_checked) { return true; } else { return false; } } /*If b falls in the progression, then a + nc = b, where n is a non-negative integer. We have to check that (b-a) mod c = 0, and then that (b-a)/c >= 0, The second condition is to prevent n from being negative. For example, the series given by (1, 5) should not accept -4. -4 is the '-1'th term.*/ if( ( (term_to_be_checked - first_term)%common_difference == 0) && ((term_to_be_checked - first_term)/common_difference >= 0) ) { return true; } else { return false; } } ================================================ FILE: C Programs/C Programs - 2/Interview_with_Oleg.c ================================================ #include #include #define PRIMARY_FILLER_LENGTH 4 #define ADDITIONAL_FILLER_LENGTH 3 #define true 1 #define false 0 void remove_filler_from_interview(char *, char *); short find_filler_length_from_here(char *, short); short search_for_additional_filler(char *, short); int main() { short size_of_string; scanf("%hu",&size_of_string); char *interview = malloc( (size_of_string + 1)*sizeof(char) ); char *interview_without_filler = malloc( (size_of_string + 1)*sizeof(char) ); scanf("%s",interview); remove_filler_from_interview(interview, interview_without_filler); printf("%s",interview_without_filler); free(interview); free(interview_without_filler); return 0; } void remove_filler_from_interview(char *interview, char *interview_without_filler) { short i = 0, length_of_filler_from_i, final_interview_index = 0, count; while( *(interview + i) != '\0') { length_of_filler_from_i = find_filler_length_from_here(interview, i); //If there is no filler here, then just put in the same character as the normal interview and proceed to the next character if(length_of_filler_from_i == 0) { *(interview_without_filler + final_interview_index) = *(interview + i); final_interview_index++; i++; } else { for(count = 0; count < 3; count++, final_interview_index++)//Filling three asterisks { *(interview_without_filler + final_interview_index) = '*'; } i = i + length_of_filler_from_i; //Start checking the interview from where the current filler ended } } *(interview_without_filler + final_interview_index) = '\0';//Terminating the string } short find_filler_length_from_here(char *interview, short i) { short filler_length = 0, primary_filler_index = 0, primary_filler_found = true, additional_filler_found = false; char primary_filler[PRIMARY_FILLER_LENGTH] = "ogo"; for(primary_filler_index = 0; primary_filler[primary_filler_index] != '\0'; primary_filler_index++) { if(*(primary_filler + primary_filler_index) != *(interview + i + primary_filler_index) ) { primary_filler_found = false; break; } } if(primary_filler_found == false)//If not found, then return filler length is 0 { filler_length = 0; } else //If a primary filler is found, then search for the secondary filler and update the filler length accordingly { filler_length = filler_length + 3; additional_filler_found = search_for_additional_filler(interview, i+filler_length); while(additional_filler_found) { filler_length = filler_length + 2; additional_filler_found = search_for_additional_filler(interview, i+filler_length); } } return filler_length; } short search_for_additional_filler(char *interview, short here) { short additional_filler_found = true, additional_filler_index; char additional_filler[ADDITIONAL_FILLER_LENGTH] = "go"; for(additional_filler_index = 0; additional_filler[additional_filler_index] != '\0'; additional_filler_index++) { if(*(interview + here + additional_filler_index) != additional_filler[additional_filler_index]) { additional_filler_found = false; break; } } return additional_filler_found; } ================================================ FILE: C Programs/C Programs - 2/Pasha_and_Stick.c ================================================ #include int main() { unsigned long length_of_stick, no_of_rectangular_cuts; scanf("%lu",&length_of_stick); /*If x is not an even number, then the number of rectangles is 0. Let x, be an even number. We must find the number of unordered pairs (a, b) such that (a + b) = x/2, where a is not equal to b. It is sufficient to count the number of times we can find (a + b) = x/2. We just replicate the same division on the other other x/2 stick. This is the number of integers upto (x/2)/2 = x/4 [ (1, x/2-1), (2, x/2 - 2) .... (x/4 - 1, x/4 + 1), (x/4, x/4)] If x is a multiple of 4, then the last pair is (x/4, x/4) which has to be discounted. Otherwise, it is (x/4 - 1, x/4 + 1)*/ if(length_of_stick%2 == 1) { no_of_rectangular_cuts = 0; } else { if(length_of_stick%4 == 0) { no_of_rectangular_cuts = length_of_stick/4 - 1; } else { no_of_rectangular_cuts = length_of_stick/4; } } printf("%lu\n",no_of_rectangular_cuts); return 0; } ================================================ FILE: C Programs/C Programs - 2/Pineapple_Incident.c ================================================ #include #define true 1 #define false 0 short check_if_pineapple_barks(unsigned long,unsigned long,unsigned long); int main() { short does_pineapple_bark; unsigned long first_bark_time, barking_interval, desired_time; scanf("%lu %lu %lu",&first_bark_time, &barking_interval, &desired_time); does_pineapple_bark = check_if_pineapple_barks(first_bark_time, barking_interval, desired_time); if(does_pineapple_bark) { printf("YES\n"); } else { printf("NO\n"); } return 0; } short check_if_pineapple_barks(unsigned long first_bark_time,unsigned long barking_interval,unsigned long desired_time) { /*First bark time = t, barking interval = s, desired time = x If x = t + ms or x = t + ms + 1, then it is a YES, it barks If x = t + ms, then x - t is a multiple of s. If x = t + ms + 1, then x - t = ms + 1, (x - t) has to leave a remainder of 1 with s. However, it doesn't bark at time t + 1 If x < t, then no other checks are necessary. The pineapple doesn't bark. Avoid subtraction in that case because these are unsigned numbers.*/ if(desired_time < first_bark_time) { return false; } if( (desired_time - first_bark_time) < barking_interval ) //This block ensures t+1 doesn't get counted as a barking time. { if(desired_time == first_bark_time)//If x-t #include #define MAX_NAME_SIZE 11 int main() { char murdered[MAX_NAME_SIZE], replacement[MAX_NAME_SIZE], person_1[MAX_NAME_SIZE], person_2[MAX_NAME_SIZE], survivor[MAX_NAME_SIZE]; unsigned int no_of_days, i; scanf("%s %s",person_1, person_2); printf("%s %s\n", person_1, person_2); scanf("%u",&no_of_days); for(i = 0; i < no_of_days; i++) { scanf("%s %s",murdered, replacement); if(strcmp(murdered, person_1) == 0) { strcpy(survivor, person_2); } else { strcpy(survivor, person_1); } printf("%s %s\n", survivor, replacement); strcpy(person_1, survivor); strcpy(person_2, replacement); } return 0; } ================================================ FILE: C Programs/C Programs - 2/Soldier_and_Bananas.c ================================================ #include int main() { unsigned int no_of_bananas, price_of_one_banana; unsigned long money_with_soldier, amount_to_be_borrowed; scanf("%u %lu %u", &price_of_one_banana, &money_with_soldier, &no_of_bananas); //Sum of bananans = k + 2k + ... wk = w(w+1)/2 * k, where k is the price and w is the number of bananas if( (no_of_bananas*(no_of_bananas + 1)/2 )*(price_of_one_banana) < money_with_soldier) { amount_to_be_borrowed = 0; } else { amount_to_be_borrowed = (no_of_bananas*(no_of_bananas + 1)/2 )*(price_of_one_banana) - money_with_soldier; } printf("%lu\n",amount_to_be_borrowed); return 0; } ================================================ FILE: C Programs/C Programs - 2/Spider_Man.c ================================================ #include #include void read(unsigned int *, unsigned int); void display(short *, unsigned int); void make_winner_list(short *, unsigned int *,unsigned int); int main() { unsigned int no_of_tests; scanf("%u",&no_of_tests); unsigned int *no_of_vertices = malloc(no_of_tests*sizeof(unsigned int)); short *winner = malloc(no_of_tests*sizeof(short)); read(no_of_vertices, no_of_tests); make_winner_list(winner, no_of_vertices, no_of_tests); display(winner, no_of_tests); free(winner); free(no_of_vertices); return 0; } /*A move in the game is equivalent to deleting an edge from a graph with n vertices where there's an edge between consecutive numbers. 1-2-3...-n. There is no edge in between n and 1 because deleting it creates no new graphs. The number of edges id v - 1, where v is the number of vertices. The number of edges reduces by 1 in every move. If the number of edges is even (0 included), Player 2 wins. If the number of edges is odd, Player 1 wins.*/ void make_winner_list(short *winner, unsigned int *no_of_vertices,unsigned int no_of_tests) { unsigned int i, sum_of_edges = 0; for(i = 0; i < no_of_tests; i++) { sum_of_edges = sum_of_edges + *(no_of_vertices + i) - 1; if(sum_of_edges%2 == 0)//Player 2 wins if there are an even number of edges { *(winner + i) = 2; } else//Player 1 wins if there are an odd number of edges { *(winner + i) = 1; } } } void read(unsigned int *no_of_vertices, unsigned int no_of_tests) { unsigned int i; for(i = 0; i < no_of_tests; i++) { scanf("%u",(no_of_vertices + i)); } } void display(short *winner, unsigned int no_of_tests) { unsigned int i; for(i = 0; i < no_of_tests; i++) { printf("%hu\n",*(winner + i)); } } ================================================ FILE: C Programs/C Programs - 2/Stones_on_a_Table.c ================================================ #include #include short find_minimum_stones_to_be_removed(char *); int main() { short no_of_stones, minimum_stones_to_be_removed; scanf("%hu",&no_of_stones); char *colour_of_stones = malloc((no_of_stones+1)*sizeof(char)); scanf("%s",colour_of_stones); minimum_stones_to_be_removed = find_minimum_stones_to_be_removed(colour_of_stones); printf("%hu\n",minimum_stones_to_be_removed); free(colour_of_stones); return 0; } short find_minimum_stones_to_be_removed(char *colour_of_stones) { short i, j, stones_to_remove = 0; char current_colour; for(i = 0; *(colour_of_stones + i) != '\0'; ) { current_colour = *(colour_of_stones + i); //Counts the number of stones of the same colour as stone i, after stone i for(j = i + 1; *(colour_of_stones + j) == current_colour ; j++) { stones_to_remove++; } //All the stones that j ran through has been removed. i needs to resume counting from where j ended. i = j; } return stones_to_remove; } ================================================ FILE: C Programs/C Programs - 2/Transform_A_to_B.c ================================================ #include #define MAX_INTERMEDIATE_NUMBERS 40 void find_path(unsigned long, unsigned long,short *, unsigned long[]); void display_path_of_numbers(unsigned long[], short); int main() { short no_of_intermediate_numbers = 0; unsigned long start_number, end_number, path_of_numbers[MAX_INTERMEDIATE_NUMBERS]; scanf("%lu %lu",&start_number, &end_number); find_path(start_number, end_number, &no_of_intermediate_numbers, path_of_numbers);//No of intermediate answers is passed by reference //Displaying The Answer. If the path ends in the start number, a path exists. if(path_of_numbers[no_of_intermediate_numbers] == start_number) { printf("YES\n"); printf("%lu\n",no_of_intermediate_numbers+1); //Right now, no_of_intermediate_numbers is the length of the path from b to a, starting from 0. display_path_of_numbers(path_of_numbers, no_of_intermediate_numbers); } else { printf("NO\n"); } return 0; } //Determines the path from a to b void find_path(unsigned long start_number,unsigned long end_number,short *no_of_intermediate_numbers,unsigned long path_of_numbers[]) { path_of_numbers[0] = end_number; for(*no_of_intermediate_numbers = 0; path_of_numbers[*no_of_intermediate_numbers] > start_number; *no_of_intermediate_numbers = *no_of_intermediate_numbers+1) { if(path_of_numbers[*no_of_intermediate_numbers]%2 == 0) { path_of_numbers[*no_of_intermediate_numbers + 1] = path_of_numbers[*no_of_intermediate_numbers]/2; } else { //Checking if the given number can be attained by 10x + 1. For example, there is no integer x, for which 10x + 1 = 15 if( (path_of_numbers[*no_of_intermediate_numbers] - 1) %10 == 0) { path_of_numbers[*no_of_intermediate_numbers + 1] = (path_of_numbers[*no_of_intermediate_numbers] - 1)/10; } else //There is no integer x, for which 10x + 1 is the current number { path_of_numbers[*no_of_intermediate_numbers + 1] = 0; //This will exit the loop because start number has to be atleast 1. } } } } //Displays the path from start to end number i.e. in reverse order of how it was built void display_path_of_numbers(unsigned long path_of_numbers[], short no_of_intermediate_numbers) { short i; for(i = no_of_intermediate_numbers; i >= 0; i--) { printf("%lu\t",path_of_numbers[i]); } } ================================================ FILE: C Programs/C Programs - 2/Triangular_Numbers.c ================================================ #include #define true 1 #define false 0 short check_if_triangular(unsigned int); int main() { short is_triangular; unsigned int num; scanf("%u",&num); is_triangular = check_if_triangular(num); if(is_triangular) { printf("YES\n"); } else { printf("NO\n"); } return 0; } short check_if_triangular(unsigned int num) { unsigned int i; //Searching for the first triangular number that is not smaller than num for(i = 1; i*(i+1)/2 < num; i++); //Checking if the first triangular number greater than or equal to num is equal if(i*(i+1)/2 == num) { return true; } else { return false; } } ================================================ FILE: C Programs/C Programs - 2/Watermelon.c ================================================ #include int main() { short weight_of_watermelon; scanf("%hu",&weight_of_watermelon); //An odd number can't be divided into two even numbers because two even numbers always sum up to an even number //2 can't be divided into two even numbers smaller than it. (A division of size 0 is not allowed.) if( (weight_of_watermelon == 2) || (weight_of_watermelon%2 == 1)) { printf("NO\n"); } else //If Weight = 4n + 2, then the weights are 2n and 2n+2, if weight is 4n, then it is 2n and 2n { printf("YES\n"); } return 0; } ================================================ FILE: C Programs/C Programs - 2/Word_Capitalisation.c ================================================ #include #include #define MAX_WORD_SIZE 1001 int main() { char *word = malloc(MAX_WORD_SIZE*sizeof(char)); scanf("%s",word); if( ('a' <= *(word + 0) ) && ('z' >= *(word + 0)) ) { *(word + 0) = *(word + 0) - ('a' - 'A'); //The ASCII capitals come before the smaller letters. Subtracting the first letter to make it small } printf("%s\n",word); free(word); return 0; } ================================================ FILE: C Programs/C Programs - 3/Anton_and_Polyhedron.c ================================================ #include #include #include void read_faces_of_polyhedara(short *, unsigned int); unsigned int get_total_number_of_faces(short *, unsigned int); int main() { unsigned int no_of_polyhedra, no_of_faces; scanf("%u",&no_of_polyhedra); short *polyhedra_face = malloc(no_of_polyhedra*sizeof(short)); read_faces_of_polyhedara(polyhedra_face, no_of_polyhedra); no_of_faces = get_total_number_of_faces(polyhedra_face, no_of_polyhedra); printf("%u\n",no_of_faces); free(polyhedra_face); return 0; } void read_faces_of_polyhedara(short *polyhedra_face, unsigned int no_of_polyhedra) { char current_polyhedra[15]; unsigned int i; for(i = 0; i < no_of_polyhedra; i++) { scanf("%s",current_polyhedra); if(strcmp(current_polyhedra, "Tetrahedron") == 0) { *(polyhedra_face + i) = 4; } else if(strcmp(current_polyhedra, "Cube") == 0) { *(polyhedra_face + i) = 6; } else if(strcmp(current_polyhedra, "Octahedron") == 0) { *(polyhedra_face + i) = 8; } else if(strcmp(current_polyhedra, "Dodecahedron") == 0) { *(polyhedra_face + i) = 12; } else if(strcmp(current_polyhedra, "Icosahedron") == 0) { *(polyhedra_face + i) = 20; } } } unsigned int get_total_number_of_faces(short *polyhedra_face, unsigned int no_of_polyhedra) { unsigned int i, total_faces = 0; for(i = 0; i < no_of_polyhedra; i++) { total_faces = total_faces + *(polyhedra_face + i); } return total_faces; } ================================================ FILE: C Programs/C Programs - 3/Calculating_Function.c ================================================ #include int main() { long long number, answer; scanf("%I64d",&number); if(number%2 == 0) { answer = number >> 1; //For even n, the answer is n/2 because f(n) is (1) + (1) + ... +(1) } else { answer = (number >> 1) - number; } printf("%I64d\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 3/Cheap_Travel.c ================================================ #include unsigned int find_minimum_cost(unsigned int, unsigned int,unsigned int,unsigned int); int main() { unsigned int no_of_rides, price_of_one_ride, special_no_of_rides, price_of_special_rides; unsigned int minimum_money_spent; scanf("%u %u %u %u", &no_of_rides, &special_no_of_rides, &price_of_one_ride, &price_of_special_rides); minimum_money_spent = find_minimum_cost(no_of_rides, special_no_of_rides, price_of_one_ride, price_of_special_rides); printf("%u",minimum_money_spent); return 0; } unsigned int find_minimum_cost(unsigned int no_of_rides, unsigned int special_no_of_rides,unsigned int price_of_one_ride,unsigned int price_of_special_rides) { unsigned int minimum_cost, no_of_special_tickets, no_of_normal_tickets; //If it is cheaper to use the special ticket than normal ticket for b rides if(price_of_special_rides <= price_of_one_ride*special_no_of_rides) { no_of_special_tickets = no_of_rides/special_no_of_rides; //Checking if it is cheaper to use the special ticket for the remaining rides if(price_of_special_rides <= price_of_one_ride*(no_of_rides%special_no_of_rides)) { no_of_special_tickets++; no_of_normal_tickets = 0; } else { no_of_normal_tickets = no_of_rides%special_no_of_rides; } } else //Otherwise only buy normal tickets { no_of_special_tickets = 0; no_of_normal_tickets = no_of_rides; } minimum_cost = no_of_special_tickets*price_of_special_rides + no_of_normal_tickets*price_of_one_ride; return minimum_cost; } ================================================ FILE: C Programs/C Programs - 3/Checking_the_Calendar.c ================================================ #include #include #define true 1 #define false 0 #define MAX_DAY_SIZE 10 #define NO_OF_DAYS_IN_WEEK 7 short check_if_consecutive_months_start_with(char[], char[]); short get_day_no(char[]); int main() { short is_possible; char day_1[MAX_DAY_SIZE], day_2[MAX_DAY_SIZE]; scanf("%s %s",day_1, day_2); is_possible = check_if_consecutive_months_start_with(day_1, day_2); if(is_possible) { printf("YES\n"); } else { printf("NO\n"); } return 0; } short check_if_consecutive_months_start_with(char day_1[], char day_2[]) { short is_possible = false, no_day_1, no_day_2, difference; no_day_1 = get_day_no(day_1); no_day_2 = get_day_no(day_2); // 7 is added inside to ensure we always get a positive number. (a-b) mod m = (a-b + m) mod m difference = (no_day_2 - no_day_1 + NO_OF_DAYS_IN_WEEK)%NO_OF_DAYS_IN_WEEK; //Let a month begin on day 1 and have x days. x = 7q + r, r is a number less than 7. The day 7q + 1 will have the same day of the week as the first day //The next month begins at day r + 1. The difference in between 1(mod 7) and the allowable values of (r + 1) give us the answer. //If the month has 31 days, then 31 = 4(7) + 3. The first day is on 1(mod 7). The next month's first day is on 4(mod 7). So, difference of 3 is allowed //IF the month has 30 = 4(7) + 2. A difference of 2 is allowed //If the month has 28 = 7(4) days. Both the first days are on 1(mod 7) so a difference of 0 is allowed. if( (difference == 3) || (difference == 2) || (difference == 0) ) { is_possible = true; } return is_possible; } short get_day_no(char day[]) { if(strcmp (day, "monday") == 0) { return 1; } else if(strcmp (day, "tuesday") == 0) { return 2; } else if(strcmp (day, "wednesday") == 0) { return 3; } else if(strcmp (day, "thursday") == 0) { return 4; } else if(strcmp (day, "friday") == 0) { return 5; } else if(strcmp (day, "saturday") == 0) { return 6; } else if(strcmp (day, "sunday") == 0) { return 7; } return -1; } ================================================ FILE: C Programs/C Programs - 3/Currency_System_in_Geraldion.c ================================================ #include #include #define true 1 #define false 0 void read(unsigned int *, unsigned int); short search_for_1(unsigned int *, unsigned int); int main() { short is_there_a_1; unsigned int no_of_denominations; scanf("%u",&no_of_denominations); unsigned int *currency_notes = malloc(no_of_denominations*sizeof(unsigned int)); read(currency_notes, no_of_denominations); is_there_a_1 = search_for_1(currency_notes, no_of_denominations); if(is_there_a_1) { printf("-1\n"); //All currencies are reachable } else { printf("1"); //There is no 1 so that is the smallest unreachable currency } free(currency_notes); return 0; } void read(unsigned int *currency_notes, unsigned int no_of_denominations) { unsigned int i; for(i = 0; i < no_of_denominations; i++) { scanf("%u",(currency_notes + i)); } } short search_for_1(unsigned int *currency_notes, unsigned int no_of_denominations) { short one_found = false; unsigned int i; for(i = 0; i < no_of_denominations; i++) { if(*(currency_notes + i) == 1) { one_found = true; break; } } return one_found; } ================================================ FILE: C Programs/C Programs - 3/Die_Roll.c ================================================ #include short maximum(short, short); int main() { short roll_1, roll_2, dot_wins, total_rolls = 6; scanf("%hu %hu",&roll_1, &roll_2); dot_wins =total_rolls - maximum(roll_1, roll_2) + 1;//+1 because the other two allow Dot to win if she equalises. the maximum is also inclusive of when Dot wins //Reducing dot wins and total rolls to it's simplest form. Since we know it's 6, we just check divisibility by 2 and 3 instead of calling a gcd function if(dot_wins%3 == 0) { dot_wins = dot_wins/3; total_rolls = total_rolls/3; } if(dot_wins%2 == 0) { dot_wins = dot_wins/2; total_rolls = total_rolls/2; } printf("%hu/%hu\n",dot_wins, total_rolls); return 0; } short maximum(short a, short b) { if(a > b) { return a; } else { return b; } } ================================================ FILE: C Programs/C Programs - 3/Domino_Effect.c ================================================ #include #include int find_no_of_standing_dominos(char *); int main() { int no_of_dominos, no_of_standing_dominos; scanf("%d",&no_of_dominos); char *domino_line = malloc((no_of_dominos + 1)*sizeof(char)); scanf("%s",domino_line); no_of_standing_dominos = find_no_of_standing_dominos(domino_line); printf("%d\n",no_of_standing_dominos); free(domino_line); return 0; } /* 1. As we go through the domino line from the first domino, every '.' is counted as a standing domino. 2. If the character in front of a '.' is L, then every domino before it falls. So, the number of standing dominos is reset to 0. 3. If we find a 'R' at D(i), then we keep going ahead till we find either a 'L' at D(j) or the end of the string at j. If there are an odd number of dominos in between position i and j, then one domino stands. If there are an even number of dominos in between position i and j, they all fall. So, if {D(j) = 'R' and (j-i-1) is odd}, no_of_dominos++. {-1 because we are counting the number of dominos in between i and j, exclusive. j not counted} i is then updated to j, 4.If we find a 'L', at D(i) then we keep going ahead till we find either a 'R' at D(j) or the end of the string at position j. In either case, all the dominos from i+1 to j-1 stand. no_of_standing_dominos = no_of_standing_dominos + (j - i - 1) {-1 because the j-th domino doesn't stand} i is then updated to j. After the dots at the beginning i.e. after the first time D(i) is an alphabet, i will always be either an alphabet or the end of the string. This is why we can afford to increment the no of standing dominos every time D(i) is a '.' */ int find_no_of_standing_dominos(char *domino_line) { int no_of_standing_dominos = 0, i, j; for(i = 0; *(domino_line + i) != '\0';) { if(*(domino_line + i) == '.')//These are only for the dots at the beginning { no_of_standing_dominos++;//These dominos occur at the front. i++; if(*(domino_line + i) == 'L') { no_of_standing_dominos = 0; } continue; } else if(*(domino_line + i) == 'R') { //Searching for the next 'L' or the end of the string for(j = i + 1; (*(domino_line + j) != '\0') && (*(domino_line + j) != 'L'); j++); if( (*(domino_line + j) == 'L') && ((j-i - 1)%2 == 1) ) //-1 because the j-th domino isn't counted. No of dominos in between i and j, exclusive { no_of_standing_dominos++; // Only one domino stands if the number of dominos in between them is odd } i = j; //i continues where j ends } else if(*(domino_line + i) == 'L') { for(j = i + 1; (*(domino_line + j) != '\0') && (*(domino_line + j) != 'R'); j++); no_of_standing_dominos = no_of_standing_dominos + (j - i - 1);//After a left pushed domino, all the dominos in between i and j stand i = j; } } return no_of_standing_dominos; } ================================================ FILE: C Programs/C Programs - 3/Expression.c ================================================ #include unsigned int find_maximum_value(short, short, short); unsigned int maximum(unsigned int, unsigned int); int main() { short a, b, c; unsigned int maximum_value; scanf("%hu %hu %hu", &a, &b, &c); maximum_value = find_maximum_value(a, b, c); printf("%u\n", maximum_value); return 0; } unsigned int find_maximum_value(short a, short b, short c) { unsigned int maximum_value = a + b + c; maximum_value = maximum(maximum_value, (a+b)*c); maximum_value = maximum(maximum_value, a+(b*c)); maximum_value = maximum(maximum_value, a*(b+c)); maximum_value = maximum(maximum_value, (a*b)+c); maximum_value = maximum(maximum_value, a*b*c); return maximum_value; } unsigned int maximum(unsigned int a, unsigned int b) { if(a > b) { return a; } else { return b; } } ================================================ FILE: C Programs/C Programs - 3/Fedya_and_Maths.c ================================================ #include #include #define SIZE_LIMIT 100000 short get_answer(short, short); int main() { char number[SIZE_LIMIT]; short answer, last_digit, second_last_digit; scanf("%s",number); last_digit = number[strlen(number) - 1] - '0'; //Getting the last digit second_last_digit = number[strlen(number) - 2] - '0';//Getting the second last digit answer = get_answer(second_last_digit, last_digit); printf("%hu\n",answer); return 0; } short get_answer(short second_last_digit, short last_digit) { //Notice that 4^n = (5 - 1)^n = (-1)^n (mod 5), Similarly, 3 = (-2)^n (mod 5) if(last_digit%2 == 1)// If the number is odd, answer will always be 0. { return 0; //(1 + 2^n -2^n -1) (mod 5) } else //Powers of two mod 5 are {2, 4, 3, 1}. We are concerned with the even indices. { //(1 + 2.2^n + 1) (mod 5) = (2^{n+1} + 2) (mod 5). If n = 2 (mod 4), then the answer is 0, otherwise it is 4 from the observations above if( (second_last_digit*10 + last_digit)%4 == 0) { return 4; } else //n = 2(mod 4) { return 0; } } } ================================================ FILE: C Programs/C Programs - 3/Filya_and_Homework.c ================================================ #include #include #include #define true 1 #define false 0 short count_no_of_distinct_elements(unsigned long *,unsigned long, unsigned long[]); short check_if_set_is_in_AP(unsigned long[], short); void get_answer(char[], short); int main() { short is_possible = false, distinct_count; unsigned long no_of_elements, i, distinct_element[3]; unsigned long *list_of_numbers = NULL; char answer[4]; scanf("%lu",&no_of_elements); list_of_numbers = malloc(no_of_elements*sizeof(unsigned long)); for(i = 0; i < no_of_elements; i++) { scanf("%lu",(list_of_numbers + i)); } distinct_count = count_no_of_distinct_elements(list_of_numbers, no_of_elements, distinct_element); if(distinct_count > 3) { is_possible = false; } else { is_possible = check_if_set_is_in_AP(distinct_element, distinct_count); } get_answer(answer, is_possible); printf("%s\n",answer); free(list_of_numbers); return 0; } short count_no_of_distinct_elements(unsigned long *list_of_numbers,unsigned long no_of_elements, unsigned long distinct_element[]) { short distinct_count = 0, already_counted; int i, j; for(i = 0; i < no_of_elements; i++) { already_counted = false; //For the i=th element, for(j = 0; j < distinct_count ; j++) { if(*(list_of_numbers + i) == distinct_element[j]) { already_counted = true; break; } } if(already_counted == false) { distinct_element[distinct_count] = *(list_of_numbers + i); distinct_count++; if(distinct_count > 3) //If it exceeds three, just stop. Because it isn't possible for more than three distinct elements. { break; } } } return distinct_count ; } short check_if_set_is_in_AP(unsigned long distinct_element[], short distinct_count) { short set_is_in_AP = false; if(distinct_count < 3) //Set of 2 or 1 element will always be in AP { set_is_in_AP = true; return set_is_in_AP; } unsigned long a = distinct_element[0], b = distinct_element[1], c = distinct_element[2]; if( (a + c == 2*b) || (b + c == 2*a) || (b + a == 2*c) ) { set_is_in_AP = true; } return set_is_in_AP; } void get_answer(char answer[], short is_possible) { if(is_possible == true) { strcpy(answer, "YES"); } else { strcpy(answer, "NO"); } } ================================================ FILE: C Programs/C Programs - 3/Game.c ================================================ #include int main() { short no_of_balls_in_box_1, no_of_balls_in_box_2; short max_balls_1_can_throw, max_balls_2_can_throw; scanf("%hu %hu %hu %hu",&no_of_balls_in_box_1, &no_of_balls_in_box_2, &max_balls_1_can_throw,&max_balls_2_can_throw); if(no_of_balls_in_box_1 > no_of_balls_in_box_2) { printf("First\n"); } else //In case of equality, the second player wins { printf("Second\n"); } return 0; } ================================================ FILE: C Programs/C Programs - 3/Initial_Bet.c ================================================ #include #define NO_OF_PEOPLE 5 int main() { int final_coins[NO_OF_PEOPLE], i, start_coins; int total_coins = 0; for(i = 0; i < NO_OF_PEOPLE; i++) { scanf("%d",&final_coins[i]); } for(i = 0; i < NO_OF_PEOPLE; i++) { total_coins = total_coins + final_coins[i]; } /*No coins leave the system and no new coins enter the system. The total number of coins remain invariant. If in the beginning, everyone had b coins, the total number of coins will always be (NO_OF_PEOPLE*b). If the total number of coins are not a multiple of NO_OF_PEOPLE, then there can be no b which can be given to everyone leading to the current conversation. Conversely, if the total number of coins is NO_OF_PEOPLE*b, where b is some integer we can always trace the steps back to when everyone had b coins in the following way - Pick the maximum and minimum number of coins. Donate coins of maximum to minimum till the person with maximum is left with only b coins. Now, repeat this procedure for the rest of the people till everyone has b coins. We know this process converges because the total number of coins is NO_OF_PEOPLE*b, According to the question, 0 is not a legitimate answer so that case must be checked.*/ if( (total_coins%NO_OF_PEOPLE == 0) && (total_coins != 0) ) { start_coins = total_coins/NO_OF_PEOPLE; } else { start_coins = -1; } printf("%d\n", start_coins); return 0; } ================================================ FILE: C Programs/C Programs - 3/LCM_Challenge.c ================================================ #include #include int main() { unsigned long long n; unsigned long long answer; scanf("%I64u",&n); if(n < 3) { printf("%I64u",n); return 0; } if(n%2 == 1) { answer = (n)*(n-1)*(n-2); } else if(n%3 != 0)//Even number not a multiple of 3. n and (n-2) are not coprime and n(n-1)(n-3) > (n-1)(n-2)(n-3) { answer = n*(n-1)*(n-3); } else //Multiples of 6 { answer = (n-1)*(n-2)*(n-3); } printf("%I64u\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 3/Maximum_Increase.c ================================================ #include #include void read(unsigned long *, unsigned int); unsigned int find_length_max_increasing_subsequence(unsigned long *, unsigned int); int main() { unsigned int no_of_numbers, maximum_subsequence_length; scanf("%u",&no_of_numbers); unsigned long *number_sequence = malloc(no_of_numbers*sizeof(unsigned long)); read(number_sequence, no_of_numbers); maximum_subsequence_length = find_length_max_increasing_subsequence(number_sequence, no_of_numbers); printf("%u\n",maximum_subsequence_length); free(number_sequence); return 0; } void read(unsigned long *number_sequence, unsigned int no_of_numbers) { unsigned int i; for(i = 0 ; i < no_of_numbers; i++) { scanf("%lu",(number_sequence + i)); } } unsigned int find_length_max_increasing_subsequence(unsigned long *number_sequence, unsigned int no_of_numbers) { unsigned int i, j, length_of_increasing_subsequence = 0, maximum_increasing_subsequence = 1; for(i = 0; i < no_of_numbers; ) { length_of_increasing_subsequence = 1; //Finds the length of the increasing subsequence starting at i for(j = i + 1; (*(number_sequence + j) > *(number_sequence + j - 1) ) && (j < no_of_numbers); j++) { length_of_increasing_subsequence++; } i = j; //i resumes where j ends i.e. It starts from the next subsequence/**< /**< /**< /**< /**< */ */ */ */ */ if(length_of_increasing_subsequence > maximum_increasing_subsequence) { maximum_increasing_subsequence = length_of_increasing_subsequence; } } return maximum_increasing_subsequence; } ================================================ FILE: C Programs/C Programs - 3/Mishka_and_Game.c ================================================ #include #include short find_who_won_more(short *, short *, short); void read_results(short *, short *, short); int main() { short no_of_games; short winner; scanf("%hu",&no_of_games); short *mishka_results = malloc(no_of_games*sizeof(short)); short *chris_results = malloc(no_of_games*sizeof(short)); read_results(mishka_results, chris_results, no_of_games); winner = find_who_won_more(mishka_results, chris_results, no_of_games);//Returns 1 if Mishka is the winner and 2 if Chris wins and 0 for draw if(winner == 1) { printf("Mishka\n"); } else if(winner == 2) { printf("Chris\n"); } else { printf("Friendship is magic!^^\n"); } free(mishka_results); free(chris_results); return 0; } void read_results(short *mishka_results, short *chris_results, short no_of_games) { short i; for(i = 0; i < no_of_games; i++) { scanf("%hu %hu",(mishka_results + i), (chris_results + i)); } } short find_who_won_more(short *mishka_results, short *chris_results, short no_of_games) { short i, mishka_win = 0, chris_win = 0; for(i = 0; i < no_of_games; i++) { if(*(mishka_results + i) > *(chris_results + i)) { mishka_win++; } else if(*(mishka_results + i) < *(chris_results + i)) { chris_win++; } } if(mishka_win > chris_win) { return 1; } else if(chris_win > mishka_win) { return 2; } else //Both are equal { return 0; } } ================================================ FILE: C Programs/C Programs - 3/Multiplication_Table.c ================================================ #include int main() { unsigned int no_of_rows, no_of_boxes_containing_num = 0, i; unsigned long number; scanf("%u %lu",&no_of_rows, &number); //The question of finding the number of boxes that contain n, is equivalent to counting the number of ordered pairs(i, j) such that i*j = n for(i = 1;( (i*i < number) && (i <= no_of_rows) ); i++) { if( (number%i == 0) && (number/i <=no_of_rows) ) //Checking if the spot[i, x/i] exists on the square { no_of_boxes_containing_num = no_of_boxes_containing_num + 2; //Two boxes [i, x/i] and [x/i, i] } } if( (i*i == number) && (i <=no_of_rows) ) { no_of_boxes_containing_num++; //Perfect square [i, i] } printf("%u\n",no_of_boxes_containing_num); return 0; } ================================================ FILE: C Programs/C Programs - 3/Next_Round.c ================================================ #include #include void read(short *, short); short find_no_of_winners(short *, short, short ); int main() { short no_of_players, threshold_winner, no_of_winners; scanf("%hu %hu",&no_of_players, &threshold_winner); short *score = malloc(no_of_players*sizeof(short)); read(score, no_of_players); no_of_winners = find_no_of_winners(score, no_of_players, threshold_winner - 1);//1 is subtracted because we start counting from 0 printf("%hu\n",no_of_winners); free(score); return 0; } void read(short *score, short no_of_players) { short i; for(i = 0; i < no_of_players; i++) { scanf("%hu",(score + i)); } } short find_no_of_winners(short *score, short no_of_players, short winning_threshold) { short no_of_winners; if(*(score + winning_threshold) > 0) { //If the winning threshold is positive, then check how many players after the winning threshold position, have scored the same number of points for(no_of_winners = winning_threshold; no_of_winners < no_of_players; no_of_winners++) { if(*(score + no_of_winners) != *(score + winning_threshold)) { break; } } } else //If the winning threshold is negative, search for the first person ahead of the winning threshold with a positive score { for(no_of_winners = winning_threshold; no_of_winners >= 0; no_of_winners--) { if(*(score + no_of_winners) > 0) { break; } } no_of_winners++;//We have found the first index i, such that Score[i] is positive, increment so that we can count from 1 again. } return no_of_winners; } ================================================ FILE: C Programs/C Programs - 3/Party.c ================================================ #include #include #define true 1 #define false 0 void read(int *, unsigned int); unsigned int find_no_of_groups(int *, unsigned int); unsigned int find_depth_of_employee(int, int *); void find_depths_of_all_employees(int *, int *, unsigned int); int main() { unsigned int no_of_people, no_of_groups; scanf("%u",&no_of_people); int *immediate_manager = malloc(no_of_people*sizeof(int)); int *depth_of_employee = malloc(no_of_people*sizeof(int)); read(immediate_manager, no_of_people); find_depths_of_all_employees(depth_of_employee, immediate_manager, no_of_people); no_of_groups = find_no_of_groups(depth_of_employee, no_of_people); printf("%u\n",no_of_groups); free(depth_of_employee); free(immediate_manager); return 0; } void read(int *immediate_manager, unsigned int no_of_people) { unsigned int i; for(i = 0; i < no_of_people; i++) { scanf("%d",(immediate_manager + i)); } } /*First assign a depth to every node. The rule for depth is - 1. The root node has a depth of 0. 2. For every other node, Depth[i] = 1 + Depth[Immediate_manager(i)]*/ unsigned int find_depth_of_employee(int current_person, int *immediate_manager) { int next_immediate_manager; if(*(immediate_manager + current_person) == -1) { return 0; } else { next_immediate_manager = *(immediate_manager + current_person) - 1; //-1 because the input counts from 1 and we count from 0 in the array return 1 + find_depth_of_employee(next_immediate_manager, immediate_manager); } } void find_depths_of_all_employees(int *depth_of_employee, int *immediate_manager, unsigned int no_of_people) { int i; for(i = 0; i < no_of_people; i++) { *(depth_of_employee + i) = find_depth_of_employee(i, immediate_manager); } } /* Here is a simple strategy that achieves the following - 1. Assign a depth to every node. 2. Place all nodes of the same depth in the same set. We have to prove this arrangement ensure two nodes which share an edge aren't in the same set and that this happens in the minimum number of sets. The first part is obvious. This arrangements ensures that a given set only has elements of the same depth. No two nodes (either from the same or different tree) share an edge. To prove it's minimum, let us assume that such an arrangement exists with the number of sets l, where l < max{depth} Consider the tree with the nodes of maximum depth. By the pigeonhole principle there will exist one set which has nodes of this tree of two different depths. But, They can't belong to the same tree because it would violate the condition of the partition. This contradicts our assumption that an arrangement exists with less than max{depth} sets. The arrangements described takes max{depth} number of nodes. So, it is the minimum number. */ unsigned int find_no_of_groups(int *depth_of_employee, unsigned int no_of_people) { short already_counted; int i, j, distinct_depth_count = 0; int *distinct_depth = malloc(no_of_people*sizeof(int)); for(i = 0; i < no_of_people; i++) { already_counted = false; //For the i=th element, for(j = 0; j < distinct_depth_count ; j++) { if(*(depth_of_employee + i) == *(distinct_depth + j) ) { already_counted = true; break; } } if(already_counted == false) { *(distinct_depth + distinct_depth_count) = *(depth_of_employee + i); distinct_depth_count++; } } free(distinct_depth); return distinct_depth_count ; //The number of distinct depths is the answer } ================================================ FILE: C Programs/C Programs - 3/Police_Recruits.c ================================================ #include #include void read(short *, int); int find_no_untreated_crimes(short *, int); int main() { int no_of_events, untreated_crimes; scanf("%u",&no_of_events); short *events = malloc(no_of_events*sizeof(short)); read(events, no_of_events); untreated_crimes = find_no_untreated_crimes(events, no_of_events); printf("%u\n",untreated_crimes); free(events); return 0; } void read(short *events, int no_of_events) { int i; for(i = 0; i < no_of_events; i++) { scanf("%hu",(events + i)); } } int find_no_untreated_crimes(short *events, int no_of_events) { int untreated_crimes = 0, i, available_police_officers = 0; for(i = 0; i < no_of_events; i++) { if(*(events + i) == -1) { if(available_police_officers > 0) { available_police_officers--; } else if(available_police_officers == 0) { untreated_crimes++; } } else//Officers are recruited { available_police_officers = available_police_officers + *(events + i); } } return untreated_crimes; } ================================================ FILE: C Programs/C Programs - 3/Raising_Bacteria.c ================================================ #include #define MASK_1 0x5555555555555555 #define MASK_2 0x3333333333333333 #define MASK_3 0x0F0F0F0F0F0F0F0F #define MASK_4 0x00FF00FF00FF00FF #define MASK_5 0x0000FFFF0000FFFF #define MASK_6 0x00000000FFFFFFFF unsigned long long find_no_of_1_in_binary(unsigned long long); int main() { unsigned long long target_bacteria, no_of_bacteria; scanf("%I64u",&target_bacteria); no_of_bacteria = find_no_of_1_in_binary(target_bacteria); printf("%I64u",no_of_bacteria); return 0; } unsigned long long find_no_of_1_in_binary(unsigned long long target_bacteria) { unsigned long long population_count; population_count = target_bacteria; population_count = (population_count & MASK_1) + (population_count >> 1 & MASK_1);//After this step, every pair b[i, i+1] = b[i] + b[i+1], for even i //After this step, every quartet b[i .. i+3] = b[i .. i+1] + b[i+2 ... i+3] from previous step, for multiples of 4 - i population_count = (population_count & MASK_2) + (population_count >> 2 & MASK_2); //After this step, every b[i .. i+7] = b[i .. i+3] + b[i+4 ... i+7] from previous step, for multiples of 8 - i population_count = (population_count & MASK_3) + (population_count >> 4 & MASK_3); //After this step, every b[i .. i+15] = b[i .. i+7] + b[i+8 ... i+15] from previous step, for multiples of 16 - i population_count = (population_count & MASK_4) + (population_count >> 8 & MASK_4); //After this step, every b[i .. i+31] = b[i .. i+15] + b[i+16 ... i+31] from previous step, for multiples of 32 - i population_count = (population_count & MASK_5) + (population_count >> 16 & MASK_5); //After this step, every b[i .. i+63] = b[i .. i+31] + b[i+32 ... i+63] from previous step, for multiples of 64 - i population_count = (population_count & MASK_6) + (population_count >> 32 & MASK_6); //After this last step, what's left is the number of 1s in the binary representation of a number return population_count; } ================================================ FILE: C Programs/C Programs - 3/Save_Luke.c ================================================ #include int main() { float velocity_left, velocity_right, length_of_corridor, width_of_luke; float relative_velocity, effective_distance, max_survival_time; scanf("%f %f %f %f", &width_of_luke, &length_of_corridor, &velocity_left, &velocity_right); relative_velocity = velocity_left + velocity_right; effective_distance = length_of_corridor - width_of_luke; max_survival_time = effective_distance/relative_velocity; printf("%f",max_survival_time); return 0; } ================================================ FILE: C Programs/C Programs - 3/Taxes.c ================================================ #include #define true 1 #define false 0 short is_prime(unsigned long); short find_minimum_tax(unsigned long); int main() { short minimum_taxes; unsigned long total_taxes; scanf("%lu",&total_taxes); minimum_taxes = find_minimum_tax(total_taxes); printf("%hu\n",minimum_taxes); return 0; } //Happens in O(root(n)) time short is_prime(unsigned long n) { short prime = true; unsigned long i; for(i = 2; i*i <= n; i++) { if(n%i == 0) { prime = false; break; } } return prime; } /*If the number is prime, then only 1 has to be paid. That is the minimum possible. The next minimum is 2. Since the Goldbach conjecture has been verified upto the limit, we can use it. Any even number is the sum of two primes. We don't need to actually find the pair of primes, we just know it exists. If a number is odd and composite , n = (n-2) + 2, is the only way it can be written as the sum of two primes. 2 is the only even prime number. The sum of two odd numbers is another odd number. So, an even number has to be involved. If (n-2) is prime, then the minimum tax = 1+1 = 2 n = n-3 + 3, and then n-3 is an even number and has minimum return 2. 3 is prime. 2+1 = 3. This is the maximum possible tax that will ever be given following the scheme. Note - Although logically the first thing to do is check if a number is prime and return 1 if it is and then go for the other test, I have included it second because checking parity of number is a very quick and easy process Even numbers don't need to be subjected to primality tests.*/ short find_minimum_tax(unsigned long tax) { //According to Goldbach conjecture, every even number can be written as the sum of two odd primes, It has been numerically verified upto the limit given if( (tax%2 == 0) && (tax != 2) ) { return 2; } else if(is_prime(tax)) { return 1; } else { //If n-2 is prime, then n = (n - 2) + 2 is the sum of two primes. This is the only way since one summand has to be even to get an odd number if(is_prime(tax - 2)) { return 2; } else //Then, n = (n-3) + 3. n-3 is an even number and can be written as the sum of two odd primes { return 3; } } } ================================================ FILE: C Programs/C Programs - 3/Tennis_Tournament.c ================================================ #include int main() { unsigned int no_of_bottles_for_one_player, no_of_participants, no_of_towels_for_one_player; unsigned int total_no_of_bottles, total_no_of_towels, no_of_matches; scanf("%u %u %u",&no_of_participants, &no_of_bottles_for_one_player, &no_of_towels_for_one_player); //If there are n people, then there have to be n-1 matches. Each match eliminates one player and one player only. We need n-1 eliminations to end no_of_matches = no_of_participants - 1; //Each player takes two bottles and one for the judge total_no_of_bottles = no_of_matches*(2*no_of_bottles_for_one_player + 1);//One judge for every match total_no_of_towels = no_of_participants*no_of_towels_for_one_player ; printf("%u %u\n", total_no_of_bottles, total_no_of_towels); return 0; } ================================================ FILE: C Programs/C Programs - 3/The_Number_of_Positions.c ================================================ #include unsigned int minimum(unsigned int, unsigned int); int main() { short no_of_people, minimum_people_in_front, maximum_people_at_back, no_of_possible_positions; scanf("%hu %hu %hu", &no_of_people, &minimum_people_in_front, &maximum_people_at_back); //The number of possible positions is the overlap in between (n-a) and (b + 1). //one is added because if someone is standing at the (b+1)th position from the back, there are exactly b people behind him and he can stand in any position //after this no_of_possible_positions = minimum(no_of_people - minimum_people_in_front, maximum_people_at_back + 1); printf("%hu\n",no_of_possible_positions); return 0; } unsigned int minimum(unsigned int a, unsigned int b) { if(a < b) { return a; } else { return b; } } ================================================ FILE: C Programs/C Programs - 3/Theatre_Square.c ================================================ #include #include int main() { unsigned long long rectangular_length, rectangular_breadth, square_side, answer; scanf("%I64u %I64u %I64u",&rectangular_length, &rectangular_breadth, &square_side); if(rectangular_length%square_side != 0) { if(rectangular_breadth%square_side != 0) { answer = (rectangular_length/square_side + 1)*(rectangular_breadth/square_side + 1); } else { answer = (rectangular_length/square_side + 1)*(rectangular_breadth/square_side); } } else { if(rectangular_breadth%square_side != 0) { answer = (rectangular_length/square_side)*(rectangular_breadth/square_side + 1); } else { answer = (rectangular_length/square_side)*(rectangular_breadth/square_side); } } printf("%I64u\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 4/Aloyna_Numbers.c ================================================ #include unsigned long long count_pairs_multiple_5(unsigned long long, unsigned long long); int main() { unsigned long long m, n, answer; scanf("%I64u %I64u",&m, &n); answer = count_pairs_multiple_5(m,n); printf("%I64u\n",answer); return 0; } unsigned long long count_pairs_multiple_5(unsigned long long m, unsigned long long n) { short i; unsigned long long answer = 0, current_mod_x, current_mod_y; answer = (n/5)*(m/5);//doing the case of i = 0 (mod 5) separately because (m - (5 - i)) will actually lose 1 possible value of y. for(i = 1; i <5; i++) { current_mod_x = n/5; current_mod_y = m/5; if(n%5 >= i) { current_mod_x++; } if(m%5 >= 5 - i) { current_mod_y++; } answer = answer + current_mod_x*current_mod_y; } return answer; } ================================================ FILE: C Programs/C Programs - 4/Arpa_Hard_Problem_Mehrad_Naive_Cheat.c ================================================ #include short get_last_digit(unsigned long); int main() { short answer; unsigned long power; scanf("%lu",&power); answer = get_last_digit(power); printf("%hu\n",answer); return 0; } short get_last_digit(unsigned long power) { short i, answer = 1; if(power == 0)//n^0 = 1 { return answer; } /*(10x + a)^{n} = a^n (mod 10) because every other term in (10x + a)^n binomial expansion is a multiple of 10. 1378^n = 8^n (mod 10). Powers of 8 are cyclic with period 4.*/ power = power%4; if(power == 0)//This means it is a multiple of 4 not equal to zero. We set it to 4 so that we multiply 8 four times (mod 10) instead of 0 times. { power = 4; } for(i = 1; i <= power; i++) { answer = (answer*8)%10; } return answer; } ================================================ FILE: C Programs/C Programs - 4/Benches.c ================================================ #include int main() { unsigned long long no_of_paths; unsigned long long no_of_arrangements; scanf("%I64u",&no_of_paths); //nC5 nP5 no_of_arrangements = (no_of_paths)*(no_of_paths -1)/2* (no_of_paths -2)/3* (no_of_paths-3)/4*(no_of_paths-4)/5; no_of_arrangements *= (no_of_paths)*(no_of_paths -1)* (no_of_paths -2)* (no_of_paths-3)*(no_of_paths-4); printf("%I64u\n",no_of_arrangements); return 0; } ================================================ FILE: C Programs/C Programs - 4/Challenge_Pendants.c ================================================ #include int main() { unsigned long long no_of_tables, no_of_ways; scanf("%I64u",&no_of_tables); //(n + 5 -1) C (5) x (n + 3 - 1) C (3) - The two kinds of pendants' distribution is independent. Stars and bars for both of them. //Among any n consecutive integers, one of them is a multiple of n. That is why we divide by 2 after the first two numbers, 3 after first 3, etc. //Dividing at each step reduces the chance of overflow that might happen if the entire number is multiplied and then divided. no_of_ways = (no_of_tables + 4) * (no_of_tables + 3)/2 * (no_of_tables + 2)/3 * (no_of_tables + 1)/4 * (no_of_tables)/5; no_of_ways *= (no_of_tables + 2)*(no_of_tables + 1)/2 *(no_of_tables)/3; printf("%I64u\n",no_of_ways); return 0; } ================================================ FILE: C Programs/C Programs - 4/Chewbacca_and_Number.c ================================================ #include #define NO_OF_DIGITS 20 void transform_n_to_minimum(char[]); int main() { char number[NO_OF_DIGITS]; scanf("%s",number); transform_n_to_minimum(number); printf("%s",number); return 0; } void transform_n_to_minimum(char number[]) { short i; for(i = 0; number[i] != '\0'; i++) { //Digits greater than 5 are replaced by their compliment if(('5' <= number[i]) && (number[i] <= '9')) { number[i] = '9' - number[i] + '0'; } } if(number[0] == '0')//If first digit is zero, then it means it was a 9. We leave it untouched. { number[0] = '9'; } } ================================================ FILE: C Programs/C Programs - 4/Chocolate.c ================================================ #include #include #define true 1 #define false 0 void read(short *, short); short check_if_divison_exists(short *, short); long long find_no_of_divisions(short *, short); int main() { short no_of_pieces; long long no_of_divisions; scanf("%hu",&no_of_pieces); short *chocolate = malloc(no_of_pieces*sizeof(short)); read(chocolate, no_of_pieces); no_of_divisions = find_no_of_divisions(chocolate, no_of_pieces); printf("%I64d\n",no_of_divisions); free(chocolate); return 0; } void read(short *chocolate, short no_of_pieces) { short i; for(i = 0; i < no_of_pieces; i++) { scanf("%hu",(chocolate + i)); } } short check_if_divison_exists(short *chocolate, short no_of_pieces) { short i, division_exists = false; for(i = 0; i < no_of_pieces; i++) { if(*(chocolate + i) == 1) { division_exists = true; break; } } return division_exists; } long long find_no_of_divisions(short *chocolate, short no_of_pieces) { short does_division_exist; long long no_of_divsions = 1; short i, zero_count; //Checking if a division exists does_division_exist = check_if_divison_exists(chocolate, no_of_pieces); if(does_division_exist == false) { no_of_divsions = 0; return no_of_divsions; } //If there is a run of p 0s in between 2 1s, then a cut can be made in (p + 1) places. We multiply all the (p+1) for(i = 0; i < no_of_pieces;) { if( *(chocolate + i) == 0) { i++; continue; } else { //Count the number of zeros in between two consecutive 1s i.e. the current run of 0s. for(zero_count = 0; (i + zero_count) < no_of_pieces ; zero_count++) { if( *(chocolate + i + zero_count + 1) == 1) { no_of_divsions = no_of_divsions*(zero_count + 1); break; } } i = i + zero_count + 1; //i resumes from where the run of 0s ends, i.e. the next 1 or the end of the string. } } return no_of_divsions; } ================================================ FILE: C Programs/C Programs - 4/Design_Tutorial_Learn_From_Math.c ================================================ #include void get_composite_summands(unsigned long, unsigned long *, unsigned long *); int main() { unsigned long number, composite_summand_1, composite_summand_2; scanf("%lu",&number); get_composite_summands(number, &composite_summand_1, &composite_summand_2); //Pass by Reference printf("%lu %lu\n", composite_summand_1, composite_summand_2); return 0; } void get_composite_summands(unsigned long number, unsigned long *composite_summand_1, unsigned long *composite_summand_2) { if(number%2 == 0) { //2n = n + n, If n is an even number, we are done if(number%4 == 0) { *composite_summand_1 = number/2; *composite_summand_2 = number/2; return; } else //2n = n - 1 + n + 1, here (n-1) and (n+1) are even numbers because n is odd { *composite_summand_1 = number/2 - 1; *composite_summand_2 = number/2 + 1; return; } } else { //n = 9 + (n -9). 9 is composite and (n-9) is even. Since, n >= 12, n-9 >=4 when n is odd in the given range. We will always get an even number *composite_summand_1 = 9; *composite_summand_2 = number - 9; return; } } ================================================ FILE: C Programs/C Programs - 4/Divisibility.c ================================================ #include int main() { unsigned long long sales, no_of_bonuses; scanf("%I64u",&sales); //To be divisible by every number from 1-10, it has to be divisible by 2^3, 3^2, 5, 7 i.e. 2520 - Any number divisible by 2520 can be divided by //every number from 1-10 because each i in between 1-10, has all it's prime factors in such a number. //Any number not divisible by 2520, will have atleast one number such that all it's prime factors aren't in that number. So, the condition is necessary //and sufficient no_of_bonuses = sales/2520LL; printf("%I64u\n",no_of_bonuses); return 0; } ================================================ FILE: C Programs/C Programs - 4/Fedor_and_New_Game.c ================================================ #include #include #define MASK1 0x55555555 #define MASK2 0x33333333 #define MASK3 0x0F0F0F0F #define MASK4 0x00FF00FF #define MASK5 0x0000FFFF void read(int *, int); int find_maximum_number_of_friends(int *, int,int, int); int population_count(int); int main() { short n, maximum_allowed_differences; int fedor_army, no_of_soldiers, maximum_no_of_friends; scanf("%hu %d %hu", &n, &no_of_soldiers, &maximum_allowed_differences); int *army = malloc(no_of_soldiers*sizeof(int)); read(army, no_of_soldiers); scanf("%d",&fedor_army); maximum_no_of_friends = find_maximum_number_of_friends(army, no_of_soldiers, maximum_allowed_differences, fedor_army); printf("%d\n",maximum_no_of_friends); free(army); return 0; } void read(int *army, int no_of_soldiers) { int i; for(i = 0; i < no_of_soldiers; i++) { scanf("%d",(army + i)); } } int find_maximum_number_of_friends(int *army, int no_of_soldiers,int maximum_allowed_differences, int fedor_army) { int i, no_of_possible_friends = 0; for(i = 0; i < no_of_soldiers; i++) { //printf("%d\t%d\tXOR = %d\n",fedor_army, *(army + i), fedor_army^ (*(army + i)) ); //bitwise XOR on fedor army and every other army. Population count is the number of 1s i.e. the number of differences. if( (population_count(fedor_army^ *(army + i))) <= maximum_allowed_differences) { no_of_possible_friends++; } } return no_of_possible_friends; } int population_count(int x) { int no_of_1s = x; //x is always 32 bits no_of_1s = (no_of_1s &MASK1) + ((no_of_1s >> 1) &MASK1); no_of_1s = (no_of_1s &MASK2) + ((no_of_1s >> 2) &MASK2); no_of_1s = (no_of_1s &MASK3) + ((no_of_1s >> 4) &MASK3); no_of_1s = (no_of_1s &MASK4) + ((no_of_1s >> 8) &MASK4); no_of_1s = (no_of_1s &MASK5) + ((no_of_1s >> 16) &MASK5); //printf("Population Count = %d\n",no_of_1s); return no_of_1s; } ================================================ FILE: C Programs/C Programs - 4/Game_test.c ================================================ #include int main() { short winner; unsigned long long order_of_square; scanf("%I64u",&order_of_square); /*If n is an even number, then the square can be divided into four smaller squares. Whatever move, player 1 makes, player 2 makes the same move on the diagonally opposite square. In other words, the square rotated by 180 degrees is painted. Player 2 always has a move and wins. If n is an odd number, then the first player paints the central square (m+1, m+1), where n = 2m+1, After that player 1 paints the diagonally opposite square that any square that player 2 paints. Player 1 always wins.*/ if(order_of_square%2 == 1) { winner = 1; } else { winner = 2; } printf("%hu\n",winner); return 0; } ================================================ FILE: C Programs/C Programs - 4/Hexagons.c ================================================ #include int main() { unsigned long long n, answer; scanf("%I64u",&n); //Each layer adds 6 new hexagons.Including itself, 1 + 6( 1 + 2 + ... + n) = 1 + 6n(n+1)/2 answer = 1LL + 3LL*n*(n+1); printf("%I64u\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 4/Hulk.c ================================================ #include #include #define MAX_SIZE 1200 void get_final_emotions(char[], short); int main() { short no_of_layers; char emotions[MAX_SIZE]; scanf("%hu",&no_of_layers); get_final_emotions(emotions, no_of_layers); printf("%s\n",emotions); return 0; } void get_final_emotions(char emotions[], short no_of_layers) { short i; char odd_emotion[8] = "I hate ", even_emotion[8] = "I love "; strcpy(emotions, ""); for(i = 1; i <= no_of_layers; i++) { if(i%2 == 1) { strcat(emotions, odd_emotion); } else { strcat(emotions, even_emotion); } if(i != no_of_layers) { strcat(emotions, "that "); } else { strcat(emotions, "it"); } } } ================================================ FILE: C Programs/C Programs - 4/Indivisibility.c ================================================ #include int main() { unsigned long long sales, bonuses, anti_bonuses; scanf("%I64u",&sales); //Sufficient to check which numbers are not multiples of any of the primes below 10 //Principle of inclusion and exclusion counts anti-bonus - the number of numbers divisible by one of the primes - 2, 3,,5, 7 anti_bonuses = (sales/2LL + sales/3LL + sales/5LL + sales/7LL); anti_bonuses -= (sales/6LL + sales/10LL + sales/14LL + sales/15LL + sales/21LL + sales/35LL); anti_bonuses += (sales/30LL + sales/42LL + sales/70LL + sales/105LL); anti_bonuses -= (sales/210LL); bonuses = sales - anti_bonuses; printf("%I64u\n",bonuses); return 0; } ================================================ FILE: C Programs/C Programs - 4/Interview.c ================================================ #include #include void read(unsigned long *, unsigned long *, unsigned int); unsigned long get_maximum(unsigned long *, unsigned long *, unsigned int); int main() { unsigned int no_of_numbers; unsigned long maximum; scanf("%u",&no_of_numbers); unsigned long *list_1 = malloc(no_of_numbers*sizeof(unsigned long)); unsigned long *list_2 = malloc(no_of_numbers*sizeof(unsigned long)); read(list_1, list_2, no_of_numbers); maximum = get_maximum(list_1, list_2, no_of_numbers); printf("%lu\n",maximum); free(list_1); free(list_2); return 0; } void read(unsigned long *list_1, unsigned long *list_2, unsigned int no_of_numbers) { unsigned int i; for(i = 0; i < no_of_numbers; i++) { scanf("%lu",(list_1 + i)); } for(i = 0; i < no_of_numbers; i++) { scanf("%lu",(list_2 + i)); } } unsigned long get_maximum(unsigned long *list_1, unsigned long *list_2, unsigned int no_of_numbers) { unsigned int i; unsigned long function_list_1 = *list_1, function_list_2 = *list_2; //Finding f(a, 1, n) and f(b, 1, n) i.e. - the bitwise OR of the entire array for(i = 1; i < no_of_numbers; i++) { function_list_1 = function_list_1 | *(list_1 + i); function_list_2 = function_list_2 | *(list_2 + i); } return (function_list_1 + function_list_2); } ================================================ FILE: C Programs/C Programs - 4/King_Moves.c ================================================ #include short count_no_of_legal_king_moves(char[]); int main() { char king_position[3]; short no_of_legal_moves; scanf("%s", king_position); no_of_legal_moves = count_no_of_legal_king_moves(king_position); printf("%hu\n",no_of_legal_moves); return 0; } short count_no_of_legal_king_moves(char king_position[]) { if( ( (king_position[0] == 'a') || (king_position[0] == 'h') ) && ( (king_position[1] == '1') || (king_position[1] == '8') ) )//Corner piece { return 3; } else if( ( (king_position[0] == 'a') || (king_position[0] == 'h') ) || ( (king_position[1] == '1') || (king_position[1] == '8') ) )//Border row or column but not corner piece { return 5; } else { return 8; } } ================================================ FILE: C Programs/C Programs - 4/Lineland_Mail.c ================================================ #include #include void read(long *, unsigned int); void get_minimum(long *, long *, unsigned int); long min(long a, long b); long max(long a, long b); void get_maximum(long *, long *, unsigned int); void display(long *, long *, unsigned int); int main() { unsigned int no_of_cities; scanf("%u",&no_of_cities); long *city = malloc(no_of_cities*sizeof(long)); long *minimum = malloc(no_of_cities*sizeof(long)); long *maximum = malloc(no_of_cities*sizeof(long)); read(city, no_of_cities); get_minimum(minimum, city, no_of_cities); get_maximum(maximum, city, no_of_cities); display(minimum, maximum, no_of_cities); free(city); free(minimum); free(maximum); return 0; } void read(long *city, unsigned int no_of_cities) { unsigned int i; for(i = 0; i < no_of_cities; i++) { scanf("%ld",(city + i)); } } void display(long *minimum, long *maximum, unsigned int no_of_cities) { unsigned int i; for(i = 0; i < no_of_cities; i++) { printf("%ld\t%ld\n",*(minimum + i), *(maximum + i)); } } void get_minimum(long *minimum, long *city, unsigned int no_of_cities) { unsigned int i; //The minimum distance is one of the adjacent cities. The first and last city have only one adjacent city so we solve it separately. *(minimum + 0) = *(city + 1) - *(city + 0); //For First city, it has to be the next city *(minimum + no_of_cities - 1) = *(city + no_of_cities - 1)-*(city + no_of_cities - 2); //For last city, it has to be the previous city for(i = 1; i < no_of_cities - 1; i++) { *(minimum + i) = min( abs(*(city + i) - *(city + i -1)), abs(*(city + i) - *(city + i +1))); //The closer distance among the next and previous city } } long min(long a, long b) { if(a < b) return a; else return b; } long max(long a, long b) { if(a > b) return a; else return b; } void get_maximum(long *maximum, long *city, unsigned int no_of_cities) { unsigned int i; //The cities are given in ascending order. Clearly, the city at the maximum distance is either the first city or the last city. for(i = 0; i < no_of_cities; i++) { *(maximum + i) = max(*(city + i) - *(city + 0), *(city + no_of_cities - 1) - *(city + i)); } } ================================================ FILE: C Programs/C Programs - 4/Lucky_Numbers.c ================================================ #include int main() { unsigned long long max_door_plate_length, no_of_unique_numbers; scanf("%I64u",&max_door_plate_length); //Answer = 2 + 2^2 + 2^3 + ... + 2^n = 2^{n + 1} - 2. When 2 is right shifted n times, the 1 is in position n+1, which is 2^{n+1} no_of_unique_numbers = (2LL << max_door_plate_length) - 2; printf("%I64u",no_of_unique_numbers); return 0; } ================================================ FILE: C Programs/C Programs - 4/PolandBall_and_Hypothesis.c ================================================ #include int find_counterexample(int); int main() { int n, counterexample; scanf("%d",&n); counterexample = find_counterexample(n); printf("%d\n",counterexample); return 0; } //Return m such that m.n + 1 is guaranteed to be composite int find_counterexample(int n) { if(n <= 2) { return 7; //7 works for both 1 and 2 } else { //n(n-2) + 1 = n^2 -1, m = n - 2 always works for n > 2 return (n-2); } } ================================================ FILE: C Programs/C Programs - 4/Professor_Gukiz_Robot.c ================================================ #include #include long maximum(long, long); int main() { long start_x, start_y, final_x, final_y, minimum_moves; scanf("%ld %ld %ld %ld",&start_x, &start_y, &final_x, &final_y); /*First take as many diagonal steps as possible. This is min{|x-x1|, |y - y1|} Then take the required number of line moves. This is max{|x-x1|, |y - y1|} - min{|x-x1|, |y - y1|} The total sum is max{|x-x1|, |y - y1|}*/ minimum_moves = maximum(abs(start_x-final_x),abs(start_y-final_y)); printf("%ld\n",minimum_moves); return 0; } long maximum(long a, long b) { if(a > b) return a; else return b; } ================================================ FILE: C Programs/C Programs - 4/Random_Teams.c ================================================ #include unsigned long long find_minimum(unsigned long long,unsigned long long); unsigned long long find_maximum(unsigned long long,unsigned long long); int main() { unsigned long long no_of_people, no_of_teams, minimum_friends, maximum_friends; scanf("%I64u %I64u",&no_of_people, &no_of_teams); minimum_friends = find_minimum(no_of_people, no_of_teams); maximum_friends = find_maximum(no_of_people, no_of_teams); printf("%I64u %I64u\n",minimum_friends, maximum_friends); return 0; } /*The minimum is obtained when every team has at most one more than the minimum number of people. If there is a team for which the difference between the number of people and the minimum number of people is more than 1, we can reduce the friendships by transfering a person from that team to the minimum team. In this arrangement, the friendships can't be reduced. Transfering from two piles with the same amount of people increases the friendships, And transfering from (p + 1) to p people conserver the number of friendships. This can be obtained in the following way - Place n/m people in each team. Place the remaining n%m people in different teams. n = 13, m = 5 . . . . . . . . . . . . . The number is given by n/m * (n/m C 2) + (n%m)*(n/m) We first count the number of friendships in all m teams when they have n/m people. Then when the remaining n%m people are placed into their teams, new n/m friendships are formed in each team. */ unsigned long long find_minimum(unsigned long long no_of_people,unsigned long long no_of_teams) { unsigned long long minimum; minimum = no_of_teams*(no_of_people/no_of_teams) * ((no_of_people/no_of_teams) - 1) /2; //n/m * (n/m C 2) minimum += (no_of_people%no_of_teams)*( (no_of_people/no_of_teams)); //n%m * (n/m) return minimum; } /*This is obtained when we place one person in m-1 teams each and place all the remaining people in the last team. In any other arrangement, the number of friends can be increased by transfering a person from a given team to the team with the maximum number of people. In this arrangement, no such transfer can take place. This yields the maximum number of friendships. Detailed proofs given in the 'Explanation' part.*/ unsigned long long find_maximum(unsigned long long no_of_people,unsigned long long no_of_teams) { unsigned long long maximum; maximum = (no_of_people - no_of_teams + 1)*(no_of_people - no_of_teams + 1 - 1)/2;//(n - (m-1) ) C 2 return maximum; } ================================================ FILE: C Programs/C Programs - 4/Reconnaissance_2.c ================================================ #include #include void get_difference_of_consecutive_soldiers(unsigned int *, unsigned int *,short); short get_position_of_first_reconnaisance_soldier(unsigned int *,short); int main() { short no_of_soldiers, i, position_of_first_reconnaissance_soldier, position_of_second_reconnaissance_soldier; scanf("%hu",&no_of_soldiers); unsigned int *heights_of_soldier = malloc(no_of_soldiers*sizeof(unsigned int)); unsigned int *consecutive_height_difference = malloc(no_of_soldiers*sizeof(unsigned int)); for(i = 0; i < no_of_soldiers; i++) { scanf("%u",(heights_of_soldier + i)); } get_difference_of_consecutive_soldiers(heights_of_soldier, consecutive_height_difference, no_of_soldiers); position_of_first_reconnaissance_soldier = get_position_of_first_reconnaisance_soldier(consecutive_height_difference, no_of_soldiers); //IF a soldier is standing at position x, then his neighbour is standing at position (x+1)mod n, where n is the number of people in the circle. //The position returned is from 1 to n. We perform mod only on the second number, since we may get (n+1) if the first position is n. if(position_of_first_reconnaissance_soldier == no_of_soldiers) { position_of_second_reconnaissance_soldier = 1; } else { position_of_second_reconnaissance_soldier = position_of_first_reconnaissance_soldier + 1; } printf("%u %u\n",position_of_first_reconnaissance_soldier, position_of_second_reconnaissance_soldier ); free(heights_of_soldier); free(consecutive_height_difference); return 0; } void get_difference_of_consecutive_soldiers(unsigned int *heights_of_soldier, unsigned int *consecutive_height_difference,short no_of_soldiers) { //C[i] = H[i] - H[(i+1)mod n] short i; for(i = 0; i < no_of_soldiers; i++) { *(consecutive_height_difference + i) = abs(*(heights_of_soldier + i) - *(heights_of_soldier + (i + 1)%no_of_soldiers)); } } //Returns position of minimum element of consecutive height difference short get_position_of_first_reconnaisance_soldier(unsigned int *consecutive_height_difference,short no_of_soldiers) { unsigned int minimum = *(consecutive_height_difference + 0); short i, first_soldier_position = 0; for(i = 0; i < no_of_soldiers; i++) { if( *(consecutive_height_difference + i) < minimum) { minimum = *(consecutive_height_difference + i); first_soldier_position = i; } } return first_soldier_position + 1 ;//Pointer arithmetic is performed starting from 0. But, the soldiers are counted starting from 1. So we add 1. } ================================================ FILE: C Programs/C Programs - 4/Selection_of_Personnel.c ================================================ #include int main() { unsigned long long no_of_applications, no_of_teams, no_of_applications_choose_5, no_of_applications_choose_6, no_of_applications_choose_7; scanf("%I64u",&no_of_applications); no_of_applications_choose_5 = (no_of_applications)*(no_of_applications-1)/2*(no_of_applications-2)/3*(no_of_applications-3)/4*(no_of_applications-4)/5; //nC6 = nC5 *(n - 5)/6 and nC7 = nC6* (n - 5)/6 no_of_applications_choose_6 = no_of_applications_choose_5*(no_of_applications - 5)/6; no_of_applications_choose_7 = no_of_applications_choose_6*(no_of_applications - 6)/7; no_of_teams = no_of_applications_choose_5 + no_of_applications_choose_6 + no_of_applications_choose_7; printf("%I64u\n",no_of_teams); return 0; } ================================================ FILE: C Programs/C Programs - 4/Tetrahedron.c ================================================ #include #include unsigned long long find_no_of_cycles(unsigned long long); const long long mod = 1000000007; int main() { unsigned long long no_of_moves, no_of_cyclic_paths; scanf("%I64u",&no_of_moves); no_of_cyclic_paths = find_no_of_cycles(no_of_moves); printf("%I64u\n",no_of_cyclic_paths); return 0; } unsigned long long find_no_of_cycles(unsigned long long no_of_moves) { unsigned long long paths_from_D_i, path_D_i_minus_1; unsigned long long paths_from_ABC_i, path_ABC_i_minus_1; unsigned long long i, no_of_cycles; //f(X, n) is the number of ways to reach D in n moves when ant is on vertex X paths_from_D_i = 1; //f(D, 0) = 1 paths_from_ABC_i = 0; //f(ABC, 0) = 1 for(i = 1; i <= no_of_moves; i++) { path_D_i_minus_1 = paths_from_D_i ; path_ABC_i_minus_1 = paths_from_ABC_i; paths_from_D_i = (3LL* path_ABC_i_minus_1)%mod; //f(D,i) = 3f(ABC, i-1) - From D ant can go to either A, B or C having spent one move. paths_from_ABC_i = (path_D_i_minus_1 + 2LL*path_ABC_i_minus_1)%mod; //f(ABC, i) = f(D,i-1) + 2f(ABC, i-1) - From A, B, C ant can go to either D or two other vertices } no_of_cycles = paths_from_D_i;//f(D, n) is the required number and this is the last value stored in f(D, i) return no_of_cycles; } ================================================ FILE: C Programs/C Programs - 4/Vasya_and_Petya_Game.c ================================================ #include #include void display(unsigned int *, unsigned int); void sundaram_sieve(unsigned int *, unsigned int, unsigned int *); void get_question_sequence(unsigned int *, unsigned int *, unsigned int); int main() { unsigned int number, no_of_questions = 0; scanf("%u",&number); unsigned int *question_sequence = malloc(number*sizeof(question_sequence)); get_question_sequence(question_sequence, &no_of_questions, number); display(question_sequence, no_of_questions); free(question_sequence); return 0; } void display(unsigned int *question_sequence, unsigned int no_of_questions) { unsigned int i; printf("%u\n", no_of_questions); for(i = 0; i < no_of_questions; i++) { printf("%u\t",*(question_sequence + i)); } } /*Question sequence consists of all primes p less than n, raised to every power i, such that p^i <= n*/ void get_question_sequence(unsigned int *question_sequence, unsigned int *no_of_questions, unsigned int number) { unsigned int current_prime, current_prime_power, current_prime_index, primeCount; //Looking at the primes mod 6, except 2 and 3, all primes are 6m + 1 or 6m - 1 unsigned int *primes = malloc((number/3 + 2)*sizeof(unsigned int)); sundaram_sieve(primes, number, &primeCount); //All primes upto the target number for(current_prime_index = 0; current_prime_index < primeCount ; current_prime_index++) { current_prime = *(primes + current_prime_index); //p = p initially current_prime_power = current_prime; //printf("Current prime index = %u\tCurrent prime = %u\n",current_prime_index, *(primes + current_prime_index)); while(current_prime_power <= number) { *(question_sequence + *no_of_questions) = current_prime_power; //printf("Q%u\t",*(question_sequence + *no_of_questions)); *(no_of_questions) = *(no_of_questions) + 1; current_prime_power *= current_prime; //p^{i+1} = p^i * p } } free(primes); } //Crossing out numbers of the form i + j + 2ij void sundaram_sieve(unsigned int *primes, unsigned int target, unsigned int *primeCount) { unsigned i, crossed_out_num, cross_limit, increment; short *auxiliary_list = malloc(target*sizeof(short)); /*f(i,j) = i + j + 2ij For a given value of i, the minimum is when j = 1. Minimum is f(i,1) = 3i + 1 f(i, j + 1) = f(i,j) + 2i + 1 so we only need to increase the value of the crossed number by 2i + 1, instead of updating by one. i goes from 1 to target/2. But, f(i,j) starts from 3i + 1. If i is greater than target/6, then f(i,j) is out of range. So, the minimum Maximum occurs when j = i. f(i,j) = 2i(i+1). The last number to be crossed out for a given i is either 2i(i + 1) or the last f(i,j) before target/2, whichever comes first.*/ //All numbers of the form i + j + 2ij need to be marked out for(i = 0; i < target; i ++) { *(auxiliary_list + i) = 1; } for(i = 1; i <= target/6; i++) { increment = 2*i + 1; cross_limit = 2*i*(i + 1); if(cross_limit > target/2) { cross_limit = target/2; } for(crossed_out_num = 3*i + 1;crossed_out_num <= cross_limit ; crossed_out_num += increment) { *(auxiliary_list + crossed_out_num) = 0; } } //We need to put 2 in ourselves because the algorithm 'only' generates all the odd primes *primeCount = 0; *(primes + *primeCount) = 2; *primeCount = *primeCount + 1; for(i = 1; i <= target/2; i++) { //Checking if the number is not crossed out and adding 2i + 1 to the list if it is unmarked. if(*(auxiliary_list + i) == 1) { *(primes + *primeCount) = (2*i + 1); //printf("%u\t", *(primes + *primeCount)); *primeCount = *primeCount + 1; } } free(auxiliary_list); } ================================================ FILE: C Programs/C Programs - 4/Way_Too_Long_Words.c ================================================ #include #include int main() { short no_of_words, i; char current_word[101]; scanf("%hu",&no_of_words); for(i = 0; i < no_of_words; i++) { scanf("%s",current_word); if(strlen(current_word) > 10) { printf("%c%d%c\n",current_word[0],strlen(current_word)-2, current_word[strlen(current_word)-1]); } else { printf("%s\n",current_word); } } return 0; } ================================================ FILE: C Programs/C Programs - 5/Bear_and_Poker.c ================================================ #include #include #define true 1 #define false 0 void read(int *, int); void reduce_bid(int *, int); short is_possible(int *, int); int main() { int no_of_players; scanf("%d",&no_of_players); int *bid = malloc(no_of_players*sizeof(int)); read(bid, no_of_players); reduce_bid(bid, no_of_players);//dividing the bids till they are coprime to 2 and 3 printf(is_possible(bid, no_of_players) ? "Yes\n" : "No\n"); free(bid); return 0; } //true if all elements are equal short is_possible(int *bid, int no_of_players) { int i; for(i = 1; i < no_of_players; i++) { if(*(bid + i) != *(bid + 0)) return false; } return true; } //Every bid is divided till it is coprime to 2 and 3 void reduce_bid(int *bid, int no_of_players) { int i; for(i = 0; i < no_of_players; i++) { while(*(bid + i) %2 == 0) { *(bid + i) = *(bid + i)/2; } while(*(bid + i) %3 == 0) { *(bid + i) = *(bid + i)/3; } } } void read(int *bid, int no_of_players) { int i; for(i = 0; i < no_of_players; i++) { scanf("%d",(bid + i)); } } ================================================ FILE: C Programs/C Programs - 5/Boredom.c ================================================ #include #define MAX_LENGTH 100000 + 1 void read_frequency(int [], int, int *); long long max(long long ,long long); long long find_maximum_score(int [], int); int main() { int frequency[MAX_LENGTH]= {0}, no_of_numbers, max_in_array = 0; long long maximum_score; scanf("%d",&no_of_numbers); read_frequency(frequency, no_of_numbers, &max_in_array); maximum_score = find_maximum_score(frequency, max_in_array); printf("%I64d\n",maximum_score); return 0; } long long find_maximum_score(int frequency[],int max_in_array) { int i; long long maximum_score_i_minus_2 = 0, maximum_score_i_minus_1 = frequency[1], maximum_score_i = frequency[1]; /*Let f(i) be the greatest score possible where all numbers upto i are deleted. There are two options - Either we delete i by selecting it - f(i-2) + frequency[i]*i. Or we delete it by selecting i-1 - f(i-1) i = 2 to 10^5 f(i) = max{f(i-1), f(i-2) + i*frequency[i]}*/ for(i = 2; i <= 1e5; i++) { maximum_score_i = max(maximum_score_i_minus_1, maximum_score_i_minus_2 + frequency[i]*1LL*i); maximum_score_i_minus_2 = maximum_score_i_minus_1; maximum_score_i_minus_1 = maximum_score_i; } return maximum_score_i; } void read_frequency(int frequency[], int no_of_numbers, int *max_in_array) { int i, current_number; for(i = 0; i < no_of_numbers; i++) { scanf("%d",¤t_number); frequency[current_number]++; *max_in_array = max(*max_in_array, current_number); } } long long max(long long a, long long b) { return (a > b ? a : b); } ================================================ FILE: C Programs/C Programs - 5/Cut_Ribbon.c ================================================ #include #define MAX_LENGTH 4001 #define NEGATIVE_INFINITY -4000 int max(int, int); int find_maximum_number_of_pieces(int, int , int , int ); int main() { int a, b, c, total_length, maximum_number_of_pieces; scanf("%d %d %d %d",&total_length, &a, &b, &c); maximum_number_of_pieces = find_maximum_number_of_pieces(total_length, a, b, c); printf("%d\n",maximum_number_of_pieces); return 0; } int find_maximum_number_of_pieces(int total_length, int a, int b, int c) { int i, max_number_of_pieces[MAX_LENGTH]; for(i = 1; i <= total_length; i++) { max_number_of_pieces[i] = NEGATIVE_INFINITY; } max_number_of_pieces[0] = 0; for(i =a; i <= total_length; i++) { max_number_of_pieces[i] = max(max_number_of_pieces[i],max_number_of_pieces[i-a] + 1); } for(i =b; i <= total_length; i++) { max_number_of_pieces[i] = max(max_number_of_pieces[i],max_number_of_pieces[i-b] + 1); } for(i =c; i <= total_length; i++) { max_number_of_pieces[i] = max(max_number_of_pieces[i],max_number_of_pieces[i-c] + 1); } return max_number_of_pieces[total_length]; } int max(int a, int b) { if(a > b) { return a; } else { return b; } } ================================================ FILE: C Programs/C Programs - 5/Display_Size.c ================================================ #include #include int main() { int no_of_pixels, no_of_rows, no_of_columns; scanf("%d",&no_of_pixels); for(no_of_rows = (int) sqrt(no_of_pixels) ;no_of_rows > 0; no_of_rows--) { if(no_of_pixels%no_of_rows == 0) { break; } } no_of_columns = no_of_pixels/no_of_rows; printf("%d %d\n",no_of_rows, no_of_columns); return 0; } ================================================ FILE: C Programs/C Programs - 5/Duff_in_Love.c ================================================ #include unsigned long long find_product_all_prime_factors(unsigned long long); int main() { unsigned long long n, largest_lovely_number; scanf("%I64u",&n); largest_lovely_number = find_product_all_prime_factors(n); printf("%I64u\n",largest_lovely_number); return 0; } unsigned long long find_product_all_prime_factors(unsigned long long n) { unsigned long long prime_product = 1, reduced_n = n, i; //n = p1^{a1} p2^{a2} ... pk^ {ak}. //Answer is product of n's prime factors a = p_1 p_2 ... p_k //This number is squarefree. And since all numbers from 1 till n are divisible by some combination of these numbers, //the largest squarefree number <= p_1 p_2 ... p_k. since no p^2 divides it. for(i = 2; i*i <= n; i++) { if(reduced_n%i == 0) { prime_product = prime_product*i; //Reducing n from p1^{a1} p2^{a2} ... .pn^ {an} to p2^{a2} ... .pn^ {an} //So that none of the multiples of i divide reduced_n. This ensures only prime factors are multiplies in product. while(reduced_n%i == 0) { reduced_n = reduced_n/i; } } } //N has been reduced to either 1 or a single number greater than root(n) since the composite factors of n are cancelled out, this number must be prime. prime_product = prime_product*reduced_n; return prime_product; } ================================================ FILE: C Programs/C Programs - 5/Flipping_Game.c ================================================ #include #include void read(short *, short); short find_maximum_number_of_ones_after_move(short *, short); short greatest_continuous_sum(short *, short); int max(int, int); int main() { short no_of_numbers, maximum_number_of_ones; scanf("%hu",&no_of_numbers); short *gain = malloc(no_of_numbers*sizeof(short)); read(gain, no_of_numbers); maximum_number_of_ones = find_maximum_number_of_ones_after_move(gain, no_of_numbers); printf("%hu\n",maximum_number_of_ones); free(gain); return 0; } void read(short *gain, short no_of_numbers) { short i, current; for(i = 0; i < no_of_numbers; i++) { scanf("%hu",¤t); /*If there is a 0, the number of 1s increases by 1 after flipping. If it is a 1, the number of 1s increases by -1 after flipping G[i] = -1, if A[i] = 1 and G[i] = 0, if A[i] = 0*/ *(gain + i) = ( (current == 0) ? 1 : -1 ); } } short find_maximum_number_of_ones_after_move(short *gain, short no_of_numbers) { short i, number_of_1s_before_move = 0, number_of_1s_after_move; //This is the number of 1s in the original array. Corresponds to G[i] = -1 for(i = 0; i < no_of_numbers; i++) { if(*(gain + i) == -1) { number_of_1s_before_move++; } } number_of_1s_after_move = greatest_continuous_sum(gain, no_of_numbers); return (number_of_1s_before_move + number_of_1s_after_move); } short greatest_continuous_sum(short *gain, short no_of_numbers) { short i, greatest_sum = *(gain + 0), current_sum = *(gain + 0); for(i = 1; i < no_of_numbers; i++) { current_sum = max(current_sum + *(gain + i), *(gain + i)); greatest_sum = max(greatest_sum, current_sum); } return greatest_sum; } int max(int a, int b) { return (a > b ? a: b); } ================================================ FILE: C Programs/C Programs - 5/Flowers.cpp ================================================ #include #include using namespace std; void count(vector &no_of_ways, int group, int LIMIT) { const int MOD = 1e9 + 7; no_of_ways[0] = 1; for(int i = 1; i < LIMIT; i++) { if(i < group) no_of_ways[i] = 1; else no_of_ways[i] = (no_of_ways[i - 1] + no_of_ways[i - group])%MOD; } } int main() { int no_of_queries, group; scanf("%d %d", &no_of_queries, &group); const int LIMIT = 1e5 + 1, MOD = 1e9 + 7; vector no_of_ways(LIMIT, 0); count(no_of_ways, group, LIMIT); vector no_of_ways_till(LIMIT, 0); for(int i = 1; i < LIMIT; i++) no_of_ways_till[i] = (no_of_ways_till[i - 1] + no_of_ways[i])%MOD; while(no_of_queries--) { int a, b; scanf("%d %d", &a, &b); printf("%d\n", (no_of_ways_till[b] - no_of_ways_till[a - 1] + MOD)%MOD); } return 0; } ================================================ FILE: C Programs/C Programs - 5/Fox_and_Dividing_Cheese.c ================================================ #include #include int find_common_power(int *, int *, int); int main() { int piece_1, piece_2; int answer; scanf("%u %u",&piece_1, &piece_2); answer = find_common_power(&piece_1, &piece_2, 2); answer = answer + find_common_power(&piece_1, &piece_2, 3); answer = answer + find_common_power(&piece_1, &piece_2, 5); printf("%d\n", (piece_1 == piece_2 ? answer : -1) );//Checking if the numbers are equal after 2, 3, 5 have been cancelled out completely. return 0; } //Returns the greatest power of prime which divides both the numbers and reduces both numbers to numbers without the prime. int find_common_power(int *piece_1, int *piece_2, int prime) { int power_1 = 0, power_2 = 0; while(*piece_1 % prime == 0) { *piece_1 = *piece_1/prime; power_1++; } while(*piece_2 % prime == 0) { *piece_2 = *piece_2/prime; power_2++; } return abs(power_1 - power_2); } ================================================ FILE: C Programs/C Programs - 5/Hungry_Sequence.c ================================================ #include int main() { int i, no_of_terms; scanf("%d",&no_of_terms); /*The sequence of consecutive numbers - 2n + 1, 2n + 2, .... , 2n + n - satisfies this property. For any number x, it's largest proper divisor is at most x/2. 2*(x/2) = x If x had a divisor greater than x/2, than it would have to be multiplied by a number less than 2. But there is only one option - 1, The largest proper divisor of any number is this series is smaller than the smallest term of this sequence of consecutive numbers. The greatest divisor of 2n + n, is n + n/2, which is less than 2n + 1 for all positive n. This means that the divisors of any number from this list are smaller than the smallest number in this sequence. So, this is a hungry sequence. There is nothing special about the number 2. Any positive integer value m can be multiplied - nm + 1, nm + 2, ... , mn + n to get a Hungry sequence. Conversely, choose any number from this sequence, x. The smallest multiple of x is 2x. If x = 2n + 1, then 2x = 4n + 2. Now, 4n + 2 > 2n + n, for all positive integers n. Since, the smallest multiple of the smallest element is greater than the largest element of the list, it is a Hungry sequence.*/ for(i = 1; i <= no_of_terms; i++) { printf("%d ", (2*no_of_terms+ i)); } return 0; } ================================================ FILE: C Programs/C Programs - 5/K_Interesting_Pair_of_Integers.c ================================================ #include #define RANGE 10000 void build_population_count(unsigned int[]); void read_and_find_frequency(int[], unsigned int); unsigned long long count_k_interesting_pairs(int[],int, unsigned int[]); int main() { int count[RANGE + 1] = {0}, k; unsigned int population_count[2*RANGE], no_of_elements; unsigned long long no_of_k_interesting_pairs; scanf("%u %d", &no_of_elements, &k); build_population_count(population_count); read_and_find_frequency(count, no_of_elements); no_of_k_interesting_pairs = count_k_interesting_pairs(count, k, population_count); printf("%I64u\n",no_of_k_interesting_pairs); return 0; } //Builds a vector PC - Population Count, where PC[x] has the number of 1s in the binary representation of x void build_population_count(unsigned int population_count[]) { unsigned int i; population_count[0] = 0; /*Let us suppose there is a binary number x - 10001, then we can XOR with 01110 to get 11111. We can XOR to numbers to get a number greater than either of the numbers. What is the greatest number we can get ? If x and y are binary numbers, and x > y, and the first 1 in the binary form of x is at position p (from the right), the greatest value of x XOR y is a number with all 1s from position p. So, x XOR y is always less than a 1 at position (p+1) and all 0s afterwards. So, 2*x is a loose upper bound. That is why we build a population count table till 2* RANGE instead of just RANGE*/ for(i = 1; i <= 2*RANGE; i++) { /*for even x, f(x) = f(x/2) ,the string is left shifted once for odd x, f(x) = f(x/2) + 1 , x/2 is left shifted and then 1 is added We can write this elegantly in one case. */ population_count[i] = population_count[i >> 1] + (i % 2); } } unsigned long long count_k_interesting_pairs(int count[],int k, unsigned int population_count[]) { unsigned int i, j; unsigned long long k_interesting_count = 0; if(k == 0) //k = 0 is a special case. Then if the count of x is n, no of pairs is nC2. { for(i = 0; i <= RANGE; i++) { if(count[i] > 0) { k_interesting_count += (long long)count[i]*(count[i] - 1)/2; //Preventing overflow by typecasting } } } else { for(i = 0; i <= RANGE; i++) { for(j = i + 1; j <= RANGE; j++) { if( (count[j] > 0) && (population_count[i^j] == k) ) { //Explicit typecasting done to prevent overflow k_interesting_count += (long long) count[i]*count[j];//i occurs count[i] times and j count[j]. No of pairs (i,j) s their product } } } } return k_interesting_count; } void read_and_find_frequency(int count[], unsigned int no_of_elements) { unsigned int num, i; for(i = 0; i < no_of_elements; i++) { scanf("%u", &num); count[num]++; } } ================================================ FILE: C Programs/C Programs - 5/Kefa_and_First_Step.c ================================================ #include #include void read(unsigned long *, unsigned int); unsigned int find_length_longest_non_decreasing_streak(unsigned long *, unsigned int); unsigned long max(unsigned long, unsigned long); int main() { unsigned int no_of_days, longest_non_decreasing_streak; scanf("%u",&no_of_days); unsigned long *money_made = malloc(no_of_days*sizeof(unsigned long)); read(money_made, no_of_days); longest_non_decreasing_streak = find_length_longest_non_decreasing_streak(money_made, no_of_days); printf("%u\n",longest_non_decreasing_streak); free(money_made); return 0; } unsigned int find_length_longest_non_decreasing_streak(unsigned long *money_made, unsigned int no_of_days) { unsigned int i, longest_non_decreasing_streak = 1, current_non_decreasing_streak = 1 ; for(i = 1; i < no_of_days; i++) { //If A[i] >= A[i-1], current streak increases, else a new streak begins. current_non_decreasing_streak = ( ( *(money_made + i) >= *(money_made + i -1) ) ? current_non_decreasing_streak+1 : 1 ); longest_non_decreasing_streak = max(longest_non_decreasing_streak, current_non_decreasing_streak); } return longest_non_decreasing_streak; } void read(unsigned long *money_made, unsigned int no_of_days) { unsigned int i; for(i = 0; i < no_of_days; i++) { scanf("%lu",(money_made + i)); } } unsigned long max(unsigned long a, unsigned long b) { return ( (a > b) ? a : b); } ================================================ FILE: C Programs/C Programs - 5/Making_a_String.c ================================================ #include #include void read(long long*, short); void selection_sort_descending(long long*, short); long long min(long long, long long); long long find_longest_string(long long*, short); int main() { short no_of_letters; scanf("%hu",&no_of_letters); long long longest_length, *occurence_of_letter = malloc(no_of_letters*sizeof(long long)); read(occurence_of_letter, no_of_letters); selection_sort_descending(occurence_of_letter, no_of_letters); longest_length = find_longest_string(occurence_of_letter, no_of_letters); printf("%I64d\n",longest_length); free(occurence_of_letter); return 0; } long long find_longest_string(long long*occurence_of_letter, short no_of_letters) { short i; long long longest_length = 0, maximum_frequency_current = *(occurence_of_letter + 0); for(i = 0; (i < no_of_letters) && (maximum_frequency_current > 0); i++) { longest_length += min(maximum_frequency_current, *(occurence_of_letter + i)); maximum_frequency_current = min(maximum_frequency_current, *(occurence_of_letter + i)); maximum_frequency_current--; } return longest_length; } long long min(long long a, long long b) { if(a < b) return a; else return b; } void read(long long*occurence_of_letter, short no_of_letters) { short i; for(i = 0; i < no_of_letters; i++) { scanf("%I64d",(occurence_of_letter + i)); } } void selection_sort_descending(long long*occurence_of_letter, short no_of_letters) { short i, j, largest_index; long long largest; //Every iteration finds the i-th maxima. So, for n elements, we only need to sort n-1 elements. The last element is forced to be in it's correct position. for(i = 0; i < no_of_letters - 1; i++) { largest = *(occurence_of_letter + i); largest_index = i; for(j = i + 1; j < no_of_letters; j++)//Go through the list from i to the end to search for a maxima { if(*(occurence_of_letter + j) > largest) { largest = *(occurence_of_letter + j); largest_index = j; } } //Place the i-th minima in the i-th position, and the element at the i-th position where the maxima was *(occurence_of_letter + largest_index) = *(occurence_of_letter + i); *(occurence_of_letter + i) = largest; } } ================================================ FILE: C Programs/C Programs - 5/Non_Square_Equation.c ================================================ #include #include long long find_solution(long long); int sum_of_digits(long long); int main() { long long n, solution; scanf("%I64d",&n); solution = find_solution(n); printf("%I64d\n",solution); return 0; } //Find smallest x, such that x^2 + s(x)*x = n, where s(x) is the sum of digits of x long long find_solution(long long n) { long long x; long long solution = -1; const int MAX_DIGIT_SUM = 81; //x^2 can be 10^18 at most, x can be 10^9 at most. s(x) can be s(10^9 -1) = 9*9 = 81 at most. x = (int)sqrt(n); while(x*x + MAX_DIGIT_SUM*x >= n) { if(x*x + sum_of_digits(x)*x == n) { solution = x; break; } x--; } return solution; } int sum_of_digits(long long num) { long long temp; int sum = 0; for(temp = num; temp > 0; temp = temp/10) { sum = sum + temp%10; } return sum; } ================================================ FILE: C Programs/C Programs - 5/Odd_Sum.c ================================================ #include #define INFINITY 1e5 + 1 int abs(int); int find_longest_subsequence_odd_sum(int); int main() { int no_of_elements, longest_odd_subsequence_sum; scanf("%d",&no_of_elements); longest_odd_subsequence_sum = find_longest_subsequence_odd_sum(no_of_elements); printf("%d\n",longest_odd_subsequence_sum); return 0; } int find_longest_subsequence_odd_sum(int no_of_elements) { int number, sum = 0, odd_min = INFINITY, i; /*Find the sum of all positive numbers. Keep track of the minimum |x| such that x is odd. If the sum we get is odd, return the sum. Else - the minimum absolute odd number may be odd or even. If it is positive, we delete it from the chosen subsequence. Sum becomes sum - x If it is negative, we add it to the subsequence, Sum becomes sum + x = sum - abs(x) In one line, we can write, sum = sum - abs(x)*/ for(i = 0; i < no_of_elements; i++) { scanf("%d",&number); if(number > 0) { //Only adding positive numbers sum = sum + number; } if(abs(number) % 2 == 1) { //We want the smallest odd number. If it is positive, we remove it from the sum. If it is negative we add it to the sum, in case sum is even odd_min = (abs(number) < odd_min ? abs(number) : odd_min); } } //Returning sum if it is odd. Else, if sum is even, we subtract the smallest odd number so that it's sum is still odd return (sum%2 == 1 ? sum : (sum - abs(odd_min)) ); } int abs(int a) { return (a > 0 ? a : -a); } ================================================ FILE: C Programs/C Programs - 5/Parking_Lot.c ================================================ #include unsigned long long power(unsigned long long, unsigned long long); int main() { unsigned long long no_of_parking_positions, no_of_arrangements, four_power_n_minus_3; scanf("%I64u",&no_of_parking_positions); four_power_n_minus_3 = power(4, no_of_parking_positions - 3); no_of_arrangements = 6*(four_power_n_minus_3 * 4) + (no_of_parking_positions - 3)*9*(four_power_n_minus_3); printf("%I64u",no_of_arrangements); return 0; } unsigned long long power(unsigned long long base, unsigned long long exponent) { unsigned long long answer = 1; if(exponent == 0) { return answer; } //Binary exponentiation algorithm. Number is squared as many times as the number of 0s in binary representation. x^5 = (x^2)^2*x while(exponent > 0) { if(exponent%2 == 1) { answer = answer*base; } base = base*base; exponent = exponent >> 1; } return answer; } ================================================ FILE: C Programs/C Programs - 5/Perfect_Permutation.c ================================================ #include void display_perfect_permutation(unsigned int); int main() { unsigned int no_of_elements; scanf("%u",&no_of_elements); display_perfect_permutation(no_of_elements); return 0; } /*If p(i) = i, then it is clearly a perfect permutation. Since, this is not allowed, we swap adjacent values p(2k) = 2k+ 1 and p(2k + 1) = 2k So, an answer is available for all even n. Since, p(p(i)) = i, every time we change the value of p(i), we must also change the p(i) accordingly. Values have to get changed in pairs. Swapping adjacent values does the trick. However, if there are an odd number of elements, the last element will not have any number to get swapped with and will satisfy p(i) = i. So, there is no perfect permutation for odd i.*/ void display_perfect_permutation(unsigned int no_of_elements) { unsigned int i; if(no_of_elements%2 == 1) { printf("-1\n"); } else { for(i = 1; i < no_of_elements; i = i + 2) { printf("%u %u ",(i + 1), i); } } } ================================================ FILE: C Programs/C Programs - 5/Preparing_for_Olympiad.c ================================================ #include #include void read(long *, int); long min(long, long); long max(long, long); long count_no_of_problem_sets(long *, int,long, long,long); int main() { int no_of_problems; long min_difficulty, max_difficulty,least_difficulty_range, no_of_problem_sets; scanf("%d %ld %ld %ld",&no_of_problems, &min_difficulty, &max_difficulty, &least_difficulty_range); long *problem_difficulty = malloc(no_of_problems*sizeof(long)); read(problem_difficulty, no_of_problems); no_of_problem_sets = count_no_of_problem_sets(problem_difficulty, no_of_problems, min_difficulty, max_difficulty, least_difficulty_range); printf("%ld\n",no_of_problem_sets); free(problem_difficulty); return 0; } long count_no_of_problem_sets(long *problem_difficulty, int no_of_problems,long min_difficulty, long max_difficulty,long least_difficulty_range) { /*We construct a binary string in bijection to the problems chosen. If the i-th bit is 1, then it means that the i-th problem is chosen If i-th bit is 0, then it isn't chosen. This bitmask is n digits long. We know n is always less than 15 The binary string is helpful in visiting every set that can be chosen from these n elements.*/ int current_problem_no, bitmask, total_no_of_problem_sets = 1 << no_of_problems; //No of binary strings of length n is 2^n. 1 right shifted n times is 2^n long total_legitimate_arrangements = 0, current_min_difficulty, current_max_difficulty, problems_in_set; long total_difficulty; //Now, we iterate through all the bitmasks for(bitmask = 1; bitmask < total_no_of_problem_sets; bitmask++) { total_difficulty = 0; problems_in_set = 0; /*The values of minimum and maximum are so set that the first problem selected becomes both min and max and from there it's just the standard way of finding min and max in an array. The min and max can't be set to the first element like usual because the first element may not be part of the chosen set.*/ current_min_difficulty = 1e6 + 1; current_max_difficulty = -1; for(current_problem_no = 0; current_problem_no < no_of_problems; current_problem_no++) { //The number 2^j corresponds with only the j-th problem chosen. We AND this with the current bitmask. If it's non-zero, then j-problem //is chosen in this arrangement if(bitmask & (1 << current_problem_no)) { current_min_difficulty = min(current_min_difficulty, *(problem_difficulty + current_problem_no)); current_max_difficulty = max(current_max_difficulty, *(problem_difficulty + current_problem_no)); total_difficulty = total_difficulty + *(problem_difficulty + current_problem_no); problems_in_set++; } } if( (problems_in_set >= 2) && (total_difficulty >= min_difficulty) && (total_difficulty <= max_difficulty) && (current_max_difficulty-current_min_difficulty >=least_difficulty_range) ) { total_legitimate_arrangements++; } } return total_legitimate_arrangements; } void read(long *problem_difficulty, int no_of_problems) { int i; for(i = 0; i < no_of_problems; i++) { scanf("%ld",(problem_difficulty + i)); } } long min(long a, long b) { if(a < b) return a; else return b; } long max(long a, long b) { if(a > b) return a; else return b; } ================================================ FILE: C Programs/C Programs - 5/Star.c ================================================ #include int main() { unsigned long long n, star_n; scanf("%I64u",&n); //A star number consists of a central number and 12 copies of the (n-1)th triangular number star_n = 6LL*n*(n-1) + 1; printf("%I64u",star_n); return 0; } ================================================ FILE: C Programs/C Programs - 5/Table_Tennis_Game_2.c ================================================ #include long find_no_of_sets(unsigned long,unsigned long ,unsigned long); int main() { unsigned long no_of_points_in_a_set, misha_points, vanya_points; long no_of_sets; scanf("%lu %lu %lu",&no_of_points_in_a_set, &misha_points, &vanya_points); no_of_sets = find_no_of_sets(no_of_points_in_a_set, misha_points, vanya_points); printf("%ld\n",no_of_sets); return 0; } long find_no_of_sets(unsigned long no_of_points_in_a_set,unsigned long misha_points,unsigned long vanya_points) { long no_of_sets, misha_sets, vanya_sets; //(a +b) might cause overflow. So doing (a%k + b%k) %k misha_sets = misha_points/no_of_points_in_a_set; vanya_sets = vanya_points/no_of_points_in_a_set; no_of_sets = (misha_sets + vanya_sets); if( (no_of_sets == 0) ||(misha_sets == 0 && vanya_points%no_of_points_in_a_set != 0) ||(vanya_sets == 0 && misha_points%no_of_points_in_a_set != 0) ) { no_of_sets = -1; } return no_of_sets; } ================================================ FILE: C Programs/C Programs - 5/Tavas_and_Saddas.c ================================================ #include #define MAX_NO_DIGITS 11 unsigned int get_index(char[]); int main() { char lucky_number[MAX_NO_DIGITS]; unsigned int index; scanf("%s",lucky_number); index = get_index(lucky_number); printf("%u\n",index); return 0; } unsigned int get_index(char lucky_number[]) { short i; unsigned int index = 1; //index can be atmost 2^{11} - 1 - A binary string with 11 ones. Int is sufficient /*Construct a binary string in correspondence to the lucky number, b[0] = 0, b[i + 1] = 0, if d[i] = 4 and b[i + 1] = 1, if d[i] = 7 4 corresponds with 01, 7 with 11, 44 with 001, 47 with 011 and so on. Where b[i] is the i-th letter of the binary string, and d[i] is the i-th letter of the decimal string. The binary string must be read from right to left. The binary number we get is (reversed) always one more than the lexicographic number of the digit we have gotten since the first string is 2 and not 1. So, we subtract 1 at the end, after constructing a binary number from the given decimal string. We read the decimal string from right to left and then keep shifting each character to the left so that the rightmost character is at the left. This way we already get the reversed binary string, as required. */ for(i = 0; lucky_number[i] != '\0'; i++) { if(lucky_number[i] == '4') { index = (index << 1); } else if(lucky_number[i] == '7') { index = (index << 1) + 1; } } index = index - 1; return index; } ================================================ FILE: C Programs/C Programs - 5/Team.c ================================================ #include int main() { short no_of_problems, vasya, petya, tonya, i, total_problems_solved = 0; scanf("%hu",&no_of_problems); for(i = 1; i <= no_of_problems; i++) { scanf("%hu %hu %hu",&vasya, &petya, &tonya); total_problems_solved = total_problems_solved + (vasya + petya + tonya >= 2 ? 1 : 0); } printf("%hu\n",total_problems_solved); return 0; } ================================================ FILE: C Programs/C Programs - 5/Tetrahedron_Efficiently.c ================================================ #include unsigned long long find_no_of_cycles(int); void raise_matrix_power(unsigned long long[][2], int); void multiply(unsigned long long [][2], unsigned long long [][2]); void copy(unsigned long long [][2], unsigned long long [][2]); const long long mod = 1e9 + 7; int main() { int no_of_moves; unsigned long long no_of_cyclic_paths; scanf("%d",&no_of_moves); no_of_cyclic_paths = find_no_of_cycles(no_of_moves); printf("%I64u\n",no_of_cyclic_paths); return 0; } unsigned long long find_no_of_cycles(int no_of_moves) { unsigned long long matrix[2][2]; if(no_of_moves == 0) { return 1; } /* | f^n(D) | = | 0 3 | | f^{n-1}(D) | | f^n(ABC) | = | 1 2 | | f^{n-1}(ABC) | Also, f^0(D) = 1 and f^0(ABC) = 0. */ matrix[0][0] = 0; matrix[0][1] = 3; matrix[1][0] = 1; matrix[1][1] = 2; raise_matrix_power(matrix, no_of_moves); return (matrix[0][0]*1 + matrix[0][1]*0);//f^n(D) = first_row(A^n) * (1, 0) } //Binary exponentiation void raise_matrix_power(unsigned long long matrix[][2], int exponent) { unsigned long long answer[2][2]; /*Initialise it to identity Answer = I_2*/ answer[0][0] = answer[1][1] = 1; answer[0][1] = answer[1][0] = 0; while(exponent > 0) { if(exponent%2 == 1) { multiply(answer, matrix);//Answer = Answer*A } multiply(matrix, matrix); //A = A*A exponent = exponent >> 1; } copy(matrix, answer); } void multiply(unsigned long long matrix_1[][2], unsigned long long matrix_2[][2]) { short i, j, k; unsigned long long product[2][2]; for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { product[i][j] = 0; for(k = 0; k < 2; k++) { product[i][j] += matrix_1[i][k]*matrix_2[k][j]; product[i][j] = (product[i][j]% mod); } } } copy(matrix_1, product); } void copy(unsigned long long matrix_1[][2], unsigned long long matrix_2[][2]) { short i, j; for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { matrix_1[i][j] = matrix_2[i][j]; } } } ================================================ FILE: C Programs/C Programs - 5/Tricky_Sum.c ================================================ #include int main() { short no_of_test_cases, i; long long answer, n, power_of_2_to_be_subtracted = 0; scanf("%hu",&no_of_test_cases); for(i = 0; i < no_of_test_cases; i++) { scanf("%I64d",&n); power_of_2_to_be_subtracted = 0; answer = n*(n+1)/2; //The greatest power of 2 less than n is 2^{i-1}, where i is the position of it's most siginificant byte in binary. //The sum of all powers of 2 upto 2^i corresponds to a string of i 1s, which is what we construct here. while(n > 0) { power_of_2_to_be_subtracted = (power_of_2_to_be_subtracted << 1) + 1; n = n >> 1; } //Answer = sum(n) - 2(sum (powers of 2) ) because they are also counted once in sum(n). answer = answer - (power_of_2_to_be_subtracted << 1); printf("%I64d\n",answer); } return 0; } ================================================ FILE: C Programs/C Programs - 5/Vacations.c ================================================ #include int main() { short no_of_days, i, current_activity, previous_activity = 0, rest_days = 0; scanf("%hu",&no_of_days); for(i = 1; i <= no_of_days; i++) { scanf("%hu",¤t_activity); /*If the gym is closed and there is no contest, he takes rest. Else, if gym is open today and he went to the gym the previous day, he is forced to take rest. Same reasoning for the contest. If only contest is available today and he went to contest yesterday, he is forced to rest.*/ if( (current_activity == 0) || (current_activity == 1 && previous_activity == 1) || (current_activity == 2 && previous_activity == 2) ) { rest_days++; previous_activity = 0; //Previous activity for the next day. } else { //If he went to contest the previous day, go to gym. If he went to gym the previous day go to contest. If it was rest, do either. if(current_activity == 3) { //If previous = 1, do 2 on the current day. //If previous = 2, do 1 on the current day //If previous = 0, do 3 on the current day //If previous = 3, do 3 on the current day as well. //What is done on the current day is the previous activity for the next day. previous_activity = ( (previous_activity < 3) ? (3 - previous_activity) : previous_activity); } else //If it isn't 3, then record the exact event. { previous_activity = current_activity; } } } printf("%hu\n",rest_days); return 0; } ================================================ FILE: C Programs/C Programs - 5/Vanya_and_Table.c ================================================ #include unsigned int count_cells_covered(unsigned int); int main() { unsigned int no_of_rectangles, total_cells_counted; scanf("%u",&no_of_rectangles); total_cells_counted = count_cells_covered(no_of_rectangles); printf("%u\n",total_cells_counted); return 0; } unsigned int count_cells_covered(unsigned int no_of_rectangles) { unsigned int i, x1, x2, y1, y2, no_of_cells_counted = 0; for(i = 0; i < no_of_rectangles; i++) { scanf("%u %u %u %u", &x1, &y1, &x2, &y2); no_of_cells_counted = no_of_cells_counted + (x2 - x1 + 1)*(y2 - y1 + 1); //This is the number of cells in the current rectangle. The last //cell has a point (x2 + 1, y2 + 1). We want to count it as well. } return no_of_cells_counted; } ================================================ FILE: C Programs/C Programs - 6/A_Shell_Game.c ================================================ #include #define NO_OF_SHUFFLES 3 int main() { int ball_shell, shell_1, shell_2, i; FILE *input = fopen("input.txt", "r"); FILE *output = fopen("output.txt", "w"); fscanf(input, "%d", &ball_shell); for(i = 1; i <= NO_OF_SHUFFLES; i++) { fscanf(input,"%d %d",&shell_1, &shell_2); if(ball_shell == shell_1) { ball_shell = shell_2; } else if(ball_shell == shell_2) { ball_shell = shell_1; } } fprintf(output,"%d\n",ball_shell); fclose(input); fclose(output); return 0; } ================================================ FILE: C Programs/C Programs - 6/Accounting.c ================================================ #include #include #define NOT_POSSIBLE -10 int find_coefficient_of_income(int,int ,short); int power(int, int); int main() { int money_at_beginning, money_at_end, coefficient_of_income_growth; short no_of_years; scanf("%d %d %hu",&money_at_beginning, &money_at_end, &no_of_years); coefficient_of_income_growth = find_coefficient_of_income(money_at_beginning, money_at_end, no_of_years); if(coefficient_of_income_growth == NOT_POSSIBLE) { printf("No solution\n"); } else { printf("%d\n",coefficient_of_income_growth); } return 0; } int find_coefficient_of_income(int money_at_beginning,int money_at_end, short no_of_years) { int assumed_coefficient, expected_answer ; if(money_at_beginning == 0)//No solution then { /*If both a = b= 0, then any value of x satisfies the equation If a is 0 and b is non zero, there is no solution*/ assumed_coefficient = (money_at_end == 0 ? 1 : NOT_POSSIBLE); return assumed_coefficient; } else { if(abs(money_at_end)% abs(money_at_beginning) != 0) { return NOT_POSSIBLE; } expected_answer = money_at_end/money_at_beginning; //X^n = b/a } if(expected_answer > 0) { for(assumed_coefficient = 0; power(assumed_coefficient, no_of_years) < expected_answer; assumed_coefficient++); } else { for(assumed_coefficient = 0; power(assumed_coefficient, no_of_years) > expected_answer; assumed_coefficient--); } //printf("%d\t%d\t=%d\n",assumed_coefficient,power(assumed_coefficient, 1),expected_answer); if(power(assumed_coefficient, no_of_years) != expected_answer) { assumed_coefficient = NOT_POSSIBLE; } return assumed_coefficient; } int power(int x,int n) { return (n == 0 ? 1 : x*power(x, n-1)); } ================================================ FILE: C Programs/C Programs - 6/Anton_and_Digits.c ================================================ #include #define min(a, b) (a < b ? a : b) #define min_of_3(a,b,c) min(a, min(b,c)) int main() { unsigned int no_of_2, no_of_3, no_of_5, no_of_6, no_of_256, no_of_32, sum = 0; scanf("%u %u %u %u",&no_of_2, &no_of_3, &no_of_5, &no_of_6); no_of_256 = min_of_3(no_of_2, no_of_5, no_of_6); //Make as many 256s as possible no_of_32 = min(no_of_2 - no_of_256, no_of_3); //Some of the 2s have been used in 256s. sum = 256*no_of_256 + 32*no_of_32; printf("%u\n",sum); return 0; } ================================================ FILE: C Programs/C Programs - 6/Black_Square.c ================================================ #include #define MAX_LENGTH 100001 int main() { int calories[5],total_calories = 0, i; char game[MAX_LENGTH]; for(i = 1; i <= 4; i++) //For convenience start the array index from 1-4, because the string also contains elements from 1-4 { scanf("%d", &calories[i]); } scanf("%s",game); for(i = 0; game[i] != '\0'; i++) { total_calories += calories[game[i] - '0']; } printf("%d\n",total_calories); return 0; } ================================================ FILE: C Programs/C Programs - 6/Dinner_with_Emma.c ================================================ #include #define INFINITY 1e9 + 1 #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) int main() { short no_of_streets, no_of_avenues, i, j; unsigned int current_cost, minimum_street_cost, maximum_street_minimum_cost = 0; scanf("%hu %hu",&no_of_streets, &no_of_avenues); for(i = 0; i < no_of_streets; i++) { //Find the minimum cost on the current street minimum_street_cost = INFINITY; for(j = 0; j < no_of_avenues; j++) { scanf("%u",¤t_cost); minimum_street_cost = min(minimum_street_cost, current_cost); } //Among the set of minimum costs on each street, choose the maximum element maximum_street_minimum_cost = max(maximum_street_minimum_cost, minimum_street_cost); } printf("%u\n",maximum_street_minimum_cost); return 0; } ================================================ FILE: C Programs/C Programs - 6/Ebony_and_Ivory.c ================================================ #include #include #define true 1 #define false 0 int main() { int ebony, ivory, shield, i; scanf("%d %d %d", &ebony, &ivory, &shield); short *is_possible = malloc( (shield + 100)*sizeof(short)); *(is_possible + 0) = true; for(i = 0; i <= shield; i++) { if(*(is_possible + i) == true) //If c is possible, then c + a, and c + b are possible as well. { *(is_possible + i + ebony) = true; *(is_possible + i + ivory) = true; } } printf(*(is_possible + shield) == true ? "Yes\n" : "No\n"); free(is_possible); return 0; } ================================================ FILE: C Programs/C Programs - 6/Find Amir.c ================================================ #include int main() { int no_of_schools, minimum_cost; scanf("%d",&no_of_schools); /*Firstly, make as many pairs of 0 cost as possible. {1 + n}, {2, n-1}, {3, n-2} ... {n/2, n/2 + 1} if n is even. If n is odd, then n/2 + 1 is unpaired. These pairs have 0 cost. Since a ticket can be used multiple times, it is sufficient to connect these pairs. The minimum way to do this is to pay a cost of 1 n/2 + (n/2 + 2) = n + 2 = 1 (mod n+1) n/2-1 + (n/2 + 3) = n + 2 n/2-2 + (n/2 + 4) = n + 2 If n is even, then there are n/2 pairs. These n/2 pairs can be connected in (n/2 - 1) tickets of price 1. For example, if there are 10 pairs, there are 5 pairs, and 4 tickets can connect them. So, cost is (n/2 - 1). If n is odd, then there are n/2 pairs (which can be connected in (n/2 - 1) tickets). Also, n/2 + 1 is isolated. n/2 + 1 should be connected to n/2 + 2. So, there are (n/2 - 1 + 1) = n/2 tickets of cost 1.*/ minimum_cost = (no_of_schools%2 == 0 ? no_of_schools/2 - 1 : no_of_schools/2); printf("%d\n", minimum_cost); return 0; } ================================================ FILE: C Programs/C Programs - 6/Game_with_Sticks.c ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int horizontal, vertical; scanf("%d %d", &horizontal, &vertical); //It doesn't matter which stick is taken. After it is taken, the grid is reduced to (m-1, n-1) //Whoever gets the configuration (1, x) or (x, 1) wins. //If min(m, n) is even, the minimum becomes odd on Malvika's turn so Malvika gets the configuration (1, x) //If min(m, n) is odd, then the minimum is odd on the first player's turns. So, the first player wins. printf( min(horizontal, vertical)%2 == 0 ? "Malvika\n" : "Akshat\n"); return 0; } ================================================ FILE: C Programs/C Programs - 6/Increasing_Sequence.c ================================================ #include int main() { int no_of_elements, i, current_number, previous_number = 0,step_length, no_of_steps_to_be_added, no_of_operations_performed = 0; scanf("%d %d",&no_of_elements, &step_length); for(i = 1; i <= no_of_elements; i++) { scanf("%d",¤t_number); if(previous_number >= current_number) { //We need to add enough steps to make current number atleast previous number + 1. //This is at least (previous number - current number + 1)/step length //If it is not a perfect multiple of step length, then we need to add one more step because integer division finds the floor. no_of_steps_to_be_added = (previous_number - current_number + 1)/step_length; no_of_steps_to_be_added += (previous_number - current_number + 1)%step_length == 0 ? 0 : 1; current_number = current_number + no_of_steps_to_be_added*step_length; no_of_operations_performed += no_of_steps_to_be_added; } previous_number = current_number; } printf("%d\n",no_of_operations_performed); return 0; } ================================================ FILE: C Programs/C Programs - 6/Insomnia_Cure.c ================================================ #include int main() { int punched, trapped, trampled, mothered, total_dragons, i, harmed_dragons = 0; scanf("%d %d %d %d %d", &punched, &trapped, &trampled, &mothered, &total_dragons); for(i = 1; i <= total_dragons; i++) { if(i%punched == 0 || i%trapped == 0 || i%trampled == 0 || i%mothered == 0) { harmed_dragons++; } } printf("%d\n",harmed_dragons); return 0; } ================================================ FILE: C Programs/C Programs - 6/Jumping_Ball.c ================================================ #include #include int find_eventually_falling_bumpers(char *, int); int main() { int no_of_bumpers, no_of_bumpers_leading_to_fall; scanf("%d",&no_of_bumpers); char *bumpers = malloc((no_of_bumpers+1)*sizeof(char)); scanf("%s",bumpers); no_of_bumpers_leading_to_fall = find_eventually_falling_bumpers(bumpers, no_of_bumpers); printf("%d\n",no_of_bumpers_leading_to_fall); free(bumpers); return 0; } int find_eventually_falling_bumpers(char *bumpers, int no_of_bumpers) { int i, fall_count = 0; for(i = 0; (*(bumpers + i) == '<') && (*(bumpers + i) != '\0'); i++,fall_count++);//No of < in the beginning before the first > or end of string for(i = no_of_bumpers - 1; (*(bumpers + i) == '>') && ( i >= 0); i--, fall_count++);//No of > in the end before the last < or beginning of string return fall_count; } ================================================ FILE: C Programs/C Programs - 6/K_Tree.c ================================================ #include unsigned long calculate_no_of_paths(short, short, short); int main() { short sum, no_of_children, d; unsigned long no_of_paths; scanf("%hu %hu %hu",&sum, &no_of_children, &d); no_of_paths = calculate_no_of_paths(sum, no_of_children, d); printf("%lu\n",no_of_paths); return 0; } unsigned long calculate_no_of_paths(short sum, short no_of_children, short d) { unsigned long no_of_paths[101][2]; short i, j; const unsigned long mod = (1e9 + 7); no_of_paths[0][0] = 1; no_of_paths[0][1] = 0; /*Here, f(n, i) represents the number of paths which sum up to n. i is a boolean value which is 1 if the path contains an edge atleast d and 0 otherwise We make a recurrence based on selecting each child separately. f(n, 0) = f(n-1, 0) + f(n-2, 0) + ... + f(n - min{n, d-1}, 0) Other case - f(n, 1) = f(n-1, 1) + f(n-2, 1) + ... + f(n - min{n, d-1}, 1) + {f(n - d, 0) + f(n - d, 1} + ... + {f(n - k, 0) + f(n - k, 1)}*/ for(i = 1; i <= sum; i++) { no_of_paths[i][0] = no_of_paths[i][1] = 0; for(j = 1; ((j <= no_of_children) && (i-j >= 0)); j++) { if(j < d) { no_of_paths[i][0] =(no_of_paths[i][0]+ no_of_paths[i-j][0])%mod; no_of_paths[i][1] = (no_of_paths[i][1] + no_of_paths[i-j][1])%mod; } else { no_of_paths[i][1] = (no_of_paths[i][1] + no_of_paths[i-j][0])%mod; no_of_paths[i][1] = (no_of_paths[i][1] + no_of_paths[i-j][1])%mod; } } } return no_of_paths[sum][1]; } ================================================ FILE: C Programs/C Programs - 6/Lovely_Palindromes.c ================================================ #include #include #define MAX_LENGTH 100002 int main() { char string[MAX_LENGTH], reverse[MAX_LENGTH]; int length, i; scanf("%s",string); length = strlen(string); for(i = 0; i < length; i++) { reverse[i] = string[length - i - 1]; } reverse[length] = '\0'; printf("%s%s\n",string,reverse); return 0; } ================================================ FILE: C Programs/C Programs - 6/Luxurious_Buildings.c ================================================ #include #include #define maximum(a, b) (a > b ? a : b) void read(int *, int); void display(int *, int); void make_every_building_luxurious(int *, int *, int); int main() { int no_of_buildings; scanf("%d",&no_of_buildings); int *no_of_floors = malloc(no_of_buildings*sizeof(int)); int *no_of_floors_to_be_added = malloc(no_of_buildings*sizeof(int)); read(no_of_floors, no_of_buildings); make_every_building_luxurious(no_of_floors, no_of_floors_to_be_added, no_of_buildings); display(no_of_floors_to_be_added, no_of_buildings); free(no_of_floors); free(no_of_floors_to_be_added); return 0; } void make_every_building_luxurious(int *no_of_floors, int *no_of_floors_to_be_added, int no_of_buildings) { int i, max = *(no_of_floors + no_of_buildings - 1); *(no_of_floors_to_be_added + no_of_buildings - 1) = 0; for(i = no_of_buildings - 2; i >= 0; i--) { *(no_of_floors_to_be_added + i) = (max >= *(no_of_floors + i) ) ? (max - *(no_of_floors + i) + 1) : 0 ; max = maximum(max, *(no_of_floors + i) ) ; } } void read(int *no_of_floors, int no_of_buildings) { int i; for(i = 0; i < no_of_buildings; i++) { scanf("%d",(no_of_floors + i)); } } void display(int *no_of_floors_to_be_added, int no_of_buildings) { int i; for(i = 0; i < no_of_buildings; i++) { printf("%d ",*(no_of_floors_to_be_added + i)); } } ================================================ FILE: C Programs/C Programs - 6/Meeting_of_Old_Friends.c ================================================ #include #define max(a,b) (a > b ? a : b) #define min(a,b) (a < b ? a : b) int main() { long long sonya_start, sonya_end, filya_start, filya_end, no_of_minutes, prinking_minute, meeting_start, meeting_end; scanf("%I64d %I64d %I64d %I64d %I64d",&sonya_start, &sonya_end, &filya_start, &filya_end, &prinking_minute); meeting_start = max(sonya_start, filya_start); meeting_end = min(sonya_end, filya_end); no_of_minutes = (meeting_end >= meeting_start) ? (meeting_end - meeting_start + 1) : 0; //Inclusive of starting and ending time no_of_minutes -= (prinking_minute >= meeting_start) && (prinking_minute <= meeting_end)? 1 : 0; //Decrement 1 if k is in the meeting time printf("%I64d\n",no_of_minutes); return 0; } ================================================ FILE: C Programs/C Programs - 6/Oleg_and_Shares.c ================================================ #include #include #define min(a,b) (a < b ? a : b) #define INFINITY 1e9 + 1 int read_and_find_minimum(int *, int); long long find_no_of_days_equalise_shares(int *, int, int, int); int main() { int no_of_shares, decreasing_amount, minimum_share; long long no_of_days; scanf("%d %d", &no_of_shares, &decreasing_amount); int *share = malloc(no_of_shares*sizeof(int)); minimum_share = read_and_find_minimum(share, no_of_shares); no_of_days = find_no_of_days_equalise_shares(share, no_of_shares, decreasing_amount, minimum_share); printf("%I64d\n",no_of_days); free(share); return 0; } long long find_no_of_days_equalise_shares(int *share, int no_of_shares,int decreasing_amount,int minimum_share) { int i; long long no_of_days = 0; for(i = 0; i < no_of_shares; i++) { if( ( *(share + i) - minimum_share) % decreasing_amount != 0) { no_of_days = -1; break; } else { no_of_days = no_of_days + (( *(share + i) - minimum_share) / decreasing_amount); } } return no_of_days; } int read_and_find_minimum(int *share, int no_of_shares) { int i, minimum = INFINITY; for(i = 0; i < no_of_shares; i++) { scanf("%d",(share + i)); minimum = min(minimum, *(share + i)); } return minimum; } ================================================ FILE: C Programs/C Programs - 6/Patrick_and_Shopping.c ================================================ #include #define min(a,b) (a < b ? a : b) int main() { int distance_1, distance_2, distance_between_shops, minimum_distance; scanf("%d %d %d",&distance_1, &distance_2, &distance_between_shops); minimum_distance = min(distance_1 + distance_between_shops + distance_2, 2*(distance_1 + distance_2)); minimum_distance = min(minimum_distance, 2*(distance_1 + distance_between_shops)); minimum_distance = min(minimum_distance, 2*(distance_2 + distance_between_shops)); printf("%d\n",minimum_distance); return 0; } ================================================ FILE: C Programs/C Programs - 6/Plate_Game.c ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int side_a, side_b, radius; scanf("%d %d %d",&side_a, &side_b, &radius); //If the first player can't place a plate, the second player wins. Else, the first player always wins. He places a plate in the center of the table. //And then places a table diagonally opposite to wherever the second player places a table printf(min(side_a, side_b) < (2*radius) ? "Second\n" : "First\n"); return 0; } ================================================ FILE: C Programs/C Programs - 6/Rewards.c ================================================ #include int main() { int gold_trophy, silver_trophy, bronze_trophy, gold_medal, silver_medal, bronze_medal, total_trophies, total_medals, no_of_shelves; int trophy_shelves, medal_shelves; scanf("%d %d %d",&gold_trophy, &silver_trophy, &bronze_trophy); scanf("%d %d %d",&gold_medal, &silver_medal, &bronze_medal); scanf("%d",&no_of_shelves); total_trophies = gold_trophy + silver_trophy + bronze_trophy; total_medals = gold_medal + silver_medal + bronze_medal; trophy_shelves = (total_trophies%5 == 0 ? total_trophies/5 : total_trophies/5 + 1); medal_shelves = (total_medals%10 == 0 ? total_medals/10 : total_medals/10 + 1); printf(trophy_shelves + medal_shelves <= no_of_shelves ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 6/Round_House.c ================================================ #include int main() { int no_of_houses, starting_house, no_of_houses_travelled, ending_house; scanf("%d %d %d", &no_of_houses, &starting_house, &no_of_houses_travelled); /*Simple modular arithmetic - (a + b) mod n However, the house numbers start from 1. And the modular class start from 0. So, {(a - 1 + b) mod n } + 1 -1 is added to a so that the house starts from 0 and then 1 is added at the end to balance the answer out. To ensure the number is positive, if (a - 1 + b)mod n, is negative, then n is added to it to keep it positive.*/ ending_house = (starting_house - 1 + no_of_houses_travelled)%no_of_houses + 1; ending_house = ending_house + (ending_house <= 0 ? no_of_houses : 0); printf("%d\n",ending_house); return 0; } ================================================ FILE: C Programs/C Programs - 6/System_of_Equations.c ================================================ #include int main() { int n, m, no_of_solutions = 0, i, j; scanf("%d %d", &n, &m); for(i = 0; i <= m; i++) { for(j = 0; j <= n; j++) { if( (i*i + j == n) && (i + j*j == m)) { no_of_solutions++; } } } printf("%d\n",no_of_solutions); return 0; } ================================================ FILE: C Programs/C Programs - 6/Vanya_and_Fence.c ================================================ #include int main() { int no_of_people, i, height_fence, current_height, total_width = 0; scanf("%d %d ",&no_of_people,&height_fence); for(i = 1; i <= no_of_people; i++) { scanf("%d",¤t_height); total_width += (current_height > height_fence ? 2 : 1); //bent person has width 2 } printf("%d\n",total_width); return 0; } ================================================ FILE: C Programs/C Programs - 6/Vanya_and_Lanterns.c ================================================ #include #include #define max(a,b) (a > b ? a : b) void read(int *, int); void selection_sort(int *, int); float find_maximum_radius(int *, int, int); int main() { int no_of_lanterns, street_length; float maximum_radius; scanf("%d %d", &no_of_lanterns, &street_length); int *lantern_position = malloc(no_of_lanterns*sizeof(int)); read(lantern_position, no_of_lanterns); selection_sort(lantern_position, no_of_lanterns); maximum_radius = find_maximum_radius(lantern_position, no_of_lanterns, street_length); printf("%.6f",maximum_radius); free(lantern_position); return 0; } float find_maximum_radius(int *lantern_position, int no_of_lanterns, int street_length) { float maximum_radius = 0; int i; for(i = 1; i < no_of_lanterns; i++) { maximum_radius = max(maximum_radius, (*(lantern_position + i) - *(lantern_position + i - 1)) ); } //Finding the maximum of distance between first lantern and beginning and last lantern and ending. maximum_radius = maximum_radius/2; //We have only compared adjacent lamps so divide by 2. maximum_radius = max(maximum_radius, *(lantern_position + 0)); maximum_radius = max(maximum_radius, street_length - *(lantern_position + no_of_lanterns - 1)); return maximum_radius; } void read(int *lantern_position, int no_of_lanterns) { int i; for(i = 0; i < no_of_lanterns; i++) { scanf("%d",(lantern_position + i)); } } void selection_sort(int *lantern_position, int no_of_lanterns) { int i, j, smallest, smallest_index; //Every iteration finds the i-th minima. So, for n elements, we only need to sort n-1 elements. The last element is forced to be in it's correct position. for(i = 0; i < no_of_lanterns - 1; i++) { smallest = *(lantern_position + i); smallest_index = i; for(j = i + 1; j < no_of_lanterns; j++)//Go through the list from i to the end to search for a minima { if(*(lantern_position + j) < smallest) { smallest = *(lantern_position + j); smallest_index = j; } } //Place the i-th minima in the i-th position, and the element at the i-th position where the minima was *(lantern_position + smallest_index) = *(lantern_position + i); *(lantern_position + i) = smallest; } } ================================================ FILE: C Programs/C Programs - 6/Vasya_and_Hipster.c ================================================ #include #define min(a,b) (a < b ? a : b) #define max(a,b) (a > b ? a : b) int main() { int red_socks, blue_socks, no_of_days_different_socks, no_of_days_same_socks; scanf("%d %d", &red_socks, &blue_socks); no_of_days_different_socks = min(red_socks, blue_socks); no_of_days_same_socks = (max(red_socks, blue_socks) - min(red_socks, blue_socks))/ 2; printf("%d %d\n",no_of_days_different_socks, no_of_days_same_socks); return 0; } ================================================ FILE: C Programs/C Programs - 6/Wizard_Duel.c ================================================ #include int main() { int length_of_corridor, speed_of_Harry_spell, speed_of_voldemort_spell; float time_taken, distance_from_Harry; scanf("%d %d %d",&length_of_corridor, &speed_of_Harry_spell, &speed_of_voldemort_spell); //L-x = tq, x = tp therefore L = t(p + q) //The speed is constant. So, the spells reach their casters with the same time with which they reached their meeting point. //From here, the situation is exactly the same as the first spell. That means all the collisions happen at the same point. time_taken = length_of_corridor/(float)(speed_of_Harry_spell + speed_of_voldemort_spell); distance_from_Harry = time_taken*speed_of_Harry_spell; printf("%f\n",distance_from_Harry); return 0; } ================================================ FILE: C Programs/C Programs - 7/3_Palindrome.c ================================================ #include int main() { int number_of_letters, i; scanf("%d", &number_of_letters); //No letter must have the same neighbour on both the left and the right. aabbaabbaabb.... satisfies this condition for(i = 1; i <= number_of_letters; i = i+2) { //If n is odd, then only one letter should be printed at the end. if(i%4 == 1) { printf(i == number_of_letters ? "a\n" : "aa"); } else { printf(i == number_of_letters ? "b\n" : "bb"); } } return 0; } ================================================ FILE: C Programs/C Programs - 7/Alena_Schedule.c ================================================ #include #define YES 1 #define NO 0 int main() { int no_of_classes, i, continuous_breaks = 0, first_class, total_breaks = 0, current_class; scanf("%d", &no_of_classes); //Adding all the leading zeroes for(first_class = 1; first_class <= no_of_classes; first_class++) { scanf("%d", ¤t_class); if(current_class == 1) break; else total_breaks++; } for(i = first_class + 1; i <= no_of_classes; i++) { scanf("%d", ¤t_class); if(current_class == 1 && continuous_breaks >= 2) total_breaks += continuous_breaks; continuous_breaks = (current_class == 0 ? continuous_breaks + 1 : 0); } total_breaks += continuous_breaks;//Adding up all the breaks after the last class i.e. - the trailing zeroes printf("%d\n",(no_of_classes - total_breaks) ); return 0; } ================================================ FILE: C Programs/C Programs - 7/Alice_and_Bob.c ================================================ #include #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) int find_gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); if(a == b) return a; if(a%2 == 0) if(b%2 == 0) return 2*find_gcd(a >> 1, b >> 1); else return find_gcd(a >> 1, b); else if(b%2 == 0) return find_gcd(a, b >> 1); else return find_gcd(min(a, b), (max(a, b) - min(a, b) ) >> 1); } int main() { int no_of_numbers, maximum = 0, number, no_of_numbers_at_end, i, no_of_turns, gcd; scanf("%d", &no_of_numbers); for(i = 1; i <= no_of_numbers; i++) { scanf("%d", &number); maximum = max(maximum, number); gcd = (i == 1 ? number : find_gcd(gcd, number) ); } no_of_numbers_at_end = maximum/gcd; no_of_turns = no_of_numbers_at_end - no_of_numbers; printf(no_of_turns%2 == 1 ? "Alice\n" : "Bob\n"); return 0; } ================================================ FILE: C Programs/C Programs - 7/An_Abandoned_Sentiment_From_Past.c ================================================ #include #define MAX_LENGTH 100 + 1 #define true 1 #define false 0 int main() { int a[MAX_LENGTH], missing_number, zero_index = -1, no_of_zeroes, entire_length,i, is_possible = false; scanf("%d %d",&entire_length, &no_of_zeroes); for(i = 0; i < entire_length; i++) { scanf("%d", &a[i]); if(a[i] == 0) zero_index = i; else if(i > 0 && a[i] <= a[i - 1]) is_possible = true; } for(i = 0; i < no_of_zeroes; i++) scanf("%d",&missing_number); //If there is more than one zero, it is always possible to make the sequence non-increasing. if(no_of_zeroes > 1) { is_possible = true; } else { if(zero_index == 0) { if(missing_number >= a[zero_index + 1]) is_possible = true; } else if(zero_index == entire_length - 1) { if(missing_number <= a[zero_index - 1]) is_possible = true; } else if(missing_number >= a[zero_index + 1] || missing_number <= a[zero_index - 1]) { is_possible = true; } } printf(is_possible ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: C Programs/C Programs - 7/Andrushya_and_Socks.c ================================================ #include #define max(a, b) (a > b ? a : b) #define MAX_SIZE 100000 + 1 int no_of_socks[MAX_SIZE] = {0}; int main() { int current_sock_type, i, no_of_sock_types, no_of_socks_on_table = 0, max_no_of_socks_on_table = 0; scanf("%d", &no_of_sock_types); for(i = 1; i < 2*no_of_sock_types; i++) { scanf("%d", ¤t_sock_type); no_of_socks[current_sock_type]++; if(no_of_socks[current_sock_type] == 1) no_of_socks_on_table++; else if(no_of_socks[current_sock_type] == 2) no_of_socks_on_table--; max_no_of_socks_on_table = max(max_no_of_socks_on_table, no_of_socks_on_table); } printf("%d\n",max_no_of_socks_on_table); return 0; } ================================================ FILE: C Programs/C Programs - 7/Combination Lock.cpp ================================================ #include #include #define MAX_LENGTH 1000 + 1 using namespace std; int main() { char current_state[MAX_LENGTH], final_state[MAX_LENGTH]; int number_of_moves = 0, number_of_locks; scanf("%d %s %s", &number_of_locks, current_state, final_state); for(int i = 0; i < number_of_locks; i++) { int start, ending; start = min(current_state[i], final_state[i]) - '0'; ending = max(current_state[i], final_state[i]) - '0'; number_of_moves += min(ending - start, 10 + start - ending); //Optimal to go forwards or backwards } printf("%d\n", number_of_moves); return 0; } ================================================ FILE: C Programs/C Programs - 7/Devu_Singer_Charu_Joker.c ================================================ #include int main() { int no_of_songs, total_time_for_songs = 0, minutes_current_song, i, total_time_available, minimum_performance_time, maximum_jokes = -1; const int minutes_for_charu_joke = 5; scanf("%d %d", &no_of_songs, &total_time_available); for(i = 1; i <= no_of_songs; i++) { scanf("%d", &minutes_current_song); total_time_for_songs += minutes_current_song; } minimum_performance_time = total_time_for_songs + (no_of_songs - 1)*2*minutes_for_charu_joke; if(minimum_performance_time <= total_time_available) { maximum_jokes = (no_of_songs - 1)*2 + (total_time_available - minimum_performance_time)/(minutes_for_charu_joke); } printf("%d\n",maximum_jokes); return 0; } ================================================ FILE: C Programs/C Programs - 7/Fake_NP.c ================================================ #include int main() { unsigned int left_limit, right_limit; scanf("%u %u",&left_limit, &right_limit); printf(left_limit != right_limit ? "2\n" : "%u\n",left_limit); return 0; } ================================================ FILE: C Programs/C Programs - 7/Fence.c ================================================ #include #define MAX_LENGTH 150000 + 1 int heights[MAX_LENGTH]; int main() { int i, no_of_planks, k, k_consecutive_sum = 0, minimum_k_consecutive_sum = 1e9, start_of_minimum_sum; scanf("%d %d", &no_of_planks, &k); for(i = 1; i <= no_of_planks; i++) { scanf("%d", &heights[i]); k_consecutive_sum += (i <= k ? heights[i] : heights[i] - heights[i - k]); if(i >= k && k_consecutive_sum <= minimum_k_consecutive_sum) { minimum_k_consecutive_sum = k_consecutive_sum; start_of_minimum_sum = (i - k + 1); } } printf("%d\n",start_of_minimum_sum); return 0; } ================================================ FILE: C Programs/C Programs - 7/Find_Marble.c ================================================ #include #include int main() { int no_of_glasses, initial_position, final_position, minimum_shuffles = 0, i; scanf("%d %d %d", &no_of_glasses, &initial_position, &final_position); int *shuffled_result = malloc((no_of_glasses + 1)*sizeof(int)); for(i = 1; i <= no_of_glasses; i++) scanf("%d", (shuffled_result + i) ); for(i = initial_position; ; i = *(shuffled_result + i), minimum_shuffles++) if( (i == initial_position && minimum_shuffles!= 0) || (i == final_position) ) break; printf("%d\n", (i == final_position ? minimum_shuffles : -1) );// free(shuffled_result); return 0; } ================================================ FILE: C Programs/C Programs - 7/Free Ice Cream.cpp ================================================ #include int main() { int no_of_people, distressed_kids = 0; long long ice_cream; scanf("%d %I64d", &no_of_people, &ice_cream); for(int i = 1; i <= no_of_people; i++) { char action; int amount; scanf(" %c %d", &action, &amount); if(action == '+') ice_cream += amount; else if(amount > ice_cream) distressed_kids++; else ice_cream -= amount; } printf("%I64d %d\n", ice_cream, distressed_kids); } ================================================ FILE: C Programs/C Programs - 7/Hexadecimal's Theorem Alternate Solution.cpp ================================================ #include int main() { int n; scanf("%d", &n); printf("0 0 %d\n", n); return 0; } ================================================ FILE: C Programs/C Programs - 7/Hexadecimal's Theorem.cpp ================================================ #include #include #include using namespace std; vector fibonacci; void precompute_fibonacci() { const int MAX = 1e9; fibonacci.push_back(0); fibonacci.push_back(1); for(int i = 2; fibonacci[i - 1] + fibonacci[i - 2] <= MAX; i++) fibonacci.push_back(fibonacci[i - 1] + fibonacci[i - 2]); } int main() { precompute_fibonacci(); int n; scanf("%d", &n); if(n == 0) //F(0) printf("0 0 0\n"); else if(n == 1)//F(1) and F(2) printf("1 0 0\n"); else if(n == 2) //F(3) printf("1 1 0\n"); else { int index = 4; while(fibonacci[index] != n) index++; printf("%d %d %d\n",fibonacci[index - 1], fibonacci[index - 3], fibonacci[index - 4]); } return 0; } ================================================ FILE: C Programs/C Programs - 7/IQ_Test.c ================================================ #include int main() { int no_of_numbers, number, no_of_even_numbers = 0, no_of_odd_numbers = 0, last_even_index, last_odd_index, i; scanf("%d", &no_of_numbers); for(i = 1; i <= no_of_numbers; i++) { scanf("%d", &number); if(number%2 == 0) no_of_even_numbers++, last_even_index = i; else no_of_odd_numbers++, last_odd_index = i; } printf("%d\n", (no_of_even_numbers == 1 ? last_even_index : last_odd_index) ); return 0; } ================================================ FILE: C Programs/C Programs - 7/Magnets.c ================================================ #include int main() { int no_of_magnets, i, no_of_magnet_groups = 0; char previous_orientation = 'X', current_orientation, current_magnet[3]; scanf("%d", &no_of_magnets); for(i = 1; i <= no_of_magnets; previous_orientation = current_orientation, i++) { scanf("%s",current_magnet); current_orientation = current_magnet[0]; if(previous_orientation != current_orientation) no_of_magnet_groups++; } printf("%d\n",no_of_magnet_groups); return 0; } ================================================ FILE: C Programs/C Programs - 7/Mahmod_Longest_Uncommon_Subsequence.c ================================================ #include #include #define max(a, b) (a > b ? a : b) #define MAX_LENGTH 100000 int main() { char string_1[MAX_LENGTH + 1], string_2[MAX_LENGTH + 1]; scanf("%s %s",string_1, string_2); printf("%d\n", (strcmp(string_1, string_2) != 0 ? max( strlen(string_1),strlen(string_2) ) : -1) ); return 0; } ================================================ FILE: C Programs/C Programs - 7/Monster_and_Squirrel.c ================================================ #include int main() { int number_of_vertices; long long number_of_regions; scanf("%d",&number_of_vertices); //Each vertex had (n - 3) lines drawn from it. Since, there are no intersections, each line increases the number of regions by 1. number_of_regions = (number_of_vertices - 2)*1LL*(number_of_vertices - 2); printf("%I64d\n",number_of_regions); return 0; } ================================================ FILE: C Programs/C Programs - 7/New Year Transportation.cpp ================================================ #include #include #define INFINITY 1e9 using namespace std; int main() { int number_of_cells, destination; scanf("%d %d", &number_of_cells, &destination); vector number_of_jumps(number_of_cells); vector visited(number_of_cells + 1, false); for(int i = 1; i <= number_of_cells - 1; i++) scanf("%d", &number_of_jumps[i]); number_of_jumps[number_of_cells] = INFINITY; for(int next_cell = 1; next_cell <= number_of_cells; next_cell += number_of_jumps[next_cell]) visited[next_cell] = true; printf(visited[destination] ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 7/Optimal_Point_on_a_Line.cpp ================================================ #include #include using namespace std; #define MAX_POINTS 300000 + 1 int points[MAX_POINTS]; int main() { int no_of_points, median, i; scanf("%d",&no_of_points); for(i = 0; i < no_of_points; i++) scanf("%d", &points[i]); sort(points, points + no_of_points); median = points[(no_of_points - 1)/2]; printf("%d\n",median); return 0; } ================================================ FILE: C Programs/C Programs - 7/Pashmak_and_Flowers.c ================================================ #include int main() { int no_of_minima = 0, no_of_maxima = 0, most_beautiful = 0, least_beautiful = 1e9 + 1, no_of_flowers, current_beauty, i; long long no_of_choices; scanf("%d", &no_of_flowers); for(i = 1; i <= no_of_flowers; i++) { scanf("%d",¤t_beauty); if(current_beauty == most_beautiful) no_of_maxima++; if(current_beauty == least_beautiful) no_of_minima++; if(current_beauty < least_beautiful) least_beautiful = current_beauty, no_of_minima = 1; if(current_beauty > most_beautiful) most_beautiful = current_beauty, no_of_maxima = 1; } //If all flowers are equally beautiful, then choices = n(n-1)/2 no_of_choices = ( most_beautiful == least_beautiful ? (no_of_flowers*1LL*(no_of_flowers - 1) )/2 : no_of_minima*1LL*no_of_maxima ); printf("%d %I64d\n",(most_beautiful - least_beautiful), no_of_choices); return 0; } ================================================ FILE: C Programs/C Programs - 7/Potions_Homework.cpp ================================================ #include #include using namespace std; long long laziness[100001]; int main() { const int MOD = 1e4 + 7; int no_of_students, i; long long minimum_time = 0LL; ios::sync_with_stdio(false); cin.tie(0); cin >> no_of_students; for(i = 0; i < no_of_students; i++) cin >> laziness[i]; sort(laziness, laziness + no_of_students); for(i = 0; i < no_of_students; i++) minimum_time = (minimum_time + laziness[i]*laziness[no_of_students - i - 1])%MOD; cout << minimum_time; return 0; } ================================================ FILE: C Programs/C Programs - 7/Pythagorean Triples.cpp ================================================ #include int main() { int side_1; long long side_2, side_3, k; scanf("%d", &side_1); if(side_1 <= 2) { printf("-1\n"); return 0; } /*If n is even, n^2 = 4k, then (2k - 1)^2 + 4k = (2k + 1)^2 a = root(4k), b = k - 1, c = k + 1 If n is odd, n^2 = (2k + 1), a = root(2k + 1), b = k, c = k + 1*/ if(side_1%2 == 0) { k = (side_1*1ll*side_1)/4; side_2 = (k - 1); side_3 = (k + 1); } else { k = ( (side_1*1LL*side_1) - 1)/2; side_2 = k; side_3 =(k + 1); } printf("%I64d %I64d\n" ,side_2, side_3); return 0; } ================================================ FILE: C Programs/C Programs - 7/Red_Blue_Balls.c ================================================ #include #define MAX_SIZE 50 int main() { long long equivalent_number = 0LL; int no_of_balls, i; char stack[MAX_SIZE + 1]; scanf("%d %s", &no_of_balls, stack); for(i = 0; i < no_of_balls; i++) if(stack[i] == 'B') equivalent_number = equivalent_number| (1LL << i); printf("%I64d\n",equivalent_number); return 0; } ================================================ FILE: C Programs/C Programs - 7/The_Contest.c ================================================ #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) int main() { int no_of_problems, i, time_i_problem, total_time = 0, no_of_time_periods, minimum_time; int start_time[1001], end_time[1001]; scanf("%d", &no_of_problems); for(i = 1; i <= no_of_problems; i++) { scanf("%d", &time_i_problem); total_time += time_i_problem; } scanf("%d", &no_of_time_periods); for(i = 0; i < no_of_time_periods; i++) scanf("%d %d", &start_time[i], &end_time[i]); for(i = 0; i < no_of_time_periods && total_time > end_time[i]; i++); minimum_time = (i == no_of_time_periods ? -1 : max(start_time[i], total_time) ); printf("%d\n",minimum_time); return 0; } ================================================ FILE: C Programs/C Programs - 7/Young_Physicist.c ================================================ #include int main() { int no_of_vectors, total_x = 0, x, total_y = 0, y, total_z = 0, z, i; scanf("%d", &no_of_vectors); for(i = 1; i <= no_of_vectors; i++) { scanf("%d %d %d",&x, &y, &z); total_x += x; total_y += y; total_z += z; } printf(total_x == 0 && total_y == 0 && total_z == 0 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 8/A and B Team Training.cpp ================================================ #include #define min(a,b) (a < b ? a : b) int main() { int experienced_people_no, newbie_no, no_of_available_people; int no_of_teams; scanf("%d %d", &experienced_people_no, &newbie_no); no_of_teams = min(experienced_people_no, newbie_no); /*No of teams cannot exceed the min(E, N) ... We choose the highest configuration possible. To check if a configuration is possible, make I teams of (E, N, _) and then check if the third spot can be filled in all i teams.*/ while(no_of_teams > 0) { no_of_available_people = (experienced_people_no + newbie_no) - 2*no_of_teams; if(no_of_available_people >= no_of_teams) break; no_of_teams--; } printf("%d\n", no_of_teams); return 0; } ================================================ FILE: C Programs/C Programs - 8/Almost Prime.cpp ================================================ #include #include using namespace std; vector no_of_almost_primes_till(3000 + 1, 0); void precompute_primes() { vector no_of_prime_factors(3000 + 1, 0); for(int i = 2; i <= 3000; i++) { if(no_of_prime_factors[i] == 0) { for(int multiple = i; multiple <= 3000; multiple += i) { no_of_prime_factors[multiple]++; } } } for(int i = 1; i <= 3000; i++) { no_of_almost_primes_till[i] = no_of_almost_primes_till[i - 1] + (no_of_prime_factors[i] == 2); } } int main() { precompute_primes(); int n; scanf("%d", &n); printf("%d\n", no_of_almost_primes_till[n]); return 0; } ================================================ FILE: C Programs/C Programs - 8/Brian's Photos.cpp ================================================ #include int main() { bool is_colourful = false; int no_of_rows, no_of_columns; scanf("%d %d", &no_of_rows, &no_of_columns); for(int row = 1; row <= no_of_rows; row++) { for(int column = 1; column <= no_of_columns; column++) { char colour; scanf(" %c", &colour); if(colour != 'B' && colour != 'G' && colour != 'W') is_colourful = true; } } printf(is_colourful ? "#Color\n" : "#Black&White\n"); return 0; } ================================================ FILE: C Programs/C Programs - 8/Caisa and Pylons.cpp ================================================ #include #include #include using namespace std; int main() { int number_of_plyons; scanf("%d", &number_of_plyons); vector height (number_of_plyons + 1); for(int i = 1; i <= number_of_plyons; i++) scanf("%d", &height[i]); int money_needed = height[1]; int energy = 0; for(int i = 1; i <= number_of_plyons - 1; i++) { energy += (height[i] - height[i + 1]); if(energy < 0) { money_needed += abs(energy); energy = 0; } } printf("%d\n", money_needed); return 0; } ================================================ FILE: C Programs/C Programs - 8/Choosing Teams.cpp ================================================ #include #include #include #define all(v) (v).begin(),(v).end() using namespace std; int main() { int number_of_people, number_of_attempts; scanf("%d %d", &number_of_people, &number_of_attempts); vector attempts (number_of_people); for(int i = 0; i < number_of_people; i++) scanf("%d", &attempts[i]); sort(all(attempts)); int no_of_teams = 0, i = 0; while(i + 2 < number_of_people && (attempts[i +2] + number_of_attempts) <= 5) { i += 3; no_of_teams++; } printf("%d\n",no_of_teams); return 0; } ================================================ FILE: C Programs/C Programs - 8/Ciel and Flowers.cpp ================================================ #include #include #define min_3(a, b, c) min(a, min(b, c) ) #define max_3(a, b, c) max(a, max(b, c) ) using namespace std; int main() { int green, red, blue; scanf("%d %d %d",&red, &green, &blue); int one_mixed_boquet = 0, two_mixed_boquet = 0, no_mixed_boquet; no_mixed_boquet = red/3 + green/3 + blue/3; if(min_3(red,green, blue) >= 1) one_mixed_boquet = 1 + (red - 1)/3 + (green - 1)/3 + (blue - 1)/3; if(min_3(red, green, blue) >= 2) two_mixed_boquet = 2 + (red - 2)/3 + (green - 2)/3 + (blue - 2)/3; printf("%d\n",max_3(no_mixed_boquet, two_mixed_boquet, one_mixed_boquet)); return 0; } ================================================ FILE: C Programs/C Programs - 8/Diverse Permutation.cpp ================================================ #include int main() { int n, k; int current_number, previous_number; scanf("%d %d", &n, &k); for(int i = 1; i <= k + 1; i++) { if(i == 1) current_number = 1; else current_number = (i%2 == 0 ? k + 2 - previous_number : k + 3 - previous_number); printf("%d ", current_number); previous_number = current_number; } for(int i = k + 2; i <= n; i++) { printf("%d ",i); } return 0; } ================================================ FILE: C Programs/C Programs - 8/HQ9+.cpp ================================================ #include #define MAX_LENGTH 100 + 1 int main() { bool produces_output = false; char program[MAX_LENGTH]; scanf("%s", program); for(int i = 0; program[i] != '\0'; i++) { if(program[i] == 'H' || program[i] == 'Q' || program[i] == '9') { produces_output = true; break; } } printf(produces_output ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 8/Hexadecimal's Numbers.cpp ================================================ #include int corresponding_decimal(int bitmask) { int decimal = 0; //Get the bitmask in decimal For example, 11 should be eleven .. So, we treat it like a polynomial, multiply decimal by 10 at each step and add //it to whatever bit was there ... 11 will be 1*10 + 1. for(int i = 31; i >= 0; i--) { decimal = decimal*10 + ( (bitmask & (1 << i) ) != 0) ; } return decimal; } int main() { int limit, no_of_saved_numbers = 0; scanf("%d", &limit); int max_numbers = (1 << 10) - 1; //At most 2^10 - 1 numbers for(int bitmask = 1; bitmask <= max_numbers; bitmask++) { if(corresponding_decimal(bitmask) > limit) break; no_of_saved_numbers++; } printf("%d\n", no_of_saved_numbers); return 0; } ================================================ FILE: C Programs/C Programs - 8/Infinite Sequence.cpp ================================================ #include int main() { long long nearest_end, position, i; scanf("%I64d", &position); i = 0; while(i*(i + 1)/2 < position) i++; i--; nearest_end = i*(i + 1)/2 ; printf("%I64d\n",(position - nearest_end)); return 0; } ================================================ FILE: C Programs/C Programs - 8/Jzzhu and Sequences.cpp ================================================ #include int main() { const int MOD = 1e9 + 7; int X, Y, number_of_terms; long long answer; scanf("%d %d %d", &X, &Y, &number_of_terms); X = (X + MOD)%MOD; Y = (Y + MOD)%MOD; switch(number_of_terms%6) { case 1: answer = X; break; case 2: answer = Y; break; case 3: answer = Y + MOD - X; break; case 4: answer = 0 + MOD - X; break; case 5: answer = 0 + MOD - Y; break; case 0: answer = X + MOD - Y; break; } answer = (answer + MOD)%MOD; //In case it's negative printf("%I64d\n",answer); return 0; } ================================================ FILE: C Programs/C Programs - 8/K-Factorisation.cpp ================================================ #include #include using namespace std; int main() { unsigned int n, number_of_factors; scanf("%d %d", &n, &number_of_factors); vector factor; for(unsigned int i = 2; i <= n ; i++) { while(n%i == 0) { if(factor.size() == number_of_factors) factor.back() *=i; else factor.push_back(i); n = n/i; } } if(factor.size() < number_of_factors) printf("-1\n"); else for(unsigned int i = 0; i < number_of_factors; i++) printf("%d ",factor[i]); return 0; } ================================================ FILE: C Programs/C Programs - 8/Noldbach Problem.cpp ================================================ #include #include using namespace std; vector noldbach_number(1000 + 1, false); vector primes; void precompute_noldbach() { vector is_prime(1000 + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= 1000; i++) { if(is_prime[i]) { for(int multiple = 2*i; multiple <= 1000; multiple += i) { is_prime[multiple] = false; } primes.push_back(i); } } for(int i = 0; primes[i] + primes[i + 1] <= 1000 ; i++) { noldbach_number[primes[i] + primes[i + 1] + 1] = true; } } int main() { precompute_noldbach(); int n, k; scanf("%d %d", &n, &k); int conjecture_count = 0; for(int i = 0; primes[i] <= n; i++) { if(noldbach_number[primes[i]]) conjecture_count++; } printf(conjecture_count >= k ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 8/Olesya and Rodion.cpp ================================================ #include using namespace std; int main() { int number_of_digits, multiple; scanf("%d %d", &number_of_digits, &multiple); if(number_of_digits == 1 && multiple == 10) { printf("-1\n"); } else { printf("%d", multiple); int no_of_zeroes = (multiple == 10 ? number_of_digits - 2 : number_of_digits - 1); for(int zero_count = 1; zero_count <= no_of_zeroes; zero_count++) printf("0"); } printf("\n"); return 0; } ================================================ FILE: C Programs/C Programs - 8/Petr and Book.cpp ================================================ #include #include using namespace std; int main() { int no_of_pages; scanf("%d", &no_of_pages); int i; vector pages_read_on_day(7); for(i = 0; i < 7; i++) scanf("%d", &pages_read_on_day[i]); i = 0; while(true) { no_of_pages -= pages_read_on_day[i]; if(no_of_pages <= 0) break; i = (i + 1)%7; } printf("%d\n",i + 1); return 0; } ================================================ FILE: C Programs/C Programs - 8/Petya and Strings.cpp ================================================ #include #include #define MAX_LENGTH 100 + 1 #define tolower(c) (c < 'a' ? (c + 'a' - 'A') : c) int main() { char string_1[MAX_LENGTH], string_2[MAX_LENGTH]; scanf("%s %s", string_1, string_2); for(int i = 0; string_1[i] != '\0'; i++) { if(tolower(string_1[i]) > tolower(string_2[i]) ) { printf("1\n"); return 0; } else if(tolower(string_1[i]) < tolower(string_2[i]) ) { printf("-1\n"); return 0; } } printf("0\n"); return 0; } ================================================ FILE: C Programs/C Programs - 8/Sum of Digits.cpp ================================================ #include #define MAX_LENGTH 100000 + 1 int find_digit_sum(int n) { int sum = 0; while(n > 0) { sum += n%10; n /= 10; } return sum; } int main() { char number[MAX_LENGTH]; int i, digit_sum = 0, no_of_spells = 0; scanf("%s", number); if(number[1] != '\0') { for(i = 0; number[i] != '\0'; i++) digit_sum += (number[i] - '0'); no_of_spells = 1; while(digit_sum >= 10) { no_of_spells++; digit_sum = find_digit_sum(digit_sum); } } printf("%d\n", no_of_spells); return 0; } ================================================ FILE: C Programs/C Programs - 8/T Primes Alternate Solution.cpp ================================================ #include #include #include using namespace std; vector is_prime(1000000 + 1, true); void precompute_prime_squares() { is_prime[0] = is_prime[1] = false; for(int i = 2; i <= 1e6; i++) if(is_prime[i]) for(int multiple = 2*i; multiple <= 1e6; multiple += i) is_prime[multiple] = false; } int main() { int no_of_queries; scanf("%d", &no_of_queries); precompute_prime_squares(); for(int i = 1; i <= no_of_queries; i++) { long long number, root; scanf("%I64d", &number); root = (int) sqrt(number); printf(root*root == number && is_prime[root] ? "YES\n" : "NO\n"); } return 0; } ================================================ FILE: C Programs/C Programs - 8/T-Primes.cpp ================================================ #include #include #include using namespace std; set prime_square; void precompute_prime_squares() { vector is_prime(1000000 + 1, true); for(int i = 2; i <= 1e6; i++) { if(is_prime[i]) { prime_square.insert(i*1LL*i); for(int multiple = 2*i; multiple <= 1e6; multiple += i) is_prime[multiple] = false; } } } int main() { int no_of_queries; scanf("%d", &no_of_queries); precompute_prime_squares(); for(int i = 1; i <= no_of_queries; i++) { long long number; scanf("%I64d", &number); printf(prime_square.count(number) == 1 ? "YES\n" : "NO\n"); } return 0; } ================================================ FILE: C Programs/C Programs - 8/The Golden Age.cpp ================================================ #include #include #include #define all(v) (v).begin(),(v).end() using namespace std; int main() { unsigned int a, b, i; long long x, y, left_limit, right_limit, max_lucky_years = 0, current_lucky_run; scanf("%I64d %I64d %I64d %I64d",&x, &y, &left_limit, &right_limit); vector powers_of_x; vector powers_of_y; vector sums_of_powers_x_y; //All the unlucky years. powers_of_x.push_back(1); while(powers_of_x.back() <= right_limit/x) { powers_of_x.push_back(x*powers_of_x.back()); } powers_of_y.push_back(1); while(powers_of_y.back() <= right_limit/y) { powers_of_y.push_back(y*powers_of_y.back()); } sums_of_powers_x_y.push_back(left_limit - 1); sums_of_powers_x_y.push_back(right_limit + 1); for(a = 0; a < powers_of_x.size(); a++) { for(b = 0; b < powers_of_y.size(); b++) { sums_of_powers_x_y.push_back(powers_of_x[a] + powers_of_y[b]); } } sort( all(sums_of_powers_x_y) ); i = 0; while(sums_of_powers_x_y[i] < left_limit - 1) i++; i++; while(sums_of_powers_x_y[i] <= right_limit + 1 && i < sums_of_powers_x_y.size()) { current_lucky_run = sums_of_powers_x_y[i] - sums_of_powers_x_y[i - 1] - 1; max_lucky_years = max(max_lucky_years, current_lucky_run); i++; } printf("%I64d\n",max_lucky_years); return 0; } ================================================ FILE: C Programs/C Programs - 8/Two Bags of Potatos.cpp ================================================ #include #include using namespace std; int main() { int x, y, limit, k, sum; scanf("%d %d %d",&y, &k, &limit); vector possibilities; int no_of_possibilities = 0; for(sum = k, x = sum - y; sum <= limit; sum += k, x = sum - y) { if(x > 0) { no_of_possibilities++; possibilities.push_back(x); } } if(no_of_possibilities == 0) printf("-1\n"); else for(int i = 0; i < no_of_possibilities; i++) printf("%d\t",possibilities[i]); return 0; } ================================================ FILE: C Programs/C Programs - 8/Vanya and Cards.cpp ================================================ #include #define abs(x) ( (x) > 0 ? (x) : -(x) ) int main() { int number_of_cards, maximum, card_i; scanf("%d %d", &number_of_cards, &maximum); int sum = 0; for(int i = 1; i <= number_of_cards; i++) { scanf("%d", &card_i); sum += card_i; } int no_of_cards_required = 0; sum = abs(sum); if(sum != 0) no_of_cards_required = sum/maximum + (sum%maximum != 0); printf("%d\n", no_of_cards_required); return 0; } ================================================ FILE: C Programs/C Programs - 8/Vitaly and Night.cpp ================================================ #include int main() { int no_of_floors, no_of_flats, open, awake_people = 0; scanf("%d %d", &no_of_floors, &no_of_flats); for(int i = 1; i <= no_of_floors; i++) { for(int j = 1; j <= no_of_flats; j++) { bool is_awake = false; for(int window = 1; window <= 2; window++) { scanf("%d", &open); if(open == 1) is_awake = true; } awake_people += (is_awake == true); } } printf("%d\n", awake_people); return 0; } ================================================ FILE: C Programs/C Programs - 8/Wet Shark and Odd and Even.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int min_odd_number, number_of_elements, number_i; long long sum = 0; scanf("%d", &number_of_elements); min_odd_number = 1e9 + 1; for(int i = 1; i <= number_of_elements; i++) { scanf("%d", &number_i); sum += number_i; if(number_i%2 == 1) min_odd_number = min(min_odd_number, number_i); } printf("%I64d\n", sum%2 == 0 ? sum : sum - min_odd_number); return 0; } ================================================ FILE: C Programs/C Programs - 8/Yaroslav and Permutations.cpp ================================================ #include #include #include using namespace std; int main() { int number_of_elements, element_i; scanf("%d", &number_of_elements); map frequency; for(int i = 1; i <= number_of_elements; i++) { scanf("%d", &element_i); frequency[element_i]++; } int max_frequency = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) max_frequency = max(max_frequency, it->second); int half_size = number_of_elements/2 + number_of_elements%2; printf(max_frequency > half_size ? "NO\n" : "YES\n"); return 0; } ================================================ FILE: C Programs/C Programs - 9/Alyona and Copybooks.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define min_3(a, b, c) min(a, min(b, c)) int main() { int no_of_books, price_1, price_2, price_3; scanf("%d %d %d %d", &no_of_books, &price_1, &price_2, &price_3); long long minimum_amount = 0; switch(no_of_books%4) { case 1: minimum_amount = min_3(price_1*3LL, price_1 + price_2, price_3); break; case 2: minimum_amount = min_3(price_1*2LL, price_2, price_3*2LL); break; case 3: minimum_amount = min_3(price_1, price_2 + price_3, price_3*3LL); } printf("%I64d\n", minimum_amount); return 0; } ================================================ FILE: C Programs/C Programs - 9/Appleman and Toastman.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_groups; long long answer = 0; scanf("%d", &no_of_groups); vector group(no_of_groups + 1, 0); for(int i = 1; i <= no_of_groups; i++) { scanf("%d", &group[i]); } sort(all(group)); for(unsigned int i = group.size() - 1; i >= 1; i--) { int no_of_times_i_is_counted = (i == group.size() - 1 ? i : i + 1); answer += no_of_times_i_is_counted*1LL*group[i]; } printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs - 9/Array.cpp ================================================ #include #include #include #define all(v) (v).begin(),(v).end() using namespace std; int main() { vector zero; vector positive; vector negative; int no_of_elements, zero_start; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); sort(all(element)); if(element.back() > 0) { positive.push_back(element.back()); element.pop_back(); negative.push_back(element.front()); zero_start = 1; } else { positive.push_back(element[0]); positive.push_back(element[1]); negative.push_back(element[2]); zero_start = 3; } for(unsigned int i = zero_start; i < element.size(); i++) zero.push_back(element[i]); printf("1 %d\n",negative.back()); printf("%u ", positive.size() ); for(unsigned int i = 0; i < positive.size(); i++) printf("%d ",positive[i]); printf("\n%u ", zero.size()); for(unsigned int i = 0; i < zero.size(); i++) printf("%d ",zero[i]); return 0; } ================================================ FILE: C Programs/C Programs - 9/Bear and Five Cards.cpp ================================================ #include #include #define max(a, b) (a > b ? a : b) using namespace std; int main() { map frequency; const int no_of_cards = 5; int sum = 0; for(int i = 1; i <= no_of_cards; i++) { int card_i; scanf("%d", &card_i); sum += card_i; frequency[card_i]++; } int max_subtracted = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { int number_i = it->first; int frequency_i = it->second; int subtracted_amount = 0; if(frequency_i > 1) { subtracted_amount = (frequency_i > 2 ? 3*number_i : 2*number_i); } max_subtracted = max(max_subtracted, subtracted_amount); } printf("%d\n", sum - max_subtracted); return 0; } ================================================ FILE: C Programs/C Programs - 9/Bus to Udayland.cpp ================================================ #include #define ROW_LENGTH 5 + 1 #define MAX_ROWS 1000 + 1 int main() { char bus_seating[MAX_ROWS][ROW_LENGTH]; int no_of_rows; scanf("%d", &no_of_rows); bool can_sit_together = false; for(int i = 0; i < no_of_rows; i++) { scanf("%s", bus_seating[i]); if(bus_seating[i][0] == 'O' && bus_seating[i][1] == 'O' && can_sit_together == false) { bus_seating[i][0] = bus_seating[i][1] = '+'; can_sit_together = true; } if(bus_seating[i][3] == 'O' && bus_seating[i][4] == 'O' && can_sit_together == false) { bus_seating[i][3] = bus_seating[i][4] = '+'; can_sit_together = true; } } if(can_sit_together) { printf("YES\n"); for(int i = 0; i < no_of_rows; i++) printf("%s\n",bus_seating[i]); } else { printf("NO\n"); } return 0; } ================================================ FILE: C Programs/C Programs - 9/Case of the Zeroes and Ones.cpp ================================================ #include #define MAX_LENGTH 200000 + 1 #define min(a, b) (a < b ? a : b) int main() { char sequence[MAX_LENGTH]; int length, no_of_zeroes = 0, no_of_ones = 0; scanf("%d %s", &length, sequence); for(int i = 0; i < length; i++) { no_of_zeroes += (sequence[i] == '0'); no_of_ones += (sequence[i] == '1'); } int no_of_survivors = length - 2*min(no_of_ones, no_of_zeroes); printf("%d\n", no_of_survivors); return 0; } ================================================ FILE: C Programs/C Programs - 9/Circle Line.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_stations, start, destination; scanf("%d", &no_of_stations); vector distance(no_of_stations + 1); for(int i = 1; i <= no_of_stations; i++) scanf("%d", &distance[i]); scanf("%d %d", &start, &destination); int straight_distance = 0; for(int i = start; i != destination; i = (i == no_of_stations ? 1 : i + 1)) straight_distance += distance[i]; int round_distance = 0; for(int i = destination; i != start; i = (i == no_of_stations ? 1 : i + 1)) round_distance += distance[i]; printf("%d\n", min(straight_distance, round_distance)); return 0; } ================================================ FILE: C Programs/C Programs - 9/Crazy Computer.cpp ================================================ #include int main() { int no_of_words, minute_i, maximum_break; scanf("%d %d", &no_of_words, &maximum_break); int previous_minute = 0, no_of_words_on_screen = 0; for(int i = 1; i <= no_of_words; i++) { scanf("%d", &minute_i); no_of_words_on_screen = (minute_i - previous_minute <= maximum_break ? no_of_words_on_screen + 1 : 1); previous_minute = minute_i; } printf("%d\n", no_of_words_on_screen); return 0; } ================================================ FILE: C Programs/C Programs - 9/Crossword Solving.cpp ================================================ #include #include #define MAX_LENGTH 1000 + 1 using namespace std; int main() { int key_length, text_length; char key[MAX_LENGTH], text[MAX_LENGTH]; scanf("%d %d %s %s", &key_length, &text_length, key, text); vector change(key_length + 1); vector current_change; for(int i = 0; i + key_length <= text_length ; i++) { current_change.clear(); for(int j = 0; j < key_length; j++) { if(key[j] != text[i + j]) { current_change.push_back(j); } } if(current_change.size() < change.size()) { change = current_change; } } printf("%u\n", change.size()); if(change.size() > 0) { for(unsigned int i = 0; i < change.size(); i++) printf("%d ", change[i] + 1); } return 0; } ================================================ FILE: C Programs/C Programs - 9/Divisibility.cpp ================================================ #include #define abs(x) ( (x) > 0 ? (x) : -(x) ) #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) int main() { long long k, left, right, no_of_multiples = 0; scanf("%I64d %I64d %I64d", &k, &left, &right); if(right > 0 && left < 0) { left = abs(left); no_of_multiples = (right)/k + (left)/k + 1; //Add 0 as a multiple as well. } else { long long greater_limit = max(abs(right), abs(left)); long long lower_limit = min(abs(right), abs(left)); if(lower_limit == 0) { no_of_multiples = (greater_limit)/k + 1; //Count 0 as well } else { no_of_multiples = (greater_limit)/k - (lower_limit - 1)/k; } } printf("%I64d\n", no_of_multiples); return 0; } ================================================ FILE: C Programs/C Programs - 9/Fox and Number Game.cpp ================================================ #include #include using namespace std; int gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } int main() { int no_of_elements, element_i, array_gcd; scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &element_i); array_gcd = (i == 1 ? element_i : gcd(array_gcd, element_i)); } printf("%d\n", array_gcd*no_of_elements); return 0; } ================================================ FILE: C Programs/C Programs - 9/Haiku.cpp ================================================ #include #define MAX_LENGTH 100 + 2 bool is_vowel(char ch) { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': return true; default : return false; } } int main() { bool is_haiku = true; char line[MAX_LENGTH]; const int no_of_lines = 3; for(int i = 1; i <= no_of_lines; i++) { int vowel_count = 0; fgets(line, MAX_LENGTH, stdin); for(int letter = 0; line[letter] != '\n'; letter++) vowel_count += is_vowel(line[letter]); if(i == 2) { if(vowel_count != 7) is_haiku = false; } else { if(vowel_count != 5) is_haiku = false; } } printf(is_haiku ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 9/I'm Bored with Life.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int factorial(int n) { int fact = 1; while(n > 0) { fact *= n; n--; } return fact; } int main() { int a, b; scanf("%d %d", &a, &b); printf("%d\n", factorial(min(a, b))); return 0; } ================================================ FILE: C Programs/C Programs - 9/Is your Horseshoe on the other hoof.cpp ================================================ #include #include using namespace std; int main() { map frequency; int hoof_i, no_of_hooves = 4; for(int i = 1; i <= no_of_hooves;i++) { scanf("%d", &hoof_i); frequency[hoof_i]++; } int no_of_new_hooves = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { int frequency_i = it->second; no_of_new_hooves += frequency_i - 1; //Keep one copy and throw the rest } printf("%d\n", no_of_new_hooves); return 0; } ================================================ FILE: C Programs/C Programs - 9/Kitahara Haruki's Gift.cpp ================================================ #include int main() { int no_of_apples, weight_i; scanf("%d", &no_of_apples); int no_of_100s = 0, no_of_200s = 0; for(int i = 1; i <= no_of_apples; i++) { scanf("%d", &weight_i); no_of_100s += (weight_i == 100); no_of_200s += (weight_i == 200); } no_of_200s = (no_of_200s%2); //Distribute half of them to either group. no_of_100s = no_of_100s - 2*no_of_200s; //Balancing out the 200; printf(no_of_100s%2 == 0 && no_of_100s >= 0 ? "YES\n" : "NO\n"); //check if remaining 100s can be divided in half. return 0; } ================================================ FILE: C Programs/C Programs - 9/Little Elephant and Function.cpp ================================================ #include int main() { int no_of_elements; scanf("%d", &no_of_elements); printf("%d ", no_of_elements); for(int i = 1; i < no_of_elements; i++) printf("%d ", i); return 0; } ================================================ FILE: C Programs/C Programs - 9/Little Elephant and Problem.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector original_array(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original_array[i]); vector sorted_array = original_array; sort(all(sorted_array)); int differences = 0; for(int i = 0; i < no_of_elements; i++) differences += (sorted_array[i] != original_array[i]); printf(differences <= 2 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs - 9/New Year and Days.cpp ================================================ #include #define MAX_TIME_LENGTH 5 + 1 int main() { int savings = 0, date; char of[2 + 1], time_period[MAX_TIME_LENGTH]; scanf("%d %s %s", &date ,of, time_period); //Scanf reads a string till it encounters a whitespace ... so I used two strings. if(time_period[0] == 'm') //Month { savings = 12*(date <= 29) + 11*(date == 30) + 7*(date == 31); //Only one of these can be true. } else if(time_period[0] == 'w') //Week { savings = 52 + (date == 5 || date == 6); // Days 6 and 7 occur one more time } printf("%d\n", savings); return 0; } ================================================ FILE: C Programs/C Programs - 9/One Dimensional Japanese Crossword.cpp ================================================ #include #include #define MAX_LENGTH 100 + 1 using namespace std; int main() { int no_of_blocks, segment_length; char crossword[MAX_LENGTH]; scanf("%d %s", &no_of_blocks, crossword); vector black_segment_length; for(int i = 0; i < no_of_blocks; i += segment_length + 1) { segment_length = 0; while(crossword[i + segment_length] == 'B') { segment_length++; } if(segment_length > 0) black_segment_length.push_back(segment_length); } printf("%u\n", black_segment_length.size()); for(unsigned int i = 0; i < black_segment_length.size(); i++) printf("%d ",black_segment_length[i]); return 0; } ================================================ FILE: C Programs/C Programs - 9/Present from Lena.cpp ================================================ #include int main() { int n; scanf("%d", &n); for(int row = 0; row <= n; row++) { for(int space = 0; space < n - row; space++) printf(" "); for(int number = 0; number <= row; number++) if(row == 0) printf("%d", number); else printf("%d ", number); for(int number = row - 1; number >= 0; number--) if(number == 0) printf("%d", number); else printf("%d ", number); printf("\n"); } for(int row = n - 1; row >= 0; row--) { for(int space = 0; space < n - row; space++) printf(" "); for(int number = 0; number <= row; number++) if(row == 0) printf("%d", number); else printf("%d ", number); for(int number = row - 1; number >= 0; number--) if(number == 0) printf("%d", number); else printf("%d ", number); printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs - 9/Prime Matrix.cpp ================================================ #include #include #define min(a, b) (a < b ? a : b) using namespace std; vector prime_distance(1e5 + 4); void precompute_prime_distance() { vector is_prime(1e5 + 10, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= 1e5 + 3; i++) { if(is_prime[i]) { for(int multiple = 2*i; multiple <= 1e5 + 3; multiple += i) { is_prime[multiple] = false; } } } int last_prime; for(int i = 1e5 + 3; i >= 0; i--) { if(is_prime[i]) last_prime = i; prime_distance[i] = last_prime - i; } } int main() { const int INFINITY = 1e9 + 1; int no_of_rows, no_of_columns; scanf("%d %d", &no_of_rows, &no_of_columns); precompute_prime_distance(); vector > matrix(no_of_rows, vector (no_of_columns) ); for(int row = 0; row < no_of_rows; row++) { for(int column = 0; column < no_of_columns; column++) { int element; scanf("%d", &element); matrix[row][column] = prime_distance[element]; } } int min_row_sum = INFINITY; for(int row = 0; row < no_of_rows; row++) { int row_sum = 0; for(int column = 0; column < no_of_columns; column++) { row_sum += matrix[row][column]; } min_row_sum = min(min_row_sum, row_sum); } int min_column_sum = INFINITY; for(int column = 0; column < no_of_columns; column++) { int column_sum = 0; for(int row = 0; row < no_of_rows; row++) { column_sum += matrix[row][column]; } min_column_sum = min(min_column_sum, column_sum); } printf("%d\n",min(min_row_sum, min_column_sum)); return 0; } ================================================ FILE: C Programs/C Programs - 9/String Task.cpp ================================================ #include #include #include #include using namespace std; #define to_lower(ch) ( ch += (ch >= 'A' && ch <= 'Z' ? 'a' - 'A' : 0) ) #define MAX_LENGTH 100 + 2 bool is_vowel(char ch) { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': return true; default : return false; } } int main() { char initial_string[MAX_LENGTH]; string answer; scanf("%s", initial_string); for(int i = 0; initial_string[i] != '\0'; i++) { if(is_vowel(to_lower(initial_string[i])) == false) { answer += '.'; answer += to_lower(initial_string[i]); } } cout << answer << "\n"; return 0; } ================================================ FILE: C Programs/C Programs - 9/Subtractions.cpp ================================================ #include #include using namespace std; int no_of_steps_in_finding_gcd(int a, int b) { int m = min(a, b); int n = max(a, b); if(m == 0) return 0; else return n/m + no_of_steps_in_finding_gcd(m, n%m); } void solve() { int a, b; scanf("%d %d", &a, &b); printf("%d\n", no_of_steps_in_finding_gcd(a, b) ); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: C Programs/C Programs - 9/Toy Army.cpp ================================================ #include int main() { int number_of_soldiers, killed; scanf("%d", &number_of_soldiers); killed = 3*((number_of_soldiers + 1)/2); printf("%d\n", killed); return 0; } ================================================ FILE: C Programs/C Programs - 9/k-th_Divisor.cpp ================================================ #include #include #include #define all(v) (v).begin(),(v).end() using namespace std; int main() { long long num, answer; unsigned int k, max_number_of_divisors; scanf("%I64d %d", &num, &k); vector divisors; for(int i = 1; i*1LL*i <= num; i++) if(num%i == 0) divisors.push_back(i); max_number_of_divisors = 2*divisors.size(); if(divisors.back()*1LL*divisors.back() == num) max_number_of_divisors--; //Square root gets counted twice if(k > max_number_of_divisors) { answer = -1; } else { if(k <= divisors.size()) answer = divisors[k - 1]; else //If k and k' are indices such that f(k)*f(k') = N, k + k' = f - 1, where f is the number of factors, k' = f - k - 1, in 1-index. answer = num/divisors[max_number_of_divisors - k ]; } printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 10/A and B Compilation Errors.cpp ================================================ #include int main() { int no_of_errors, error_i; scanf("%d", &no_of_errors); int sum_1 = 0; for(int i = 1; i <= no_of_errors; i++) { scanf("%d", &error_i); sum_1 += error_i; } //Second List int sum_2 = 0; for(int i = 1; i <= no_of_errors - 1; i++) { scanf("%d", &error_i); sum_2 += error_i; } int sum_3 = 0; for(int i = 1; i <= no_of_errors - 2; i++) { scanf("%d", &error_i); sum_3 += error_i; } printf("%d \n%d\n", sum_1-sum_2, sum_2 - sum_3); return 0; } ================================================ FILE: C Programs/C Programs 10/Amr and Music.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef pair int_pair; int main() { int no_of_instruments, no_of_days, day_i; scanf("%d %d", &no_of_instruments, &no_of_days); vector < int_pair > no_of_days_to_learn; for(int i = 0; i < no_of_instruments; i++) { scanf("%d", &day_i); no_of_days_to_learn.push_back( make_pair(day_i, i + 1)); } sort(all(no_of_days_to_learn)); vector learnt_instrument; for(int i = 0; i < no_of_instruments && no_of_days > 0; i++) { no_of_days -= no_of_days_to_learn[i].first; if(no_of_days >= 0) learnt_instrument.push_back(no_of_days_to_learn[i].second); } printf("%u\n", learnt_instrument.size()); for(unsigned int i = 0; i < learnt_instrument.size(); i++) printf("%d ", learnt_instrument[i]); return 0; } ================================================ FILE: C Programs/C Programs 10/Arrival of General.cpp ================================================ #include int main() { int no_of_soldiers; scanf("%d", &no_of_soldiers); const int oo = 100 + 1; int tallest_soldier = 0, shortest_soldier = oo; int leftmost_tallest = -1, rightmost_shortest = -1; for(int i = 1; i <= no_of_soldiers; i++) { int height_i; scanf("%d", &height_i); if(height_i > tallest_soldier) { tallest_soldier = height_i; leftmost_tallest = i; } if(height_i <= shortest_soldier) { shortest_soldier = height_i; rightmost_shortest = i; } } int no_of_swaps = 0; if(leftmost_tallest < rightmost_shortest) no_of_swaps = (leftmost_tallest - 1) + (no_of_soldiers - rightmost_shortest); else no_of_swaps = (leftmost_tallest - 1) + (no_of_soldiers - rightmost_shortest) - 1; printf("%d\n", no_of_swaps); return 0; } ================================================ FILE: C Programs/C Programs 10/Bear and Game.cpp ================================================ #include #include using namespace std; int main() { int no_of_interesting_minutes, interesting_minute_i, tv_on_minutes = 0; scanf("%d", &no_of_interesting_minutes); bool tv_on = true; vector interesting_minute; interesting_minute.push_back(0); for(int i = 1; i <= no_of_interesting_minutes; i++) { scanf("%d", &interesting_minute_i); interesting_minute.push_back(interesting_minute_i); } if(interesting_minute.back() != 90) interesting_minute.push_back(90); for(unsigned int i = 1; i < interesting_minute.size() ; i++) { if(tv_on) { int boring_interval = (interesting_minute[i] - 1) - interesting_minute[i - 1]; if(boring_interval >= 15) { tv_on_minutes += 15; tv_on = false; } else { tv_on_minutes += boring_interval + 1; //Watch the boring interval + the interesting minute } } } printf("%d\n", tv_on_minutes); return 0; } ================================================ FILE: C Programs/C Programs 10/Beautiful Year.cpp ================================================ #include #include using namespace std; int is_beautiful(int year) { vector digit_frequency(10, 0); while(year > 0) { digit_frequency[year%10]++; year = year/10; } for(int i = 0; i < 10; i++) if(digit_frequency[i] > 1) return false; return true; } int main() { int year; scanf("%d", &year); int beautiful_year; for(beautiful_year = year + 1; ; beautiful_year++) if(is_beautiful(beautiful_year)) break; printf("%d\n", beautiful_year); return 0; } ================================================ FILE: C Programs/C Programs 10/Black Square.cpp ================================================ #include #include using namespace std; #define MAX_LENGTH 100 + 5 int main() { int no_of_rows, no_of_columns; scanf("%d %d", &no_of_rows, &no_of_columns); char rectangle[MAX_LENGTH][MAX_LENGTH]; int no_of_black_squares = 0, left_most = no_of_columns + 1, right_most = -1, highest = -1, lowest = no_of_rows + 1; for(int i = 0; i < no_of_rows; i++) { scanf("%s", rectangle[i]); for(int j = 0; j < no_of_columns; j++) { if(rectangle[i][j] == 'B') { no_of_black_squares ++; left_most = min(left_most, j); right_most = max(right_most, j); highest = max(highest, i); lowest = min(lowest, i); } } } int square_rows = highest - lowest + 1, square_columns = right_most - left_most + 1; int square_side = max(square_columns, square_rows); int repainted = -1; if(no_of_black_squares == 0) { repainted = 1; } else if(square_side <= min(no_of_rows, no_of_columns)) { repainted = square_side*square_side - no_of_black_squares; } printf("%d\n", repainted); return 0; } ================================================ FILE: C Programs/C Programs 10/Counterexample.cpp ================================================ #include int main() { long long left, right; scanf("%I64d %I64d", &left, &right); long long range = right - (left - 1); if(range < 3 || (left%2 == 1 && range < 4)) { printf("-1\n"); } else { if(left%2 == 0) printf("%I64d %I64d %I64d", left, left + 1, left + 2); else printf("%I64d %I64d %I64d", left + 1, left + 2, left + 3); } return 0; } ================================================ FILE: C Programs/C Programs 10/Difference Row.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector sequence(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &sequence[i]); sort(all(sequence)); swap(sequence[0], sequence.back()); for(unsigned int i = 0; i < sequence.size(); i++) printf("%d ", sequence[i]); return 0; } ================================================ FILE: C Programs/C Programs 10/Eugene and Array.cpp ================================================ #include int main() { int no_of_elements, no_of_queries, no_of_1 = 0, no_of_minus_1 = 0; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); no_of_1 += (element_i == 1); no_of_minus_1 += (element_i == -1); } for(int i = 1; i <= no_of_queries; i++) { int left, right, range; scanf("%d %d", &left, &right); range = right - (left - 1); printf(range%2 == 0 && no_of_1 >= range/2 && no_of_minus_1 >= range/2 ? "1\n" : "0\n"); } return 0; } ================================================ FILE: C Programs/C Programs 10/Interesting Drink.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_shops; scanf("%d", &no_of_shops); vector price_in_shop(no_of_shops); for(int i = 0; i < no_of_shops; i++) scanf("%d", &price_in_shop[i]); sort(all(price_in_shop)); int no_of_days, budget_day_i; scanf("%d", &no_of_days); for(int i = 1; i <= no_of_days; i++) { scanf("%d", &budget_day_i); int no_of_eligible_shops = upper_bound(all(price_in_shop), budget_day_i) - price_in_shop.begin(); printf("%d\n",no_of_eligible_shops); //0 indexed vector so no need to subtract 1. } return 0; } ================================================ FILE: C Programs/C Programs 10/Keyboard Layouts.cpp ================================================ #include #include #define NO_OF_ALPHABETS 26 #define MAX_LENGTH 1000 + 2 #define tolower(ch) (ch >= 'A' && ch <= 'Z' ? ch + 'a' - 'A' : ch) #define tocapital(ch) (ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch) #define isalpha(ch) (tolower(ch) >= 'a' && tolower(ch) <= 'z' ? true : false) #define is_capital(ch) (ch >= 'A' && ch <= 'Z' ? true : false) using namespace std; int main() { char keyboard_1[NO_OF_ALPHABETS], keyboard_2[NO_OF_ALPHABETS]; scanf("%s %s", keyboard_1, keyboard_2); map corresponding_keyboard_2_char; for(int i = 0; i < NO_OF_ALPHABETS; i++) { corresponding_keyboard_2_char[ keyboard_1[i] ] = keyboard_2[i]; } char text[MAX_LENGTH]; scanf("%s", text); for(int i = 0; text[i] != '\0'; i++) { if(isalpha(text[i])) { char input = tolower(text[i]); putchar(is_capital(text[i]) ? tocapital(corresponding_keyboard_2_char[input]) : corresponding_keyboard_2_char[input]); } else { putchar(text[i]); //Not there in the keyboards } } return 0; } ================================================ FILE: C Programs/C Programs 10/Life Without Zeroes.cpp ================================================ #include long long reverse(long long n) { long long reverse_n = 0; while(n > 0) { reverse_n = reverse_n*10 + n%10; n = n/10; } return reverse_n; } long long zeroless(long long n) { long long zeroless_n = 0; while(n > 0) { int digit = n%10; if(digit != 0) zeroless_n = zeroless_n*10 + digit; n = n/10; } return reverse(zeroless_n); } int main() { int a, b; scanf("%d %d", &a, &b); printf(zeroless(a) + zeroless(b) == zeroless(a + b) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 10/Modified GCD.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int get_gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return get_gcd(max(a, b)%min(a, b), min(a, b)); } int main() { int a, b; scanf("%d %d", &a, &b); int gcd = get_gcd(a, b); vector factors; for(int i = 1; i*i <= gcd; i++) { if(gcd%i == 0) { if(i*i == gcd) { factors.push_back(i); } else { factors.push_back(i); factors.push_back(gcd/i); } } } sort(all(factors)); int number_of_queries; scanf("%d", &number_of_queries); for(int i = 1; i <= number_of_queries; i++) { int left, right, answer; scanf("%d %d", &left, &right); int index = upper_bound(factors.begin(), factors.end(), right) - factors.begin(); //Returns 1 indexed index--; if(factors[index] < left) answer = -1; else answer = factors[index]; printf("%d\n", answer); } return 0; } ================================================ FILE: C Programs/C Programs 10/Multi Judge Solving.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_problems, max_solved_difficulty; scanf("%d %d", &no_of_problems, &max_solved_difficulty); vector difficulty(no_of_problems); for(int i = 0; i < no_of_problems; i++) { scanf("%d", &difficulty[i]); } sort(all(difficulty)); int no_of_practice_problems_required = 0; int range = 2*max_solved_difficulty; for(int i = 0; i < no_of_problems; i++) { if(difficulty[i] > range) { while(difficulty[i] > range) { no_of_practice_problems_required++; range = range*2; } } range = max(2*difficulty[i], range); } printf("%d\n", no_of_practice_problems_required); return 0; } ================================================ FILE: C Programs/C Programs 10/Next Test.cpp ================================================ #include #include using namespace std; int main() { vector is_used(3000 + 2, false); int no_of_tests, test_i, default_for_next; scanf("%d", &no_of_tests); for(int i = 1; i <= no_of_tests; i++) { scanf("%d", &test_i); is_used[test_i] = true; } for(int i = 1; i <= 3001; i++) { if(is_used[i] == false) { default_for_next = i; break; } } printf("%d\n", default_for_next); return 0; } ================================================ FILE: C Programs/C Programs 10/Presents.cpp ================================================ #include #include using namespace std; int main() { int no_of_people; scanf("%d", &no_of_people); vector present_giver_of(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) { int gift_receiver; scanf("%d", &gift_receiver); present_giver_of[gift_receiver] = i; } for(int i = 1; i <= no_of_people; i++) printf("%d ", present_giver_of[i]); return 0; } ================================================ FILE: C Programs/C Programs 10/Serega and Coat Rack.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_hooks, fine, no_of_guests; scanf("%d %d", &no_of_hooks, &fine); vector hook_prices(no_of_hooks); for(int i = 0; i < no_of_hooks; i++) scanf("%d", &hook_prices[i]); sort(all(hook_prices)); scanf("%d", &no_of_guests); int unhappy_guests = max(no_of_guests - no_of_hooks, 0); int total_fine = unhappy_guests*fine; int no_of_satisfied_guests = no_of_guests - unhappy_guests; int income = 0; for(int i = 0; i < no_of_satisfied_guests; i++) income += hook_prices[i]; printf("%d\n", income - total_fine); return 0; } ================================================ FILE: C Programs/C Programs 10/Serega and Suffixes.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector no_of_distinct_elements_from_here(no_of_elements + 1, 0); set distinct_elements; for(int i = no_of_elements; i >= 1; i--) { distinct_elements.insert(element[i]); no_of_distinct_elements_from_here[i] = distinct_elements.size(); } for(int i = 0; i < no_of_queries; i++) { int start_i; scanf("%d", &start_i); printf("%u\n", no_of_distinct_elements_from_here[start_i]); } return 0; } ================================================ FILE: C Programs/C Programs 10/Slightly Decreasing Permutation.cpp ================================================ #include int main() { int n, k; scanf("%d %d", &n, &k); for(int i = 1; i <= k ; i++) printf("%d ", n - (i - 1)); for(int i = 1; i + k <= n; i++) printf("%d ", i); return 0; } ================================================ FILE: C Programs/C Programs 10/SwapSort.cpp ================================================ #include #include #include using namespace std; int main() { typedef pair pair_int; int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); vector swaps; //Selection Sort for(int i = 0; i < no_of_elements; i++) { int min_i_index = i; for(int j = i + 1; j < no_of_elements; j++) { if(element[j] < element[min_i_index]) min_i_index = j; } if(min_i_index != i) { swaps.push_back(make_pair(i, min_i_index)); swap(element[min_i_index], element[i]); } } printf("%u\n", swaps.size()); for(unsigned int i = 0; i < swaps.size(); i++) { printf("%d %d\n", swaps[i].first, swaps[i].second); } return 0; } ================================================ FILE: C Programs/C Programs 10/Taxi.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int no_of_groups; scanf("%d", &no_of_groups); int no_of_1s = 0, no_of_2s = 0, no_of_3s = 0, no_of_4s = 0; int group_i; for(int i = 1; i <= no_of_groups; i++) { scanf("%d", &group_i); no_of_1s += (group_i == 1); no_of_2s += (group_i == 2); no_of_3s += (group_i == 3); no_of_4s += (group_i == 4); } int no_of_rides_with_3_and_1 = min(no_of_3s, no_of_1s); int no_of_rides = no_of_4s + no_of_rides_with_3_and_1 + no_of_2s/2; //The remaining groups of 2s 3s and 4s no_of_3s -= no_of_rides_with_3_and_1; no_of_1s -= no_of_rides_with_3_and_1; no_of_2s = no_of_2s%2; no_of_rides += no_of_3s; //Pair up as many 3s with 1s and then the remaining 3s go alone. //Pair of 1s with the remaining 2s if(no_of_2s > 0) { no_of_1s -= 2; no_of_rides++; } if(no_of_1s > 0) no_of_rides += no_of_1s/4 + (no_of_1s%4 != 0); printf("%d\n", no_of_rides); return 0; } ================================================ FILE: C Programs/C Programs 10/Toy Cars.cpp ================================================ #include #include using namespace std; int main() { int no_of_cars; scanf("%d", &no_of_cars); vector good_cars; for(int i = 1; i <= no_of_cars; i++) { bool good_car = true; for(int j = 1; j <= no_of_cars; j++) { int collision; scanf("%d", &collision); if(collision == 1 || collision == 3) good_car = false; } if(good_car) good_cars.push_back(i); } printf("%u\n",good_cars.size()); for(unsigned int i = 0; i < good_cars.size(); i++) printf("%d\n", good_cars[i]); return 0; } ================================================ FILE: C Programs/C Programs 10/Unimodal Arrays.cpp ================================================ #include int main() { bool is_unimodal = true; int no_of_elements, element_i, element_i_minus_1 = 0, phase = 1; scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &element_i); if(phase == 1) { if(element_i < element_i_minus_1)//Phase 2 has only one element phase = 3; else if(element_i == element_i_minus_1) phase = 2; } else if(phase == 2) { if(element_i > element_i_minus_1) is_unimodal = false; else if(element_i < element_i_minus_1) phase = 3; } else if(phase == 3) { if(element_i >= element_i_minus_1) is_unimodal = false; } element_i_minus_1 = element_i; } printf(is_unimodal ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 10/Valera and Plates.cpp ================================================ #include int main() { int no_of_days, no_of_bowls, no_of_plates; scanf("%d %d %d", &no_of_days, &no_of_bowls, &no_of_plates); int no_of_cleanings = 0; for(int i = 1; i <= no_of_days; i++) { int dish_type; scanf("%d", &dish_type); if(dish_type == 1) { if(no_of_bowls == 0) no_of_cleanings++; else no_of_bowls--; } if(dish_type == 2) { if(no_of_plates == 0 && no_of_bowls == 0) no_of_cleanings++; else if(no_of_plates > 0) no_of_plates--; else no_of_bowls--; } } printf("%d\n", no_of_cleanings); return 0; } ================================================ FILE: C Programs/C Programs 10/Vanya and Cubes.cpp ================================================ #include int main() { int no_of_cubes, height; scanf("%d", &no_of_cubes); for(height = 1; ; height++) { no_of_cubes -= (height*(height + 1))/2; if(no_of_cubes < 0) break; } height--; printf("%d\n", height); return 0; } ================================================ FILE: C Programs/C Programs 11/BerSU Ball.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_girls; scanf("%d", &no_of_girls); vector girl_skills(no_of_girls); for(int i = 0; i < no_of_girls; i++) scanf("%d", &girl_skills[i]); int no_of_boys; scanf("%d", &no_of_boys); vector boy_skills(no_of_boys); for(int i = 0; i < no_of_boys; i++) scanf("%d", &boy_skills[i]); sort(all(girl_skills)); sort(all(boy_skills)); vector is_available(no_of_boys, true); int no_of_pairs = 0; for(int i = 0; i < no_of_girls; i++) { int eligible_boy = lower_bound(all(boy_skills), girl_skills[i] - 1) - boy_skills.begin(); for( ;abs(boy_skills[eligible_boy] - girl_skills[i]) <= 1 && eligible_boy < no_of_boys; eligible_boy++) { if(is_available[eligible_boy]) { no_of_pairs++; is_available[eligible_boy] = false; break; } } } printf("%d\n", no_of_pairs); return 0; } ================================================ FILE: C Programs/C Programs 11/Elections.cpp ================================================ #include #include using namespace std; int main() { int no_of_candidates, no_of_cities; scanf("%d %d", &no_of_candidates, &no_of_cities); vector no_of_wins_for(no_of_candidates + 1, 0); for(int city_i = 1; city_i <= no_of_cities; city_i++) { int round_winner = 1, winner_votes = 0; //If everyone gets 0 votes, the first candidate must win. for(int candidate_i = 1; candidate_i <= no_of_candidates; candidate_i++) { int votes; scanf("%d", &votes); if(votes > winner_votes) { round_winner = candidate_i; winner_votes = votes; } } no_of_wins_for[round_winner]++; } int winner = 0; for(int i = 1; i <= no_of_candidates; i++) if(no_of_wins_for[i] > no_of_wins_for[winner]) winner = i; printf("%d\n", winner); return 0; } ================================================ FILE: C Programs/C Programs 11/Five in a Row.cpp ================================================ #include #define NO_OF_ROWS 10 #define NO_OF_COLUMNS 10 bool horizontal_win(char grid[][NO_OF_COLUMNS + 2], int i, int j) { int no_of_crosses = 0, no_of_dots = 0; for(int counter = 0; counter < 5 && i + counter < NO_OF_ROWS; counter++) { no_of_crosses += (grid[i + counter][j] == 'X'); no_of_dots += (grid[i + counter][j] == '.'); } return (no_of_crosses == 4 && no_of_dots == 1 ? true : false); } bool vertical_win(char grid[][NO_OF_COLUMNS + 2], int i, int j) { int no_of_crosses = 0, no_of_dots = 0; for(int counter = 0; counter < 5 && j + counter < NO_OF_COLUMNS; counter++) { no_of_crosses += (grid[i][j + counter] == 'X'); no_of_dots += (grid[i][j + counter] == '.'); } return (no_of_crosses == 4 && no_of_dots == 1 ? true : false); } bool diagonal_win(char grid[][NO_OF_COLUMNS + 2], int i, int j) { int no_of_crosses = 0, no_of_dots = 0; for(int counter = 0; counter < 5 && i + counter < NO_OF_ROWS && j + counter < NO_OF_COLUMNS; counter++) { no_of_crosses += (grid[i + counter][j + counter] == 'X'); no_of_dots += (grid[i + counter][j + counter] == '.'); } return (no_of_crosses == 4 && no_of_dots == 1 ? true : false); } bool anti_diagonal_win(char grid[][NO_OF_COLUMNS + 2], int i, int j) { int no_of_crosses = 0, no_of_dots = 0; for(int counter = 0; counter < 5 && i + counter <= NO_OF_ROWS && j - counter >= 0; counter++) { no_of_crosses += (grid[i + counter][j - counter] == 'X'); no_of_dots += (grid[i + counter][j - counter] == '.'); } return (no_of_crosses == 4 && no_of_dots == 1 ? true : false); } int main() { bool win_possible = false; char grid[NO_OF_ROWS][NO_OF_COLUMNS + 2]; for(int i = 0; i < NO_OF_ROWS; i++) scanf("%s", grid[i]); for(int i = 0; i < NO_OF_ROWS; i++) { for(int j = 0; j < NO_OF_COLUMNS; j++) { if(horizontal_win(grid, i, j) || vertical_win(grid, i, j) || diagonal_win(grid, i, j) || anti_diagonal_win(grid, i, j)) { win_possible = true; break; } } } printf(win_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 11/Football.cpp ================================================ #include #define max(a, b) (a > b ? a : b) #define MAX_LENGTH 100 + 2 int main() { char players[MAX_LENGTH]; scanf("%s", players); int maximum_dangerous_sequence = 1, current_dangerous_sequence = 1; for(int i = 1; players[i] != '\0'; i++) { current_dangerous_sequence = (players[i] == players[i - 1] ? current_dangerous_sequence + 1 : 1); maximum_dangerous_sequence = max(maximum_dangerous_sequence, current_dangerous_sequence); } printf(maximum_dangerous_sequence >= 7 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 11/Fortune Telling.cpp ================================================ #include #include using namespace std; int main() { const int odd_oo = 1e9 + 1; int no_of_flowers, answer; scanf("%d", &no_of_flowers); int sum_of_even_numbers = 0, sum_of_odd_numbers = 0, smallest_odd_number = odd_oo; for(int i = 1; i <= no_of_flowers; i++) { int petals; scanf("%d", &petals); if(petals%2 == 0) sum_of_even_numbers += petals; else { sum_of_odd_numbers += petals; smallest_odd_number = min(smallest_odd_number, petals); } } if(sum_of_odd_numbers == 0) answer = 0; else if(sum_of_odd_numbers%2 == 0) answer = sum_of_even_numbers + sum_of_odd_numbers - smallest_odd_number; //To keep the sum odd else if(sum_of_odd_numbers%2 == 1) answer = sum_of_even_numbers + sum_of_odd_numbers; printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 11/Free Cash Alternate Solution.cpp ================================================ #include #include using namespace std; int main() { int no_of_customers; scanf("%d ", &no_of_customers); int hour_i, minute_i, previous_hour = 0, previous_minute = 0; int no_of_customers_at_this_time = 0, max_customers_arriving_together = 0; for(int i = 1; i <= no_of_customers; i++) { scanf("%d %d", &hour_i, &minute_i); no_of_customers_at_this_time = (hour_i == previous_hour && minute_i == previous_minute ? no_of_customers_at_this_time + 1 : 1); max_customers_arriving_together = max(max_customers_arriving_together, no_of_customers_at_this_time); previous_hour = hour_i; previous_minute = minute_i; } printf("%d\n", max_customers_arriving_together); return 0; } ================================================ FILE: C Programs/C Programs 11/Free Cash.cpp ================================================ #include #include #include using namespace std; int main() { const int NO_OF_MINUTES_IN_HOUR = 60; int no_of_customers, no_of_minutes, no_of_hours; scanf("%d ", &no_of_customers); map no_of_customers_arriving_at; for(int i = 1; i <= no_of_customers; i++) { scanf("%d %d", &no_of_hours, &no_of_minutes); int arrival_time = no_of_hours*NO_OF_MINUTES_IN_HOUR + no_of_minutes; no_of_customers_arriving_at[arrival_time]++; } int max_customers_arriving_together = 0; for(map :: iterator it = no_of_customers_arriving_at.begin(); it != no_of_customers_arriving_at.end(); it++) { max_customers_arriving_together = max(max_customers_arriving_together, it->second); } printf("%d\n", max_customers_arriving_together); return 0; } ================================================ FILE: C Programs/C Programs 11/Games.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_teams; scanf("%d", &no_of_teams); vector home_uniform(no_of_teams + 1); map no_of_guest_uniforms; for(int i = 1; i <= no_of_teams; i++) { int guest_uniform; scanf("%d %d", &home_uniform[i], &guest_uniform); no_of_guest_uniforms[guest_uniform]++; } int no_of_changes = 0; for(int i = 1; i <= no_of_teams; i++) { no_of_changes += no_of_guest_uniforms[home_uniform[i]]; } printf("%d\n", no_of_changes); return 0; } ================================================ FILE: C Programs/C Programs 11/Good Number.cpp ================================================ #include int main() { int no_of_numbers, k; scanf("%d %d", &no_of_numbers, &k); int good_numbers = 0; for(int i = 1; i <= no_of_numbers; i++) { int number, digit_present[10] = {false}, smallest_missing_digit = 0; scanf("%d", &number); if(number == 0) digit_present[0] = true; while(number > 0) { digit_present[number%10] = true; number = number/10; } while(digit_present[smallest_missing_digit] && smallest_missing_digit < 10) smallest_missing_digit++; good_numbers += (smallest_missing_digit > k); } printf("%d\n", good_numbers); return 0; } ================================================ FILE: C Programs/C Programs 11/Johnny Likes Numbers.cpp ================================================ #include int main() { int n, k; scanf("%d %d", &n, &k); int next_multiple = n + (k - n%k); printf("%d\n", next_multiple); return 0; } ================================================ FILE: C Programs/C Programs 11/Lever.cpp ================================================ #include #define MAX_LENGTH 1000000 + 2 int main() { char lever[MAX_LENGTH]; scanf("%s", lever); bool left = true, right = false; long long left_moment = 0, right_moment = 0, weights_till_here = 0; int distance_from_pivot; for(int i = 0; lever[i] != '\0'; i++) { if(lever[i] == '^') { left = false, right = true; distance_from_pivot = 0; } else { if(left) { if(lever[i] != '=') weights_till_here += (lever[i] - '0'); left_moment += weights_till_here; } else if(right) { distance_from_pivot++; if(lever[i] != '=') right_moment += distance_from_pivot*(lever[i] - '0'); } } } if(left_moment == right_moment) printf("balance\n"); else printf(left_moment > right_moment ? "left\n" : "right\n"); return 0; } ================================================ FILE: C Programs/C Programs 11/Lunch Rush.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { int no_of_restaurants, time_limit; scanf("%d %d", &no_of_restaurants, &time_limit); const int NEGATIVE_INFINITY = -1e9; int maximum_joy = NEGATIVE_INFINITY; for(int i = 1; i <= no_of_restaurants; i++) { int time_i, joy_i; scanf("%d %d", &joy_i, &time_i); if(time_i <= time_limit) { maximum_joy = max(maximum_joy, joy_i); } else { maximum_joy = max(maximum_joy, joy_i - (time_i - time_limit)); } } printf("%d\n", maximum_joy); return 0; } ================================================ FILE: C Programs/C Programs 11/Magic Spheres.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { int blue, violet, orange; scanf("%d %d %d", &blue, &violet, &orange); int required_blue, required_violet, required_orange; scanf("%d %d %d", &required_blue, &required_violet, &required_orange); int no_of_new_spheres_possible = 0, no_of_new_spheres_needed = 0; no_of_new_spheres_needed = max(required_blue - blue, 0) + max(required_orange - orange, 0) + max(required_violet - violet, 0); no_of_new_spheres_possible = max( (blue - required_blue)/2, 0) + max( (orange - required_orange)/2, 0) + max( (violet - required_violet)/2, 0); printf(no_of_new_spheres_possible >= no_of_new_spheres_needed ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: C Programs/C Programs 11/New Year and Hurry.cpp ================================================ #include int main() { int travel_time, no_of_problems; scanf("%d %d", &no_of_problems, &travel_time); const int NO_OF_MINUTES_IN_HOUR = 60; int time = 4*NO_OF_MINUTES_IN_HOUR; time = time - travel_time; int solved_problems = 0; for(int problem_i = 1; problem_i <= no_of_problems; problem_i++) { if(time - 5*problem_i >= 0) { time = time - 5*problem_i; solved_problems++; } else //Time is insufficient { break; } } printf("%d\n", solved_problems); return 0; } ================================================ FILE: C Programs/C Programs 11/Nicholas and Permutation.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); int index_1, index_n; for(int i = 1; i <= n; i++) { int element; scanf("%d", &element); if(element == 1) index_1 = i; else if(element == n) index_n = i; } int distance = max( max(index_1, index_n) - 1, n - min(index_1, index_n) ); printf("%d\n", distance); return 0; } ================================================ FILE: C Programs/C Programs 11/Petya and Staircases.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_steps, no_of_dirty_steps; scanf("%d %d", &no_of_steps, &no_of_dirty_steps); vector dirty_steps(no_of_dirty_steps); for(int i = 0; i < no_of_dirty_steps; i++) scanf("%d", &dirty_steps[i]); sort(all(dirty_steps)); bool is_possible = true; if(no_of_dirty_steps > 0) { if(dirty_steps.front() == 1 || dirty_steps.back() == no_of_steps) { is_possible = false; } else { for(int i = 2; i < no_of_dirty_steps; i++) { if(dirty_steps[i] == dirty_steps[i - 1] + 1 && dirty_steps[i] == dirty_steps[i - 2] + 2) //Three consecutive dirty steps { is_possible = false; break; } } } } printf(is_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 11/Playing with Dice.cpp ================================================ #include #include using namespace std; int main() { int num_1, num_2; scanf("%d %d", &num_1, &num_2); int one_wins = 0, draw = 0, two_wins = 0; for(int dice_i = 1; dice_i <= 6; dice_i++) { one_wins += (abs(num_1 - dice_i) < abs(num_2 - dice_i)); two_wins += (abs(num_1 - dice_i) > abs(num_2 - dice_i)); draw += (abs(num_1 - dice_i) == abs(num_2 - dice_i)); } printf("%d %d %d", one_wins, draw, two_wins); return 0; } ================================================ FILE: C Programs/C Programs 11/Saitama Destroys Hotel.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_stops, top_floor; scanf("%d %d", &no_of_stops, &top_floor); vector floor_stop(no_of_stops); vector passenger_arrival_time(no_of_stops); for(int i = 0; i < no_of_stops; i++) scanf("%d %d", &floor_stop[i], &passenger_arrival_time[i]); reverse(all(floor_stop)); reverse(all(passenger_arrival_time)); int total_travel_time = 0, current_floor = top_floor; for(int i = 0; i < no_of_stops; i++) { total_travel_time += (current_floor - floor_stop[i]); int wait_time = max(passenger_arrival_time[i] - total_travel_time, 0); total_travel_time += wait_time; current_floor = floor_stop[i]; } total_travel_time += current_floor; //Go to floor 0 from the last floor stop printf("%d\n", total_travel_time); return 0; } ================================================ FILE: C Programs/C Programs 11/Sasha and Sticks.cpp ================================================ #include int main() { long long no_of_sticks, one_turn_draw; scanf("%I64d %I64d", &no_of_sticks, &one_turn_draw); long long no_of_turns = no_of_sticks/one_turn_draw; printf(no_of_turns%2 == 1 ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: C Programs/C Programs 11/Soft Drinking.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define min_3(a, b, c) min(a, min(b, c)) int main() { int no_of_friends , no_of_bottles, bottle_volume, no_of_limes, no_of_slices, total_salt, one_round_drink, one_round_salt; scanf("%d %d %d %d", &no_of_friends, &no_of_bottles, &bottle_volume, &no_of_limes); scanf("%d %d %d %d", &no_of_slices, &total_salt, &one_round_drink, &one_round_salt); int no_of_toasts = min_3( (no_of_bottles*bottle_volume)/one_round_drink, no_of_limes*no_of_slices, total_salt/one_round_salt )/no_of_friends; printf("%d\n", no_of_toasts); return 0; } ================================================ FILE: C Programs/C Programs 11/The Child and The Homework.cpp ================================================ #include #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() #define MAX_LENGTH 100 + 2 int main() { typedef pair int_char; char option[MAX_LENGTH]; vector option_length; for(int i = 0; i < 4; i++) { scanf("%s", option); option_length.push_back(make_pair(strlen(option) - 2, 'A' + i)); //Excluding the alphabet and the . } sort(all(option_length)); char answer = 'C'; if(2*option_length[0].first <= option_length[1].first && option_length[3].first >= 2*option_length[2].first)//Two options { answer = 'C'; } else if(2*option_length[0].first <= option_length[1].first) { answer = option_length[0].second; } else if(option_length[3].first >= 2*option_length[2].first) { answer = option_length[3].second; } printf("%c\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 11/The New Year Meeting Friends Alternate Solution.cpp ================================================ #include #include using namespace std; #define min_3(a, b, c) min(a, min(b, c)) #define max_3(a, b, c) max(a, max(b, c)) int main() { int location_1, location_2, location_3; scanf("%d %d %d", &location_1, &location_2, &location_3); int leftmost = min_3(location_1, location_2, location_3); int rightmost = max_3(location_1, location_2, location_3); printf("%d\n", rightmost - leftmost); return 0; } ================================================ FILE: C Programs/C Programs 11/The New Year Meeting Friends.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { const int no_of_friends = 3; vector location(no_of_friends); scanf("%d %d %d", &location[0], &location[1], &location[2]); sort(all(location)); int minimum_distance = 300; for(int meet_point = location[0]; meet_point <= location[2]; meet_point++) { int distance = abs(meet_point - location[0]) + abs(meet_point - location[1]) + abs(meet_point - location[2]); minimum_distance = min(minimum_distance, distance); } printf("%d\n", minimum_distance); return 0; } ================================================ FILE: C Programs/C Programs 11/Word.cpp ================================================ #include #define is_capital(ch) (ch >= 'A' && ch <= 'Z' ? true : false) #define lower_case(ch) (is_capital(ch) ? ch + 'a' - 'A' : ch) #define capital(ch) (is_capital(ch) ? ch : ch - ('a' - 'A') ) #define MAX_LENGTH 100 + 2 int main() { char word[MAX_LENGTH]; scanf("%s", word); int i, no_of_capitals = 0, no_of_lower_case = 0, length; for(i = 0; word[i] != '\0'; i++) { no_of_capitals += is_capital(word[i]) ; } length = i; no_of_lower_case = (length - no_of_capitals); if(no_of_lower_case >= no_of_capitals) { for(i = 0; word[i] != '\0'; i++) { putchar(lower_case(word[i])); } } else { for(int i = 0; i < length; i++) { putchar(capital(word[i])); } } return 0; } ================================================ FILE: C Programs/C Programs 11/inc ARG.cpp ================================================ #include #define MAX_LENGTH 100 + 2 int main() { int no_of_bits; char initial_state[MAX_LENGTH]; scanf("%d %s", &no_of_bits, initial_state); int first_zero_location = no_of_bits; //Assume there is no 0 so it will be outside the register at first for(int i = 0; i < no_of_bits; i++) { if(initial_state[i] == '0') { first_zero_location = i + 1; //0-indexed break; } } printf("%d\n", first_zero_location); return 0; } ================================================ FILE: C Programs/C Programs 12/Anastasia and Pebbles.cpp ================================================ #include int main() { int no_of_pebble_types, pebble_limit; scanf("%d %d", &no_of_pebble_types, &pebble_limit); int days_to_collect_all_pebbles = 0; for(int i = 1; i <= no_of_pebble_types; i++) { int pebble_i; scanf("%d", &pebble_i); days_to_collect_all_pebbles += pebble_i/pebble_limit + (pebble_i%pebble_limit != 0); //Ceil } days_to_collect_all_pebbles = days_to_collect_all_pebbles/2 + days_to_collect_all_pebbles%2; printf("%d\n", days_to_collect_all_pebbles); return 0; } ================================================ FILE: C Programs/C Programs 12/Bear and Three Balls.cpp ================================================ #include #include using namespace std; int main() { int no_of_balls; scanf("%d", &no_of_balls); set ball; for(int i = 1; i <= no_of_balls; i++) { int ball_i; scanf("%d", &ball_i); ball.insert(ball_i); } bool gift_givable = false; for(set :: iterator i = ball.begin(); i != ball.end(); i++) { int ball_i = *i; if(ball.count(ball_i + 1) == 1 && ball.count(ball_i - 1) == 1) { gift_givable = true; break; } } printf(gift_givable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 12/Buggy Sorting.cpp ================================================ #include int main() { int no_of_elements; scanf("%d", &no_of_elements); if(no_of_elements <= 2) printf("-1\n"); else for(int i = no_of_elements; i >= 1; i--) printf("%d ", i); return 0; } ================================================ FILE: C Programs/C Programs 12/Co Prime Array.cpp ================================================ #include #include using namespace std; int gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } int main() { int no_of_numbers; scanf("%d", &no_of_numbers); vector coprime_array; for(int i = 1; i <= no_of_numbers; i++) { int number_i; scanf("%d", &number_i); if(i == 1 || gcd(coprime_array.back(), number_i) == 1) { coprime_array.push_back(number_i); } else { coprime_array.push_back(1); coprime_array.push_back(number_i); } } int no_of_operations = coprime_array.size() - no_of_numbers; printf("%d\n", no_of_operations); for(unsigned int i = 0; i < coprime_array.size(); i++) printf("%d ", coprime_array[i]); return 0; } ================================================ FILE: C Programs/C Programs 12/Dima and Friends.cpp ================================================ #include int main() { int no_of_friends; scanf("%d", &no_of_friends); int other_fingers = 0; for(int i = 1; i <= no_of_friends; i++) { int finger_i; scanf("%d", &finger_i); other_fingers += finger_i; } const int NO_OF_FINGERS = 5; int no_of_choices = 0, no_of_people = no_of_friends + 1; for(int dima_fingers = 1; dima_fingers <= NO_OF_FINGERS; dima_fingers++) { int total_fingers = other_fingers + dima_fingers; no_of_choices += (total_fingers%no_of_people != 1); //choice is valid only if total =/= 1 mod no of people } printf("%d\n", no_of_choices); return 0; } ================================================ FILE: C Programs/C Programs 12/Dima and Sequence.cpp ================================================ #include #include using namespace std; int population_count(int x) { int no_of_1s = x; const int MASK_1 = 0x55555555; const int MASK_2 = 0x33333333; const int MASK_3 = 0x0F0F0F0F; const int MASK_4 = 0x00FF00FF; const int MASK_5 = 0x0000FFFF; no_of_1s = (no_of_1s&MASK_1) + ( (no_of_1s >> 1) & MASK_1); no_of_1s = (no_of_1s&MASK_2) + ( (no_of_1s >> 2) & MASK_2); no_of_1s = (no_of_1s&MASK_3) + ( (no_of_1s >> 4) & MASK_3); no_of_1s = (no_of_1s&MASK_4) + ( (no_of_1s >> 8) & MASK_4); no_of_1s = (no_of_1s&MASK_5) + ( (no_of_1s >> 16) & MASK_5); return no_of_1s; } int main() { int no_of_elements; scanf("%d", &no_of_elements); const int MAX_BITS = 32; vector no_of_elements_with_i_bits_set(MAX_BITS, 0); for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); no_of_elements_with_i_bits_set[population_count(element_i)]++; } long long no_of_pairs = 0; for(int i = 0; i < MAX_BITS; i++) { int frequency_i_pop_count = no_of_elements_with_i_bits_set[i]; no_of_pairs += frequency_i_pop_count*1LL*(frequency_i_pop_count - 1); } no_of_pairs = no_of_pairs/2; //All pairs are counted up to order printf("%I64d\n", no_of_pairs); return 0; } ================================================ FILE: C Programs/C Programs 12/Dreamoon and Stairs Alternate Solution.cpp ================================================ #include int main() { int no_of_steps, multiple; scanf("%d %d", &no_of_steps, &multiple); int lower_limit = no_of_steps/2 + no_of_steps%2; int smallest_multiplier = lower_limit/multiple + (lower_limit%multiple != 0); int minimum_number_of_steps = smallest_multiplier*multiple; printf("%d\n", (minimum_number_of_steps <= no_of_steps ? minimum_number_of_steps : - 1)); return 0; } ================================================ FILE: C Programs/C Programs 12/Dreamoon and Stairs.cpp ================================================ #include int main() { int no_of_steps, multiple; scanf("%d %d", &no_of_steps, &multiple); int minimum_no_of_steps = no_of_steps/2 + no_of_steps%2; while(minimum_no_of_steps <= no_of_steps) { if(minimum_no_of_steps%multiple == 0) { break; } minimum_no_of_steps++; //Replace a 2 with two 1s } printf(minimum_no_of_steps > no_of_steps ? "-1\n" : "%d\n", minimum_no_of_steps); return 0; } ================================================ FILE: C Programs/C Programs 12/Fashion in Berland.cpp ================================================ #include int main() { int no_of_buttons; scanf("%d", &no_of_buttons); int no_of_open_buttons = 0; for(int i = 1; i <= no_of_buttons; i++) { int button_i; scanf("%d", &button_i); no_of_open_buttons += (button_i == 0); } bool fashionable = (no_of_buttons > 1 && no_of_open_buttons == 1) || (no_of_buttons == 1 && no_of_open_buttons == 0); printf(fashionable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 12/Inbox (100500).cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { int no_of_letters; scanf("%d", &no_of_letters); int previous_letter_status = 0, no_of_unread_letters = 0, no_of_unread_segments = 0; for(int i = 1; i <= no_of_letters; i++) { int unread; scanf("%d", &unread); no_of_unread_letters += (unread == 1); if(previous_letter_status == 0 && unread == 1) no_of_unread_segments++; previous_letter_status = unread; } int no_of_operations = no_of_unread_letters + max(no_of_unread_segments - 1, 0); //Incase there are no unread segments, it should be 0 printf("%d\n", no_of_operations); return 0; } ================================================ FILE: C Programs/C Programs 12/Key Races.cpp ================================================ #include int main() { int length_text, speed_1, speed_2, ping_1, ping_2; scanf("%d %d %d %d %d", &length_text, &speed_1, &speed_2, &ping_1, &ping_2); int total_time_1 = speed_1*length_text + 2*ping_1; int total_time_2 = speed_2*length_text + 2*ping_2; if(total_time_1 == total_time_2) printf("Friendship\n"); else printf(total_time_1 < total_time_2 ? "First\n" : "Second\n"); return 0; } ================================================ FILE: C Programs/C Programs 12/Ksusha and Arrays.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); sort(all(element)); bool first_element_divides_all = true; for(int i = 1; i < no_of_elements; i++) { if(element[i]%element.front() != 0) { first_element_divides_all = false; break; } } printf("%d\n", first_element_divides_all ? element.front(): -1); return 0; } ================================================ FILE: C Programs/C Programs 12/Lecture.cpp ================================================ #include #include #include using namespace std; int main() { int length_of_sentence, no_of_words; cin >> length_of_sentence >> no_of_words; map translated; for(int i = 1; i <= no_of_words; i++) { string word, translation; cin >> word >> translation; translated[word] = translation; } for(int i = 1; i <= length_of_sentence; i++) { string current_word; cin >> current_word; cout << (current_word.length() <= translated[current_word].length() ? current_word : translated[current_word]) << " "; } return 0; } ================================================ FILE: C Programs/C Programs 12/Little Elephant and Chess.cpp ================================================ #include #define NO_OF_COLUMNS 8 int main() { const int no_of_rows = 8; bool all_rows_have_alternating_colours = true; for(int i = 1; i <= no_of_rows; i++) { char row[NO_OF_COLUMNS + 2]; scanf("%s", row); for(int square = 1; row[square] != '\0'; square++) { if(row[square] ==row[square - 1]) { all_rows_have_alternating_colours = false; } } } printf(all_rows_have_alternating_colours ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 12/Little Girl and Maximum Sum.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector element(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector no_of_queries_starting_here(no_of_elements + 1, 0); vector no_of_queries_ending_here(no_of_elements + 1, 0); for(int i = 1; i <= no_of_queries; i++) { int left_i, right_i; scanf("%d %d", &left_i, &right_i); no_of_queries_starting_here[left_i]++; if(right_i + 1 <= no_of_elements) no_of_queries_ending_here[right_i + 1]++; } int no_of_queries_on_this_index = 0; vector no_of_times_index_queried(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { no_of_queries_on_this_index += (no_of_queries_starting_here[i] - no_of_queries_ending_here[i]); no_of_times_index_queried[i] = no_of_queries_on_this_index; } sort(all(element)); sort(all(no_of_times_index_queried)); long long maximum_sum = 0; for(int i = 1; i <= no_of_elements; i++) maximum_sum += no_of_times_index_queried[i]*1LL*element[i]; printf("%I64d\n", maximum_sum); return 0; } ================================================ FILE: C Programs/C Programs 12/Minimum Difficulty.cpp ================================================ #include #include #include using namespace std; int main() { int number_of_holds; scanf("%d", &number_of_holds); vector height(number_of_holds + 1); for(int i = 1; i <= number_of_holds; i++) scanf("%d", &height[i]); int original_difficulty = 0; for(int i = 2; i <= number_of_holds; i++) original_difficulty = max(original_difficulty, height[i] - height[i - 1]); const int oo = 1e4; int minimum_difficulty = oo; for(int i = 2; i <= number_of_holds - 1; i++) { int current_difficulty = max(original_difficulty, height[i + 1] - height[i - 1]); minimum_difficulty = min(current_difficulty, minimum_difficulty); } printf("%d\n", minimum_difficulty); return 0; } ================================================ FILE: C Programs/C Programs 12/Pasha and Pixels.cpp ================================================ #include #include using namespace std; int main() { int no_of_rows, no_of_columns, no_of_moves; scanf("%d %d %d", &no_of_rows, &no_of_columns, &no_of_moves); int black_square_formed_on_move = 0; typedef vector v_int; vector black_pixel(no_of_rows + 2, v_int (no_of_columns + 2, false)); for(int move_i = 1; move_i <= no_of_moves; move_i++) { int row_i, column_i; scanf("%d %d", &row_i, &column_i); black_pixel[row_i][column_i] = true; if(black_square_formed_on_move == 0) { if(black_pixel[row_i - 1][column_i] && black_pixel[row_i - 1][column_i - 1] && black_pixel[row_i][column_i - 1]) { black_square_formed_on_move = move_i; } if(black_pixel[row_i - 1][column_i] && black_pixel[row_i - 1][column_i + 1] && black_pixel[row_i][column_i + 1]) { black_square_formed_on_move = move_i; } if(black_pixel[row_i][column_i - 1] && black_pixel[row_i + 1][column_i - 1] && black_pixel[row_i + 1][column_i]) { black_square_formed_on_move = move_i; } if(black_pixel[row_i][column_i + 1] && black_pixel[row_i + 1][column_i + 1] && black_pixel[row_i + 1][column_i]) { black_square_formed_on_move = move_i; } } } printf("%d\n", black_square_formed_on_move); return 0; } ================================================ FILE: C Programs/C Programs 12/Puzzles.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_students, no_of_puzzles; scanf("%d %d", &no_of_students, &no_of_puzzles); vector no_of_pieces(no_of_puzzles); for(int i = 0; i < no_of_puzzles; i++) scanf("%d", &no_of_pieces[i]); sort(all(no_of_pieces)); const int oo = 1e9; int minimum_difference = oo; for(int i = no_of_students - 1; i < no_of_puzzles; i++) { minimum_difference = min(minimum_difference, no_of_pieces[i] - no_of_pieces[i - (no_of_students - 1)]); } printf("%d\n", minimum_difference); return 0; } ================================================ FILE: C Programs/C Programs 12/Santa Claus and Candies.cpp ================================================ #include int main() { int no_of_gifts; scanf("%d", &no_of_gifts); int no_of_people = 1; while(no_of_people*(no_of_people + 1) <= 2*no_of_gifts) no_of_people++; no_of_people--; printf("%d\n", no_of_people); for(int i = 1; i < no_of_people; i++) { printf("%d ", i); no_of_gifts -= i; } printf("%d\n", no_of_gifts); //Last person gets all remaining gifts return 0; } ================================================ FILE: C Programs/C Programs 12/Sereja and Dima.cpp ================================================ #include #include using namespace std; int main() { int no_of_cards; scanf("%d", &no_of_cards); vector card(no_of_cards); for(int i = 0; i < no_of_cards; i++) scanf("%d", &card[i]); int sergey_sum = 0, dima_sum = 0; for(int front_i = 0, back_i = no_of_cards - 1, no_of_turns = 1; no_of_turns <= no_of_cards; no_of_turns++) { int greater_card = max(card[front_i], card[back_i]); if(card[front_i] >= card[back_i]) front_i++; else back_i--; if(no_of_turns%2 == 1) sergey_sum += greater_card; else dima_sum += greater_card; } printf("%d %d\n", sergey_sum, dima_sum); return 0; } ================================================ FILE: C Programs/C Programs 12/Shaas and Oskols.cpp ================================================ #include #include using namespace std; int main() { int no_of_wires; scanf("%d", &no_of_wires); vector no_of_birds_on_wire(no_of_wires + 1); for(int i = 1; i <= no_of_wires; i++) scanf("%d", &no_of_birds_on_wire[i]); int no_of_shots; scanf("%d", &no_of_shots); for(int i = 1; i <= no_of_shots; i++) { int wire_i, shot_bird; scanf("%d %d", &wire_i, &shot_bird); if(wire_i - 1 >= 1) no_of_birds_on_wire[wire_i - 1] += (shot_bird - 1); if(wire_i + 1 <= no_of_wires) no_of_birds_on_wire[wire_i + 1] += (no_of_birds_on_wire[wire_i] - shot_bird); no_of_birds_on_wire[wire_i] = 0; } for(int i = 1; i <= no_of_wires; i++) printf("%d\n", no_of_birds_on_wire[i]); return 0; } ================================================ FILE: C Programs/C Programs 12/Sleuth.cpp ================================================ #include #include #define MAX_LENGTH 100 + 5 #define to_upper(ch) (ch >= 'a' && ch <= 'z' ? ch - ('a' - 'A') : ch) #define is_alpha(ch) (to_upper(ch) >= 'A' && to_upper(ch) <= 'Z' ? true : false) bool is_vowel(char ch) { switch(to_upper(ch)) { case 'A': case 'E': case 'I': case 'O': case 'U': case 'Y': return true; } return false; } int main() { char question[MAX_LENGTH]; fgets(question, MAX_LENGTH, stdin); bool last_letter_vowel = false; for(int i = strlen(question) - 1; i >= 0; i--) { if(is_alpha(question[i]) ) { if(is_vowel(question[i]) ) last_letter_vowel = true; break; } } printf(last_letter_vowel ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 12/The Festive Evening.cpp ================================================ #include #include #include #define MAX_LENGTH 1000000 + 2 using namespace std; int main() { int no_of_guests, no_of_guards; char guests[MAX_LENGTH]; scanf("%d %d %s", &no_of_guests, &no_of_guards, guests); map last_appearance; for(int i = 0; i < no_of_guests; i++) last_appearance[guests[i]] = i; set entering_guests; bool unsafe_situation = false; for(int i = 0; i < no_of_guests; i++) { entering_guests.insert(guests[i]); if(entering_guests.size() > no_of_guards) unsafe_situation = true; if(last_appearance[guests[i]] == i) entering_guests.erase(guests[i]); } printf(unsafe_situation ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 12/The Number on The Board.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() #define MAX_LENGTH 100000 + 2 using namespace std; int main() { int digit_sum; char number_on_board[MAX_LENGTH]; scanf("%d %s", &digit_sum, number_on_board); vector board_number; int board_digit_sum = 0; for(int i = 0; number_on_board[i] != '\0'; i++) { board_digit_sum += number_on_board[i] - '0'; board_number.push_back(number_on_board[i] - '0'); } sort(all(board_number)); int min_no_of_digit_changes = 0; for(unsigned int i = 0; i < board_number.size() && board_digit_sum < digit_sum; i++) { if(board_number[i] != 9) { board_digit_sum += 9 - board_number[i]; min_no_of_digit_changes++; } } printf("%d\n", min_no_of_digit_changes); return 0; } ================================================ FILE: C Programs/C Programs 12/Watching a Movie.cpp ================================================ #include int main() { int no_of_interesting_portions, skip_step; scanf("%d %d", &no_of_interesting_portions, &skip_step); int current_minute = 1, no_of_watched_minutes = 0; for(int i = 1; i <= no_of_interesting_portions; i++) { int beginning_i, end_i; scanf("%d %d", &beginning_i, &end_i); no_of_watched_minutes += (beginning_i - current_minute)%skip_step + (end_i - (beginning_i - 1)); current_minute = end_i + 1; } printf("%d\n", no_of_watched_minutes); return 0; } ================================================ FILE: C Programs/C Programs 13/A Good Contest.cpp ================================================ #include #define MAX_SIZE 10 + 2 int main() { int no_of_users, good_contest = false; scanf("%d", &no_of_users); while(no_of_users--) { char name[MAX_SIZE]; int before_score, after_score; scanf("%s %d %d", name, &before_score, &after_score); if(before_score >= 2400 && after_score > before_score) good_contest = true; } printf(good_contest ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 13/Arpa's Obvious Problem and Mehrad's Terrible Solution.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, target; scanf("%d %d", &no_of_elements, &target); map frequency; for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); frequency[element_i]++; } long long no_of_good_pairs = 0; for(map :: iterator i = frequency.begin(); i != frequency.end(); i++) { int element_i = i->first; int frequency_i = i->second; int pair_element = target^element_i; int pair_frequency = (element_i == pair_element ? frequency_i - 1 : frequency[pair_element]); no_of_good_pairs += pair_frequency*1LL*frequency_i; } no_of_good_pairs = no_of_good_pairs/2; printf("%I64d\n", no_of_good_pairs); return 0; } ================================================ FILE: C Programs/C Programs 13/Arrays.cpp ================================================ #include int main() { int size_a, size_b; scanf("%d %d", &size_a, &size_b); int last_a, first_b, last_a_position, first_b_position; scanf("%d %d", &last_a_position, &first_b_position); int element_i; for(int i = 1; i <= size_a; i++) { scanf("%d", &element_i); if(i == last_a_position) last_a = element_i; } for(int i = size_b; i >= 1; i--) { scanf("%d", &element_i); if(i == first_b_position) first_b = element_i; } printf(last_a < first_b ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 13/Arya and Bran.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int no_of_days, target_candies; scanf("%d %d", &no_of_days, &target_candies); const int one_day_limit = 8; int total_candies = 0, given_candies = 0, required_days = -1; for(int day_i = 1; day_i <= no_of_days; day_i++) { int box_i, given_on_day_i; scanf("%d", &box_i); total_candies += box_i; given_on_day_i = min(one_day_limit, total_candies); total_candies -= given_on_day_i; given_candies += given_on_day_i; if(given_candies >= target_candies) { required_days = day_i; break; } } printf("%d\n", required_days); return 0; } ================================================ FILE: C Programs/C Programs 13/Bear and Elections.cpp ================================================ #include #include using namespace std; int main() { int no_of_candidates; scanf("%d", &no_of_candidates); int limak_votes; priority_queue votes; scanf("%d", &limak_votes); for(int i = 2; i <= no_of_candidates; i++) { int vote_i; scanf("%d", &vote_i); votes.push(vote_i); } int limak_bribes = 0; while(limak_votes + limak_bribes <= votes.top()) { int current_max = votes.top(); votes.pop(); current_max--; limak_bribes++; votes.push(current_max); } printf("%d\n", limak_bribes); return 0; } ================================================ FILE: C Programs/C Programs 13/Business Trip.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int minimum_growth; scanf("%d", &minimum_growth); const int no_of_months = 12; vector growth(no_of_months); for(int i = 0; i < no_of_months; i++) scanf("%d", &growth[i]); sort(all(growth)); reverse(all(growth)); int month_i = 0, plant_growth = 0; while(plant_growth < minimum_growth && month_i < no_of_months) { plant_growth += growth[month_i++]; } printf("%d\n", plant_growth < minimum_growth ? -1 : month_i); return 0; } ================================================ FILE: C Programs/C Programs 13/Cards.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_people; scanf("%d", &no_of_people); vector < pair > cards; for(int i = 1; i <= no_of_people; i++) { int card_i; scanf("%d", &card_i); cards.push_back(make_pair(card_i, i)); } sort(all(cards)); vector < pair > dealt_cards; for(int front_i = 0, back_i = no_of_people - 1; front_i < back_i; front_i++, back_i--) { int front_index = cards[front_i].second; int back_index = cards[back_i].second; dealt_cards.push_back(make_pair(front_index, back_index)); } for(unsigned int i = 0; i < dealt_cards.size(); i++) printf("%d %d\n", dealt_cards[i].first, dealt_cards[i].second); return 0; } ================================================ FILE: C Programs/C Programs 13/Code Obfuscation.cpp ================================================ #include #include #define MAX_LENGTH 500 + 2 using namespace std; int main() { char code[MAX_LENGTH]; scanf("%s", code); set alphabets_used; int code_obfuscation = true; for(int i = 0; code[i] != '\0'; i++) { //Before inserting an alphabet, all alphabets smaller than it must already have been used if(alphabets_used.count(code[i]) == 0) { if(alphabets_used.size() < code[i] - 'a') { code_obfuscation = false; break; } } alphabets_used.insert(code[i]); } printf(code_obfuscation ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 13/Drinks.cpp ================================================ #include int main() { int no_of_drinks; scanf("%d", &no_of_drinks); double numerator = 0.0; for(int i = 1; i <= no_of_drinks; i++) { int percent_i; scanf("%d", &percent_i); numerator += percent_i; } double denominator = no_of_drinks*1.0; double fraction = numerator/denominator; printf("%lf\n", fraction); return 0; } ================================================ FILE: C Programs/C Programs 13/Epic Game.cpp ================================================ #include #include using namespace std; int gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } int main() { int a, b, n; scanf("%d %d %d", &a, &b, &n); int winner; for(int turn_i = 0; n > 0; turn_i++) { int current_player = (turn_i%2 == 0 ? a : b) ; n -= gcd(current_player, n); if(n == 0) winner = turn_i%2; } printf("%d\n", winner); return 0; } ================================================ FILE: C Programs/C Programs 13/Functions Again.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); long long maximum_value, maximum_with_last_difference_added, maximum_with_last_difference_removed; maximum_with_last_difference_added = abs(element[2] - element[1]); maximum_with_last_difference_removed = 0; maximum_value = maximum_with_last_difference_added; for(int i = 3; i <= no_of_elements; i++) { long long maximum_with_this_difference_added, maximum_with_this_difference_removed, maximum_value_ending_here; maximum_with_this_difference_added = max(0LL, maximum_with_last_difference_removed) + abs(element[i] - element[i - 1]); maximum_with_this_difference_removed = maximum_with_last_difference_added - abs(element[i] - element[i - 1]); maximum_value_ending_here = max(maximum_with_this_difference_added, maximum_with_this_difference_removed); maximum_value = max(maximum_value, maximum_value_ending_here); maximum_with_last_difference_added = maximum_with_this_difference_added; maximum_with_last_difference_removed = maximum_with_this_difference_removed; } printf("%I64d\n", maximum_value); return 0; } ================================================ FILE: C Programs/C Programs 13/Generous Kefa.cpp ================================================ #include #define MAX_LENGTH 100 + 2 #define NO_OF_ALPHABETS 26 int main() { int no_of_balloons, no_of_people; char balloon_colours[MAX_LENGTH]; scanf("%d %d %s",&no_of_balloons, &no_of_people, balloon_colours); int no_of_balloons_of_colour[NO_OF_ALPHABETS] = {0}; for(int i = 0; i < no_of_balloons; i++) { no_of_balloons_of_colour[balloon_colours[i] - 'a']++; } int everyone_happy = true; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(no_of_balloons_of_colour[i] > no_of_people) { everyone_happy = false; break; } } printf(everyone_happy ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 13/George and Job.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_numbers, no_of_intervals, max_interval_size; scanf("%d %d %d", &no_of_numbers, &max_interval_size, &no_of_intervals); vector sum_till(no_of_numbers + 1, 0); for(int i = 1; i <= no_of_numbers; i++) { int number_i; scanf("%d", &number_i); sum_till[i] = number_i + sum_till[i - 1]; } typedef vector v_long; vector maximum_sum_till(no_of_numbers + 1, v_long(no_of_intervals + 1, 0)); for(int interval_i = 1; interval_i <= no_of_intervals; interval_i++) { for(int number_i = max_interval_size; number_i <= no_of_numbers; number_i++) { int right = number_i, left = (number_i - max_interval_size) + 1; long long interval_ending_here_sum = sum_till[right] - sum_till[left - 1]; long long maximum_sum_with_interval_ending_here = maximum_sum_till[left - 1][interval_i - 1] + interval_ending_here_sum ; long long maximum_sum_with_interval_ending_before_here = maximum_sum_till[number_i - 1][interval_i]; maximum_sum_till[number_i][interval_i] = max(maximum_sum_with_interval_ending_here, maximum_sum_with_interval_ending_before_here); } } printf("%I64d\n", maximum_sum_till[no_of_numbers][no_of_intervals]); return 0; } ================================================ FILE: C Programs/C Programs 13/Godsend.cpp ================================================ #include int main() { int no_of_elements; scanf("%d", &no_of_elements); int only_even_numbers = true; for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); if(element_i%2 == 1) only_even_numbers = false; } printf(only_even_numbers ? "Second\n" : "First\n"); return 0; } ================================================ FILE: C Programs/C Programs 13/Ilya and Queries.cpp ================================================ #include #include #include using namespace std; #define MAX_LENGTH 100000 + 2 int main() { char string[MAX_LENGTH]; scanf("%s", string); int length = strlen(string); vector answer_till_here(length + 1, 0); for(unsigned int i = 0; string[i] != '\0'; i++) { answer_till_here[i] = (i == 0 ? 0 : answer_till_here[i - 1]); if(string[i] != '\0' && string[i] == string[i + 1]) answer_till_here[i]++; } int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int left_i, right_i; scanf("%d %d", &left_i, &right_i); left_i--, right_i--; //1-indexed int answer = (left_i == 0 ? answer_till_here[right_i - 1] : answer_till_here[right_i - 1] - answer_till_here[left_i - 1]); printf("%d\n", answer); } return 0; } ================================================ FILE: C Programs/C Programs 13/Kuriyama Mirai's Stones.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 1, 0); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &element[i]); sum_till[i] = element[i] + sum_till[i - 1]; } sort(all(element)); vector sorted_sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sorted_sum_till[i] = element[i] + sorted_sum_till[i - 1]; } int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int query_type, left, right; scanf("%d %d %d", &query_type, &left, &right); long long answer = (query_type == 1 ? sum_till[right] - sum_till[left - 1] : sorted_sum_till[right] - sorted_sum_till[left - 1]); printf("%I64d\n", answer); } return 0; } ================================================ FILE: C Programs/C Programs 13/Lights Out.cpp ================================================ #include #include using namespace std; #define toggle(x) (x = !x) int main() { typedef vector v_int; vector light_on(3 + 2, v_int(3 + 2, true)); for(int row = 1; row <= 3; row++) { for(int column = 1; column <= 3; column++) { int no_of_toggles; scanf("%d", &no_of_toggles); if(no_of_toggles%2 == 1) { toggle(light_on[row][column]); toggle(light_on[row][column - 1]); toggle(light_on[row][column + 1]); toggle(light_on[row + 1][column]); toggle(light_on[row - 1][column]); } } } for(int row = 1; row <= 3; row++) { for(int column = 1; column <= 3; column++) { if(light_on[row][column]) printf("1"); else printf("0"); } printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 13/Little Dima and Equation.cpp ================================================ #include #include using namespace std; long long int_power(int x, int n) { long long power = 1; for(int i = 1; i <= n; i++) { power *= x; } return power; } int sum_of_digits(int x) { const int base = 10; int digit_sum = 0; while(x > 0) { digit_sum += x%base; x = x/base; } return digit_sum; } int main() { int a, b, c; scanf("%d %d %d", &a, &b, &c); vector solutions; for(int digit_sum = 1; digit_sum <= 81; digit_sum++) { long long x = b*int_power(digit_sum, a) + c; if(sum_of_digits(x) == digit_sum && x > 0 && x < 1e9) solutions.push_back(x); } printf("%d\n", solutions.size()); for(unsigned int i = 0; i < solutions.size(); i++) printf("%d ", solutions[i]); return 0; } ================================================ FILE: C Programs/C Programs 13/Little Elephant and Bits.cpp ================================================ #include #define MAX_SIZE 100000 + 2 int main() { char number[MAX_SIZE]; scanf("%s", number); char new_number[MAX_SIZE]; int first_zero = -1, new_number_i = 0; for(int i = 0; number[i] != '\0'; i++) { if(number[i] == '0' && first_zero == -1)//Delete leftmost 0. { first_zero = i; } else { new_number[new_number_i++] = number[i]; } } int last_digit_position = new_number_i; if(first_zero == -1) //If no 0, delete any 1. last_digit_position--; new_number[last_digit_position] = '\0'; printf("%s\n", new_number); return 0; } ================================================ FILE: C Programs/C Programs 13/New Skateboard.cpp ================================================ #include #define MAX_LENGTH 300000 + 2 int main() { char calculator[MAX_LENGTH]; scanf("%s", calculator); long long no_of_multiples_of_4 = ( (calculator[0] - '0')%4 == 0); for(int i = 0; calculator[i + 1] != '\0'; i++) { int current_suffix = (calculator[i] - '0')*10 + (calculator[i + 1] - '0'); int no_of_strings_ending_with_this_suffix = i + 1; if(current_suffix%4 == 0) no_of_multiples_of_4 += no_of_strings_ending_with_this_suffix; no_of_multiples_of_4 += ( (calculator[i + 1] - '0')%4 == 0); } printf("%I64d\n", no_of_multiples_of_4); return 0; } ================================================ FILE: C Programs/C Programs 13/Oath of the Night's Watch.cpp ================================================ #include #include #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) using namespace std; int main() { const int oo = 1e9 + 1; int no_of_people, min_strength = oo, max_strength = 0; scanf("%d", &no_of_people); map strength_frequency; for(int i = 1; i <= no_of_people; i++) { int strength_i; scanf("%d", &strength_i); strength_frequency[strength_i]++; min_strength = min(strength_i, min_strength); max_strength = max(strength_i, max_strength); } int number_of_people_supported = max(0, no_of_people - strength_frequency[max_strength] - strength_frequency[min_strength]); printf("%d\n", number_of_people_supported); return 0; } ================================================ FILE: C Programs/C Programs 13/Sort the Array.cpp ================================================ #include #include using namespace std; int main() { int number_of_elements; scanf("%d", &number_of_elements); vector element(number_of_elements + 1); for(int i = 1; i <= number_of_elements; i++) scanf("%d", &element[i]); int descending_segments = 0, in_descending_segment = false, reversed_segment_fits = false; int segment_start = 1, segment_end = number_of_elements; for(int i = 2; i <= number_of_elements && descending_segments <= 1; i++) { if(in_descending_segment) { if(element[i] > element[i - 1]) { segment_end = i - 1; in_descending_segment = false; } } else { if(element[i] < element[i - 1]) { in_descending_segment = true; segment_start = i - 1; descending_segments++; } } } if(descending_segments == 0) segment_end = segment_start; if( (segment_end == number_of_elements || element[segment_start] <= element[segment_end + 1] ) && (segment_start == 1 || element[segment_end] >= element[segment_start - 1]) ) { reversed_segment_fits = true; } if(descending_segments <= 1 && reversed_segment_fits) printf("yes\n%d %d\n", segment_start, segment_end); else printf("no\n"); return 0; } ================================================ FILE: C Programs/C Programs 13/Star Sky.cpp ================================================ #include #define MAX_BRIGHTNESS 10 #define MAX_LENGTH 100 int main() { int no_of_stars, no_of_views, maximum_brightness; scanf("%d %d %d", &no_of_stars, &no_of_views, &maximum_brightness); int no_of_stars_of_initial_brightness_in[MAX_BRIGHTNESS + 1][MAX_LENGTH + 1][MAX_LENGTH + 1] = {{{0}}}; for(int star_i = 1; star_i <= no_of_stars; star_i++) { int brightness_i, x_i, y_i; scanf("%d %d %d", &x_i, &y_i, &brightness_i); no_of_stars_of_initial_brightness_in[brightness_i][x_i][y_i]++; } for(int brightness_i = 0; brightness_i <= maximum_brightness; brightness_i++) { for(int x_i = 1; x_i <= MAX_LENGTH; x_i++) { for(int y_i = 1; y_i <= MAX_LENGTH; y_i++) { no_of_stars_of_initial_brightness_in[brightness_i][x_i][y_i] += no_of_stars_of_initial_brightness_in[brightness_i][x_i][y_i - 1] + no_of_stars_of_initial_brightness_in[brightness_i][x_i - 1][y_i] - no_of_stars_of_initial_brightness_in[brightness_i][x_i - 1][y_i - 1]; } } } while(no_of_views--) { int time, x_1,y_1, x_2, y_2; scanf("%d %d %d %d %d", &time, &x_1, &y_1, &x_2, &y_2); int sum_of_brightness = 0; for(int brightness_i = 0; brightness_i <= maximum_brightness; brightness_i++) { int no_of_stars_of_this_brightness = no_of_stars_of_initial_brightness_in[brightness_i][x_2][y_2] - no_of_stars_of_initial_brightness_in[brightness_i][x_2][y_1 - 1] - no_of_stars_of_initial_brightness_in[brightness_i][x_1 - 1][y_2] + no_of_stars_of_initial_brightness_in[brightness_i][x_1 - 1][y_1 - 1]; int final_brightness = (brightness_i + time)%(maximum_brightness + 1); sum_of_brightness += no_of_stars_of_this_brightness*final_brightness; } printf("%d\n", sum_of_brightness); } return 0; } ================================================ FILE: C Programs/C Programs 13/Vanya and Books.cpp ================================================ #include int main() { int no_of_pages; scanf("%d", &no_of_pages); long long no_of_digits_used = 0; long long power_of_10 = 1; while(power_of_10 <= no_of_pages) { no_of_digits_used += no_of_pages - (power_of_10 - 1); power_of_10 *= 10; } printf("%I64d\n", no_of_digits_used); return 0; } ================================================ FILE: C Programs/C Programs 13/Vasya and Digital Root.cpp ================================================ #include int main() { int digital_root, no_of_digits; scanf("%d %d", &no_of_digits, &digital_root); if(digital_root == 0 && no_of_digits > 1) printf("No solution\n"); else { for(int i =no_of_digits; i >= 2; i--) printf("9"); printf("%d\n", digital_root); } return 0; } ================================================ FILE: C Programs/C Programs 14/Asphalting Roads.cpp ================================================ #include #include using namespace std; int main() { int no_of_roads; scanf("%d", &no_of_roads); const int MAX_ROADS = 50 + 1; vector horizontal_is_asphalted(MAX_ROADS, false); vector vertical_is_asphalted(MAX_ROADS, false); vector new_asphalt_applied_on_day; for(int day_i = 1; day_i <= no_of_roads*no_of_roads; day_i++) { int road_1, road_2; scanf("%d %d", &road_1, &road_2); if(!horizontal_is_asphalted[road_1] && !vertical_is_asphalted[road_2]) { horizontal_is_asphalted[road_1] = vertical_is_asphalted[road_2] = true; new_asphalt_applied_on_day.push_back(day_i); } } for(unsigned int i = 0; i < new_asphalt_applied_on_day.size(); i++) printf("%d ", new_asphalt_applied_on_day[i]); return 0; } ================================================ FILE: C Programs/C Programs 14/Bicycle Chain.cpp ================================================ #include #include using namespace std; int main() { int no_of_pedal_stars; scanf("%d", &no_of_pedal_stars); vector pedal_star(no_of_pedal_stars); for(int i = 0; i < no_of_pedal_stars; i++) scanf("%d", &pedal_star[i]); int no_of_wheel_stars; scanf("%d",&no_of_wheel_stars); vector wheel_star(no_of_wheel_stars); for(int i = 0; i < no_of_wheel_stars; i++) scanf("%d", &wheel_star[i]); int maximum_ratio = 0, no_of_maxima = 0; for(int i = 0; i < no_of_pedal_stars; i++) { for(int j = 0; j < no_of_wheel_stars; j++) { if(wheel_star[j]%pedal_star[i] == 0) { int this_ratio = wheel_star[j]/pedal_star[i]; if(this_ratio == maximum_ratio) { no_of_maxima++; } else if(this_ratio > maximum_ratio) { maximum_ratio = this_ratio, no_of_maxima = 1; } } } } printf("%d\n", no_of_maxima); return 0; } ================================================ FILE: C Programs/C Programs 14/Borze.cpp ================================================ #include #include using namespace std; int main() { string borze_code, translation; cin >> borze_code; for(unsigned int i = 0; i < borze_code.size(); i++) { if(borze_code[i] == '.') translation += '0'; else if(borze_code[i] == '-') { if(borze_code[i + 1] == '.') translation += '1'; else if(borze_code[i + 1] == '-') translation += '2'; i++; } } cout << translation; return 0; } ================================================ FILE: C Programs/C Programs 14/Building Permutation.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); sort(all(element)); long long no_of_moves = 0; for(int i = 0; i < no_of_elements; i++) no_of_moves += abs(element[i] - (i+1) ); printf("%I64d\n", no_of_moves); return 0; } ================================================ FILE: C Programs/C Programs 14/Chess Tourney.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_pairs; scanf("%d", &no_of_pairs); vector player_rating(2*no_of_pairs + 1, 0); for(int i = 1; i <= 2*no_of_pairs; i++) scanf("%d", &player_rating[i]); sort(all(player_rating)); printf(player_rating[no_of_pairs] < player_rating[no_of_pairs + 1] ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 14/Cormen - The Best Friend of Man.cpp ================================================ #include #include using namespace std; int main() { int no_of_days, minimum_walks_in_two_days; scanf("%d %d", &no_of_days, &minimum_walks_in_two_days); vector no_of_walks_on_day(no_of_days + 1); for(int i = 1; i <= no_of_days; i++) scanf("%d", &no_of_walks_on_day[i]); int no_of_additional_walks = 0; for(int i = 2; i <= no_of_days; i++) { int walks_in_last_two_days = no_of_walks_on_day[i] + no_of_walks_on_day[i - 1]; if(walks_in_last_two_days < minimum_walks_in_two_days) { int no_of_additional_walks_on_day_i = minimum_walks_in_two_days - walks_in_last_two_days; no_of_walks_on_day[i] += no_of_additional_walks_on_day_i; no_of_additional_walks += no_of_additional_walks_on_day_i; } } printf("%d\n", no_of_additional_walks); for(int i = 1; i <= no_of_days; i++) printf("%d ", no_of_walks_on_day[i]); return 0; } ================================================ FILE: C Programs/C Programs 14/DZY Loves Sequences.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 2); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector longest_increasing_to_left(no_of_elements + 2, 1); longest_increasing_to_left[1] = 0; for(int i = 3; i <= no_of_elements; i++) { if(element[i - 1] > element[i - 2]) longest_increasing_to_left[i] = longest_increasing_to_left[i - 1] + 1; } vector longest_increasing_to_right(no_of_elements + 2, 1); longest_increasing_to_right[no_of_elements] = 0; for(int i = no_of_elements - 2; i >= 0; i--) { if(element[i + 1] < element[i + 2]) longest_increasing_to_right[i] = longest_increasing_to_right[i + 1] + 1; } int longest_increasing_subsequence = 0; for(int i = 1; i <= no_of_elements; i++) { int length_by_changing_current_element = max(longest_increasing_to_left[i], longest_increasing_to_right[i]) + 1; if(i > 1 && i < no_of_elements) { if(element[i + 1] - element[i - 1] >= 2) { length_by_changing_current_element = longest_increasing_to_left[i] + longest_increasing_to_right[i] + 1; } } longest_increasing_subsequence = max(longest_increasing_subsequence, length_by_changing_current_element); } printf("%d\n", longest_increasing_subsequence); return 0; } ================================================ FILE: C Programs/C Programs 14/Dragons.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int strength, no_of_dragons; scanf("%d %d", &strength, &no_of_dragons); vector < pair > dragon(no_of_dragons); for(int i = 0; i < no_of_dragons; i++) scanf("%d %d", &dragon[i].first, &dragon[i].second); sort(all(dragon)); int can_defeat_all_dragons = true; for(int i = 0; i < no_of_dragons; i++) { int strength_of_dragon = dragon[i].first; int bonus = dragon[i].second; if(strength <= strength_of_dragon) { can_defeat_all_dragons = false; break; } else { strength += bonus; } } printf(can_defeat_all_dragons ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 14/Drazil and Factorial.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_digits; scanf("%d", &no_of_digits); vector number; for(int i = 1; i <= no_of_digits; i++) { int digit_i; scanf("%1d", &digit_i); switch(digit_i) { case 2: case 3: case 5: case 7: number.push_back(digit_i); break; case 4: number.push_back(2); number.push_back(2); number.push_back(3); break; case 6: number.push_back(3); number.push_back(5); break; case 8: number.push_back(2); number.push_back(2); number.push_back(2); number.push_back(7); break; case 9: number.push_back(2); number.push_back(3); number.push_back(3); number.push_back(7); break; } } sort(all(number)); for(int i = number.size() - 1; i >= 0; i--) printf("%d", number[i]); return 0; } ================================================ FILE: C Programs/C Programs 14/Football.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_lines; cin >> no_of_lines; map no_of_goals; while(no_of_lines--) { string team; cin >> team; no_of_goals[team]++; } string winner; int max_goals = 0; for(map :: iterator i = no_of_goals.begin(); i != no_of_goals.end(); i++) { int no_of_goals = i->second; if(no_of_goals > max_goals) { max_goals = no_of_goals; winner = i->first; } } cout << winner; return 0; } ================================================ FILE: C Programs/C Programs 14/Helpful Maths.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { string expression; cin >> expression; typedef unsigned int u_int; vector number; for(u_int i = 0; i < expression.size(); i++) { if(expression[i] != '+') number.push_back(expression[i]); } sort(all(number)); for(u_int i = 0; i < number.size() - 1; i++) { printf("%c+", number[i]); } printf("%c\n", number.back()); return 0; } ================================================ FILE: C Programs/C Programs 14/Increase and Decrease.cpp ================================================ #include int main() { int no_of_elements; scanf("%d", &no_of_elements); int sum = 0; for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); sum += element_i; } printf("%d\n", sum%no_of_elements == 0 ? no_of_elements : no_of_elements - 1); return 0; } ================================================ FILE: C Programs/C Programs 14/Jeff and Digits.cpp ================================================ #include int main() { int no_of_digits; scanf("%d", &no_of_digits); int no_of_5s = 0, no_of_0s = 0; for(int i = 1; i <= no_of_digits; i++) { int digit; scanf("%d", &digit); no_of_5s += (digit == 5); no_of_0s += (digit == 0); } if(no_of_0s == 0) { printf("-1\n"); } else if(no_of_5s < 9) { printf("0\n"); } else { int no_of_5s_in_number = (no_of_5s/9)*9; for(int i = 1; i <= no_of_5s_in_number; i++) printf("5"); for(int i = 1; i <= no_of_0s; i++) printf("0"); } return 0; } ================================================ FILE: C Programs/C Programs 14/Jzzhu and Children.cpp ================================================ #include int main() { int no_of_children, no_of_candies_given; scanf("%d %d", &no_of_children, &no_of_candies_given); int maximum_turns = 0, last_child = 0; for(int i = 1; i <= no_of_children; i++) { int candy_i; scanf("%d", &candy_i); int no_of_turns = candy_i/no_of_candies_given + (candy_i%no_of_candies_given != 0); if(no_of_turns >= maximum_turns) { maximum_turns = no_of_turns; last_child = i; } } printf("%d\n", last_child); return 0; } ================================================ FILE: C Programs/C Programs 14/Modulo Sum.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, modulo; scanf("%d %d", &no_of_elements, &modulo); typedef vector v_int; vector remainder_possible(modulo + 1, v_int(modulo, false)); int last_element = min(no_of_elements, modulo); for(int i = 1; i <= last_element; i++) { int element_i; scanf("%d", &element_i); for(int remainder = 0; remainder < modulo; remainder++) { if(remainder_possible[i - 1][remainder]) { int remainder_after_adding = (remainder + element_i)%modulo; remainder_possible[i][remainder_after_adding] = true; remainder_possible[i][remainder] = true; } } remainder_possible[i][element_i%modulo] = true; } printf(no_of_elements > modulo || remainder_possible[last_element][0] ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 14/Odds and Ends.cpp ================================================ #include int main() { int no_of_elements; scanf("%d", &no_of_elements); int first_or_last_element_even = false; for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); if(i == 1 || i == no_of_elements) if(element_i%2 == 0) first_or_last_element_even = true; } printf(no_of_elements%2 == 0 || first_or_last_element_even ? "No\n" : "Yes\n"); return 0; } ================================================ FILE: C Programs/C Programs 14/Panoramix's Prediction.cpp ================================================ #include int is_prime(int n) { for(int i = 2; i*i <= n; i++) if(n%i == 0) return false; return true; } int main() { int x, y; scanf("%d %d", &x, &y); int prime_in_middle = false; for(int i = x + 1; i < y; i++) { if(is_prime(i)) { prime_in_middle = true; break; } } printf(!prime_in_middle && is_prime(y) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 14/Permutation.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); const int limit = 5000; vector is_present(limit + 1, false); for(int i = 1; i <= n; i++) { int element_i; scanf("%d", &element_i); is_present[element_i] = true; } int no_of_changes = 0; for(int i = 1; i <= n; i++) no_of_changes += (!is_present[i]); printf("%d\n", no_of_changes); return 0; } ================================================ FILE: C Programs/C Programs 14/Powers of Two.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); set original_array; map frequency; for(int i = 0; i < no_of_elements; i++) { int element_i; scanf("%d", &element_i); frequency[element_i]++; original_array.insert(element_i); } long long no_of_pairs = 0; for(map :: iterator i = frequency.begin(); i != frequency.end(); i++) { int element_i = i->first; int frequency_i = i->second; for(int power = 0; power <= 31; power++) { int power_of_2 = (1 << power); int pair_element = power_of_2 - element_i; int pair_frequency = 0; if(pair_element > 0 && original_array.count(pair_element) == 1) pair_frequency = (element_i == pair_element ? frequency_i - 1 : frequency[pair_element]); no_of_pairs += frequency_i*1LL*pair_frequency; } } no_of_pairs = no_of_pairs/2; printf("%I64d\n", no_of_pairs); return 0; } ================================================ FILE: C Programs/C Programs 14/Queue at the School.cpp ================================================ #include #include using namespace std; int main() { int no_of_people, time; string school_queue; cin >> no_of_people >> time >> school_queue; for(int i = 1; i <= time; i++) { for(int person = 0; person < no_of_people; person++) { if(school_queue[person] == 'B' && school_queue[person + 1] == 'G') { swap(school_queue[person], school_queue[person + 1]); person++; } } } cout << school_queue; return 0; } ================================================ FILE: C Programs/C Programs 14/Rectangles.cpp ================================================ #include #include using namespace std; int main() { int no_of_rows, no_of_columns; scanf("%d %d", &no_of_rows, &no_of_columns); typedef vector v_int; vector rectangle(no_of_rows + 1, v_int(no_of_columns + 1)); long long no_of_sets = 0; for(int row = 1; row <= no_of_rows; row++) { int no_of_blacks_in_row = 0, no_of_whites_in_row = 0; for(int column = 1; column <= no_of_columns; column++) { scanf("%d", &rectangle[row][column]); no_of_blacks_in_row += (rectangle[row][column] == 1); } no_of_whites_in_row = no_of_columns - no_of_blacks_in_row; long long black_sets = (1LL << no_of_blacks_in_row) - 1; long long white_sets = (1LL << no_of_whites_in_row) - 1; no_of_sets += black_sets + white_sets; } for(int column = 1; column <= no_of_columns; column++) { int no_of_blacks_in_column = 0, no_of_whites_in_column = 0; for(int row = 1; row <= no_of_rows; row++) { no_of_blacks_in_column += (rectangle[row][column] == 1); } no_of_whites_in_column = no_of_rows - no_of_blacks_in_column; long long black_sets = (1LL << no_of_blacks_in_column) - 1; long long white_sets = (1LL << no_of_whites_in_column) - 1; no_of_sets += black_sets + white_sets; } no_of_sets -= (no_of_columns*no_of_rows); //Singleton sets counted twice printf("%I64d\n", no_of_sets); return 0; } ================================================ FILE: C Programs/C Programs 14/Supercentral Point.cpp ================================================ #include #include using namespace std; struct Point { int x, y; }; int main() { int no_of_points; scanf("%d", &no_of_points); vector vertex(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) scanf("%d %d", &vertex[i].x, &vertex[i].y); int no_of_supercentral_points = 0; for(int i = 1; i <= no_of_points; i++) { int upper = false, lower = false, right = false, left = false; for(int j = 1; j <= no_of_points; j++) { if(j != i) { if( (vertex[j].x == vertex[i].x) && (vertex[i].y > vertex[j].y) ) upper = true; if( (vertex[j].x == vertex[i].x) && (vertex[i].y < vertex[j].y) ) lower = true; if( (vertex[j].y == vertex[i].y) && (vertex[i].x > vertex[j].x) ) left = true; if( (vertex[j].y == vertex[i].y) && (vertex[i].x < vertex[j].x) ) right = true; } }//printf("Point %d\nUpper = %d, Lower = %d, left = %d, Right = %d\n", i, upper, lower, left, right); no_of_supercentral_points += (upper && lower && right && left); } printf("%d\n", no_of_supercentral_points); return 0; } ================================================ FILE: C Programs/C Programs 14/Tram.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { int no_of_stops; scanf("%d", &no_of_stops); int minimum_capacity = 0, no_of_people_on_train = 0; for(int i = 1; i <= no_of_stops; i++) { int no_of_entries, no_of_exits; scanf("%d %d",&no_of_exits, &no_of_entries); no_of_people_on_train += (no_of_entries - no_of_exits); minimum_capacity = max(minimum_capacity, no_of_people_on_train); } printf("%d\n", minimum_capacity); return 0; } ================================================ FILE: C Programs/C Programs 14/Ultra Fast Mathematician.cpp ================================================ #include #include using namespace std; int main() { string num_1, num_2, answer; cin >> num_1 >> num_2; typedef unsigned int u_int; for(u_int i = 0; i < num_1.size(); i++) { answer += (num_1[i] == num_2[i] ? '0' : '1'); } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 14/Vasya and String.cpp ================================================ #include #define max(a, b) (a > b ? a : b) #define MAX_LENGTH 100000 + 2 int get_max_window_length(char string[], char changed_char, int max_changes) { int max_window_length = 0, window_length = 0, no_of_changes = 0; for(int window_end = 0, window_start = 0; string[window_end] != '\0'; window_end++) { no_of_changes += (string[window_end] == changed_char); while(no_of_changes > max_changes) { no_of_changes -= (string[window_start++] == changed_char); } window_length = window_end - (window_start - 1); max_window_length = max(max_window_length, window_length); } return max_window_length; } int main() { int length, max_changes; char string[MAX_LENGTH]; scanf("%d %d %s", &length, &max_changes, string); int beauty = max(get_max_window_length(string, 'a', max_changes), get_max_window_length(string, 'b', max_changes)); printf("%d\n", beauty); return 0; } ================================================ FILE: C Programs/C Programs 15/Army.cpp ================================================ #include #include using namespace std; int main() { int no_of_ranks; scanf("%d", &no_of_ranks); vector no_of_days_to_reach(no_of_ranks + 1, 0); for(int rank_i = 2; rank_i <= no_of_ranks; rank_i++) { int day_i; scanf("%d", &day_i); no_of_days_to_reach[rank_i] = no_of_days_to_reach[rank_i - 1] + day_i; } int starting_rank, ending_rank; scanf("%d %d", &starting_rank, &ending_rank); printf("%d\n", no_of_days_to_reach[ending_rank] - no_of_days_to_reach[starting_rank]); return 0; } ================================================ FILE: C Programs/C Programs 15/Between the Offices.cpp ================================================ #include int main() { int no_of_days; const int MAX_DAYS = 102; char flights[MAX_DAYS]; scanf("%d %s", &no_of_days, flights); int flights_from_seattle = 0, flights_to_seattle = 0; for(int i = 1; i < no_of_days; i++) { flights_to_seattle += (flights[i - 1] == 'F' && flights[i] == 'S'); flights_from_seattle += (flights[i - 1] == 'S' && flights[i] == 'F'); } printf("%s\n", flights_from_seattle > flights_to_seattle ? "YES" : "NO"); return 0; } ================================================ FILE: C Programs/C Programs 15/Cableway.cpp ================================================ #include int main() { int red, blue, green; scanf("%d %d %d", &red, &green, &blue); int red_rides = red/2 + red%2; int blue_rides = blue/2 + blue%2; int green_rides = green/2 + green%2; const int ONE_RIDE_DURATION = 30; int no_of_minutes, last_ride_arrival; if(red_rides > blue_rides && red_rides > green_rides) { last_ride_arrival = 3*(red_rides - 1); no_of_minutes = last_ride_arrival + ONE_RIDE_DURATION; } else if(green_rides >= red_rides && green_rides > blue_rides) { last_ride_arrival = 3*(green_rides - 1) + 1; no_of_minutes = last_ride_arrival + ONE_RIDE_DURATION; } else if(blue_rides >= red_rides && blue_rides >= green_rides) { last_ride_arrival = 3*(blue_rides - 1) + 2; no_of_minutes = last_ride_arrival + ONE_RIDE_DURATION; } printf("%d\n", no_of_minutes); return 0; } ================================================ FILE: C Programs/C Programs 15/Ciferia.cpp ================================================ #include int main() { int k, n; scanf("%d %d", &k, &n); int power = 0; while(n%k == 0) { n = n/k; power++; } printf(n > 1 ? "NO\n" : "YES\n%d\n", power - 1); return 0; } ================================================ FILE: C Programs/C Programs 15/Coins.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); vector denominations; denominations.push_back(n); for(int i = 2; n > 1; i++) { while(n%i == 0) { n = n/i; denominations.push_back(n); } } for(int i = 0; i < denominations.size(); i++) printf("%d ", denominations[i]); return 0; } ================================================ FILE: C Programs/C Programs 15/Divisibility by Eight.cpp ================================================ #include #include #include #define MAX_DIGITS 100 + 2 using namespace std; int main() { string number; cin >> number; int found = false; int answer; typedef unsigned int u_int; for(u_int i = 0; i < number.size() && !found; i++) { if(number[i] == '8' || number[i] == '0') found = true, answer = number[i] - '0'; } for(u_int i = 0; i < number.size() && !found; i++) { for(u_int j = i + 1; j < number.size() && !found; j++) { int first_digit = number[i] - '0', second_digit = number[j] - '0'; int number_formed = 10*first_digit + second_digit; if(number_formed%8 == 0) found = true, answer = number_formed; } } for(u_int i = 0; i < number.size() && !found; i++) { for(u_int j = i + 1; j < number.size() && !found; j++) { for(u_int k = j + 1; k < number.size() && !found; k++) { int first_digit = number[i] - '0', second_digit = number[j]- '0', third_digit = number[k] - '0'; int number_formed = 100*first_digit + 10*second_digit + third_digit; if(number_formed%8 == 0) { answer = number_formed; found = true; } } } } if(found) printf("YES\n%d\n", answer); else printf("NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 15/Exams.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_exams; scanf("%d", &no_of_exams); vector < pair > exam_day(no_of_exams + 1); for(int i = 1; i <= no_of_exams; i++) { scanf("%d %d", &exam_day[i].first, &exam_day[i].second); } sort(all(exam_day)); int last_day = 0; for(int i = 1; i <= no_of_exams;i++) { int choice_1 = exam_day[i].first, choice_2 = exam_day[i].second; if(choice_1 >= last_day && choice_2 >= last_day) last_day = min(choice_1, choice_2); else if(choice_1 >= last_day) last_day = choice_1; else if(choice_2 >= last_day) last_day = choice_2; } printf("%d\n", last_day); return 0; } ================================================ FILE: C Programs/C Programs 15/Given Length and Sum of Digits.cpp ================================================ #include #include using namespace std; int main() { int sum, no_of_digits; scanf("%d %d", &no_of_digits, &sum); if(sum == 0 && no_of_digits == 1) { printf("0 0\n"); return 0; } else if(sum == 0 || sum > 9*no_of_digits) { printf("-1 -1\n"); return 0; } vector minimum_number(no_of_digits + 1, 0); int remaining_sum = sum - 1, i; for(i = no_of_digits; i > 0 && remaining_sum > 0; i--) { if(remaining_sum >= 9) { minimum_number[i] = 9; remaining_sum -= 9; } else { minimum_number[i] = remaining_sum; remaining_sum = 0; } } minimum_number[1] = (minimum_number[1] == 0 ? 1 : minimum_number[1] + 1); vector maximum_number(no_of_digits + 1, 0); remaining_sum = sum; for(i = 1; i <= no_of_digits && remaining_sum > 0; i++) { if(remaining_sum >= 9) { maximum_number[i] = 9; remaining_sum -= 9; } else { maximum_number[i] = remaining_sum; remaining_sum = 0; } } for(int i = 1; i <= no_of_digits; i++) printf("%d", minimum_number[i]); printf(" "); for(int i = 1; i <= no_of_digits; i++) printf("%d", maximum_number[i]); return 0; } ================================================ FILE: C Programs/C Programs 15/Ilya and Sticks.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_sticks; scanf("%d", &no_of_sticks); vector length(no_of_sticks); for(int i = 0; i < no_of_sticks; i++) scanf("%d", &length[i]); sort(all(length)); int side_1 = 0, side_2 = 0; long long area = 0; for(int i = no_of_sticks - 1; i - 1 >= 0; i--) { if(length[i] - length[i - 1] <= 1) { if(side_1 == 0) { side_1 = length[i - 1]; } else if(side_2 == 0) { side_2 = length[i - 1]; area += side_1*1LL*side_2; side_1 = side_2 = 0; } i--; } } printf("%I64d\n", area); return 0; } ================================================ FILE: C Programs/C Programs 15/Inna and Huge Candy Matrix.cpp ================================================ #include inline void swap(int &a, int &b) { a = a^b; b = b^a; a = a^b; } inline void horizontal_rotate(int &column, int no_of_columns) { column = no_of_columns + 1 - column; } inline void clockwise_transformation(int &row, int &column, int &no_of_rows, int &no_of_columns) { int current_column = column, current_row = row; row = current_column; column = no_of_rows + 1 - current_row; swap(no_of_columns, no_of_rows); } inline void anti_clockwise_transformation(int &row, int &column, int &no_of_rows, int &no_of_columns) { int current_row = row, current_column = column; column = current_row; row = no_of_columns + 1 - current_column; swap(no_of_columns, no_of_rows); } int main() { int original_no_of_rows, original_no_of_columns, clockwise, horizontal, anti_clockwise, no_of_points; scanf("%d %d %d %d %d %d", &original_no_of_rows, &original_no_of_columns, &clockwise, &horizontal, &anti_clockwise, &no_of_points); clockwise %= 4; horizontal %= 2; anti_clockwise %= 4; while(no_of_points--) { int no_of_rows = original_no_of_rows; int no_of_columns = original_no_of_columns; int row, column; scanf("%d %d", &row, &column); for(int i = 1; i <= clockwise; i++) clockwise_transformation(row, column, no_of_rows, no_of_columns); //printf("%d %d\n", row, column); for(int i = 1; i <= horizontal; i++) horizontal_rotate(column, no_of_columns); //printf("%d %d\n", row, column); for(int i = 1; i <= anti_clockwise; i++) anti_clockwise_transformation(row, column, no_of_rows, no_of_columns); //printf("%d %d\n", row, column); printf("%d %d\n", row, column); } return 0; } ================================================ FILE: C Programs/C Programs 15/K-Multiple Free Set.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, k; scanf("%d %d", &no_of_elements, &k); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); sort(all(element)); int set_size = 0; vector crossed_out(no_of_elements, false); for(int i = 0; i < no_of_elements; i++) { if(!crossed_out[i]) { set_size++; if(binary_search(all(element), k*1LL*element[i])) { int index = lower_bound(all(element), k*1LL*element[i]) - element.begin(); crossed_out[index] = true; } } } printf("%d\n", set_size); return 0; } ================================================ FILE: C Programs/C Programs 15/Kefa and Park.cpp ================================================ #include #include using namespace std; const int MAX_VERTICES = 2e5 + 1; int visited[MAX_VERTICES] = {false}; int has_cat[MAX_VERTICES] = {false}; int no_of_consecutive_cats_till[MAX_VERTICES] = {0}; vector tree[MAX_VERTICES]; int max_cats; void dfs(int current_park, int &no_of_paths) { if(tree[current_park].size() == 1 && visited[tree[current_park][0]]) no_of_paths++; for(int i = 0; i < tree[current_park].size(); i++) { int next_park = tree[current_park][i]; if(!visited[next_park]) { visited[next_park] = true; no_of_consecutive_cats_till[next_park] = (has_cat[next_park] ? no_of_consecutive_cats_till[current_park] + 1 : 0); if(no_of_consecutive_cats_till[next_park] <= max_cats) dfs(next_park, no_of_paths); } } } int main() { int no_of_vertices; scanf("%d %d", &no_of_vertices, &max_cats); for(int i = 1; i <= no_of_vertices; i++) scanf("%d", &has_cat[i]); for(int i = 1; i <= no_of_vertices - 1; i++) { int x, y; scanf("%d %d", &x, &y); tree[x].push_back(y); tree[y].push_back(x); } no_of_consecutive_cats_till[1] = has_cat[1]; visited[1] = true; int no_of_paths = 0; dfs(1, no_of_paths); printf("%d\n", no_of_paths); return 0; } ================================================ FILE: C Programs/C Programs 15/Mahmoud and Ehab and the MEX.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, x; scanf("%d %d", &no_of_elements, &x); const int MAX = 101; vector frequency(MAX, 0); for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); frequency[element_i]++; } int no_of_missing_elements_before_x = 0; int x_present = frequency[x]; for(int i = 0; i < x; i++) { no_of_missing_elements_before_x += (frequency[i] == 0); } printf("%d\n", no_of_missing_elements_before_x + x_present); return 0; } ================================================ FILE: C Programs/C Programs 15/Mahmoud and Ehab and the bipartiteness.cpp ================================================ #include #include using namespace std; const int BLACK = 0, WHITE = 1, NO_OF_COLOURS = 2, MAX_VERTICES = 1e5 + 1; vector tree[MAX_VERTICES]; int visited[MAX_VERTICES] = {false}; int no_of_elements[NO_OF_COLOURS] = {0}; void dfs_and_colour(int v, int current_colour) { int next_colour = (current_colour + 1)%2; if(!visited[v]) { no_of_elements[current_colour]++; visited[v] = true; for(int i = 0; i < tree[v].size(); i++) dfs_and_colour(tree[v][i], next_colour); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int edge = 1; edge <= no_of_vertices - 1; edge++) { int x, y; scanf("%d %d", &x, &y); tree[x].push_back(y); tree[y].push_back(x); } dfs_and_colour(1, BLACK); printf("%I64d\n", no_of_elements[BLACK]*1LL*no_of_elements[WHITE] - (no_of_vertices - 1)); return 0; } ================================================ FILE: C Programs/C Programs 15/Mahmoud and Ehab and the xor.cpp ================================================ #include int main() { int no_of_numbers, x; scanf("%d %d", &no_of_numbers, &x); if(no_of_numbers == 1) { printf("YES\n%d\n", x); } else if(no_of_numbers == 2) { if(x == 0) printf("NO\n"); else printf("YES\n0 %d\n", x); } else { const int POWER_2 = 1 << 19, PREVIOUS_POWER_2 = 1 << 18; int bitwise_xor = 0; printf("YES\n"); for(int i = 1; i <= no_of_numbers - 3; i++) { bitwise_xor ^= i; printf("%d ", i); } if(bitwise_xor == x) printf("%d %d %d\n", POWER_2, PREVIOUS_POWER_2, (POWER_2|PREVIOUS_POWER_2)); else printf("%d %d %d\n", PREVIOUS_POWER_2, (POWER_2^bitwise_xor^x), (POWER_2|PREVIOUS_POWER_2)); } return 0; } ================================================ FILE: C Programs/C Programs 15/Number of Ways.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); sum_till[i] = sum_till[i - 1] + element_i; } vector sum_from(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_from[i] = sum_till[no_of_elements] - sum_till[i - 1]; } long long no_of_ways = 0, total_sum = sum_till[no_of_elements]; if(total_sum%3 != 0) { printf("%I64d\n", no_of_ways); return 0; } vector no_of_places_that_sum_to_a_third_from(no_of_elements + 2, 0); for(int i = no_of_elements; i >= 1; i--) { no_of_places_that_sum_to_a_third_from[i] = no_of_places_that_sum_to_a_third_from[i + 1] + (3*sum_from[i] == total_sum); } for(int i = 1; i <= no_of_elements - 2; i++) { if(3*sum_till[i] == total_sum) { no_of_ways += no_of_places_that_sum_to_a_third_from[i + 2]; } } printf("%I64d\n", no_of_ways); return 0; } ================================================ FILE: C Programs/C Programs 15/Pearls in a Row.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_pearls; scanf("%d", &no_of_pearls); set current_segment_pearls; vector > segment; int left = 1; for(int right = 1; right <= no_of_pearls; right++) { int pearl_type; scanf("%d", &pearl_type); if(current_segment_pearls.count(pearl_type) == 1) { segment.push_back(make_pair(left, right)); current_segment_pearls.clear(); left = right + 1; } else { current_segment_pearls.insert(pearl_type); } } if(segment.size() == 0) printf("-1\n"); else { segment.back().second = max(segment.back().second, no_of_pearls); printf("%u\n", segment.size()); for(int i = 0; i < segment.size(); i++) printf("%d %d\n", segment[i].first, segment[i].second); } return 0; } ================================================ FILE: C Programs/C Programs 15/Pie Rules.cpp ================================================ #include #include using namespace std; int main() { int no_of_pieces; scanf("%d", &no_of_pieces); vector pie(no_of_pieces + 1); for(int i = 1; i <= no_of_pieces; i++) scanf("%d", &pie[i]); vector sum_from(no_of_pieces + 3, 0); const int NO_OF_PLAYERS = 2, ALICE = 0, BOB = 1; int maximum_from[no_of_pieces + 1][NO_OF_PLAYERS]; for(int i = no_of_pieces; i >= 1; i--) { sum_from[i] = sum_from[i + 1] + pie[i]; if(i == no_of_pieces) { maximum_from[i][ALICE] = maximum_from[i][BOB] = pie[i]; } else { maximum_from[i][ALICE] = max(maximum_from[i + 1][ALICE], pie[i] + sum_from[i + 1] - maximum_from[i + 1][BOB]); maximum_from[i][BOB] = max(maximum_from[i + 1][BOB], pie[i] + sum_from[i + 1] - maximum_from[i + 1][BOB]); } } int maximum_for_alice = sum_from[1] - maximum_from[1][BOB]; printf("%d %d\n", maximum_for_alice, maximum_from[1][BOB]); return 0; } ================================================ FILE: C Programs/C Programs 15/Quasi-palindrome.cpp ================================================ #include int is_palindrome(int n) { int reverse_n = 0, original_n = n; while(n > 0) { reverse_n = reverse_n*10 + n%10; n = n/10; } return (reverse_n == original_n); } int palindrome_without_trailing_zeroes(int n) { while(n%10 == 0) n = n/10; return is_palindrome(n); } int main() { int n; scanf("%d", &n); printf("%s\n", palindrome_without_trailing_zeroes(n) ? "YES" : "NO"); return 0; } ================================================ FILE: C Programs/C Programs 15/Soldier and Number Game.cpp ================================================ #include #include using namespace std; void precompute(vector &no_of_prime_divisors_till, int LIMIT) { vector largest_prime_factor(LIMIT, 0); vector no_of_prime_divisors(LIMIT, 0); for(int i = 2; i < LIMIT; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple < LIMIT; multiple += i) largest_prime_factor[multiple] = i; } int p = largest_prime_factor[i]; no_of_prime_divisors[i] = 1 + no_of_prime_divisors[i/p]; no_of_prime_divisors_till[i] += no_of_prime_divisors[i] + no_of_prime_divisors_till[i - 1]; } } int main() { const int LIMIT = 5e6 + 1; vector no_of_prime_divisors_till(LIMIT, 0); precompute(no_of_prime_divisors_till, LIMIT); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int left, right; scanf("%d %d", &right, &left); printf("%d\n", no_of_prime_divisors_till[right] - no_of_prime_divisors_till[left]); } return 0; } ================================================ FILE: C Programs/C Programs 15/Tanya and Toys.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_toys, money; scanf("%d %d", &no_of_toys, &money); set toy_type; for(int i = 1; i <= no_of_toys; i++) { int toy_i; scanf("%d", &toy_i); toy_type.insert(toy_i); } vector new_toys; for(int toy = 1; money >= toy; toy++) { if(toy_type.count(toy) == 0) { new_toys.push_back(toy); money -= toy; } } printf("%u\n", new_toys.size()); for(int i = 0; i < new_toys.size(); i++) printf("%d ", new_toys[i]); return 0; } ================================================ FILE: C Programs/C Programs 15/Team.cpp ================================================ #include int main() { int no_of_1s, no_of_0s; scanf("%d %d", &no_of_0s, &no_of_1s); if(no_of_1s > 2*(no_of_0s + 1) || no_of_0s > no_of_1s + 1) { printf("-1\n"); return 0; } while(no_of_0s > 0 && no_of_1s > 0) { if(no_of_1s > no_of_0s) { printf("110"); no_of_1s -= 2, no_of_0s--; } else if(no_of_1s == no_of_0s) { printf("10"); no_of_0s--, no_of_1s--; } else if(no_of_1s < no_of_0s) { printf("01"); no_of_0s--, no_of_1s--; } } for(int i = 1; i <= no_of_0s; i++) printf("0"); for(int i = 1; i <= no_of_1s; i++) printf("1"); return 0; } ================================================ FILE: C Programs/C Programs 15/The Eternal Immortality.cpp ================================================ #include typedef long long LL; int main() { LL a, b; scanf("%I64d %I64d", &a, &b); int answer = 1; if(b - a < 5) { for(LL i = a + 1; i <= b; i++) answer = answer*(i%10); answer %= 10; } else { answer = 0; } printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 15/Triangle.cpp ================================================ #include int triangle(int side_a, int side_b, int side_c) { return ( (side_a + side_b > side_c) && (side_b + side_c > side_a) && (side_c + side_a > side_b) ); } int segment(int side_a, int side_b, int side_c) { return ( (side_a + side_b == side_c) || (side_b + side_c == side_a) || (side_c + side_a == side_b) ); } int main() { int side_a, side_b, side_c, side_d; scanf("%d %d %d %d", &side_a, &side_b, &side_c, &side_d); if(triangle(side_a, side_b, side_c) || triangle(side_b, side_c, side_d) || triangle(side_c, side_d, side_a) || triangle(side_b, side_a, side_d) ) printf("TRIANGLE\n"); else if(segment(side_a, side_b, side_c) || segment(side_b, side_c, side_d) || segment(side_c, side_d, side_a) || segment(side_b, side_a, side_d) ) printf("SEGMENT\n"); else printf("IMPOSSIBLE\n"); return 0; } ================================================ FILE: C Programs/C Programs 15/USB Flash Drives.cpp ================================================ #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() int main() { int no_of_drives, file_size; scanf("%d %d", &no_of_drives, &file_size); vector capacity(no_of_drives); for(int i = 0; i < no_of_drives; i++) scanf("%d", &capacity[i]); sort(all(capacity)); int no_of_drives_used = 0; for(int drive_i = no_of_drives - 1; file_size > 0 && drive_i >= 0; drive_i--, no_of_drives_used++) file_size -= capacity[drive_i]; printf("%d\n", no_of_drives_used); return 0; } ================================================ FILE: C Programs/C Programs 16/Amusing Joke.cpp ================================================ #include int main() { const int NO_OF_ALPHABETS = 26; int frequency[NO_OF_ALPHABETS] = {0}; for(int i = 1; i <= 3; i++) { const int MAX_LENGTH = 103; char name[MAX_LENGTH]; scanf("%s", name); for(int j = 0; name[j] != '\0'; j++) frequency[name[j] - 'A'] += (i == 3 ? -1 : 1); } int is_possible = true; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(frequency[i] != 0) is_possible = false; printf(is_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 16/Anton and Letters.cpp ================================================ #include #include #include #define is_alpha(x) ('a' <= x && x <= 'z') using namespace std; int main() { string line; getline(cin, line); set letters; for(int i = 0; i < line.size(); i++) { if(is_alpha(line[i])) letters.insert(line[i]); } cout << letters.size(); return 0; } ================================================ FILE: C Programs/C Programs 16/Cards with Numbers.cpp ================================================ #include #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() struct card { int index, value; }; bool sort_by_value(const card &A, const card &B) { return (A.value < B.value); } int main() { FILE *input = fopen("input.txt", "r"); int no_of_cards; fscanf(input, "%d", &no_of_cards); vector cards(2*no_of_cards); for(int i = 0; i < 2*no_of_cards; i++) { fscanf(input, "%d", &cards[i].value); cards[i].index = i + 1; } sort(all(cards), sort_by_value); FILE *output = fopen("output.txt", "w"); vector > solution; for(int i = 0; i < 2*no_of_cards; i += 2) { if(cards[i].value == cards[i + 1].value) solution.push_back(make_pair(cards[i].index, cards[i + 1].index)); else { fprintf(output, "-1\n"); return 0; } } for(int i = 0; i < no_of_cards; i++) fprintf(output, "%d %d\n", solution[i].first, solution[i].second); fclose(input); fclose(output); return 0; } ================================================ FILE: C Programs/C Programs 16/Classroom Watch.cpp ================================================ #include #include using namespace std; int digit_sum(int n) { int sum = 0; while(n > 0) { sum += n%10; n = n/10; } return sum; } int main() { int n; scanf("%d", &n); const int MAX_DIGIT_SUM = 81; int x = max(0, n - MAX_DIGIT_SUM); vector answer; while(x <= n) { if(x + digit_sum(x) == n) answer.push_back(x); x++; } printf("%d\n", answer.size()); for(int i = 0; i < answer.size(); i++) printf("%d ", answer[i]); return 0; } ================================================ FILE: C Programs/C Programs 16/Cupboards.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { const int OPEN = 1, CLOSED = 0; int no_of_cupboards; scanf("%d", &no_of_cupboards); int left_open_doors = 0, left_closed_doors = 0; int right_open_doors = 0, right_closed_doors = 0; while(no_of_cupboards--) { int left, right; scanf("%d %d", &left, &right); left_open_doors += (left == OPEN); left_closed_doors += (left == CLOSED); right_open_doors += (right == OPEN); right_closed_doors += (right == CLOSED); } int minimum_left_operations = min(left_closed_doors, left_open_doors); int minimum_right_operations = min(right_open_doors, right_closed_doors); printf("%d\n", minimum_left_operations + minimum_right_operations); return 0; } ================================================ FILE: C Programs/C Programs 16/Dishonest Sellers.cpp ================================================ #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() struct prices { int now, discount, difference; }; bool sort_By_Difference(const prices &A, const prices &B) { return (A.difference < B.difference); } int main() { int no_of_days, minimum_now_buys; scanf("%d %d", &no_of_days, &minimum_now_buys); vector price(no_of_days); for(int i = 0; i < no_of_days; i++) scanf("%d", &price[i].now); for(int i = 0; i < no_of_days; i++) scanf("%d", &price[i].discount); for(int i = 0; i < no_of_days; i++) price[i].difference = price[i].now - price[i].discount; sort(all(price), sort_By_Difference); int money_used = 0; for(int i = 0; i < no_of_days; i++) { if(i < minimum_now_buys) money_used += price[i].now; else money_used += min(price[i].now, price[i].discount); } printf("%d\n", money_used); return 0; } ================================================ FILE: C Programs/C Programs 16/Dubstep.cpp ================================================ #include #include using namespace std; int main() { string song; cin >> song; string word; for(int i = 0; i < song.length(); i++) { if(i + 2 < song.length() && song[i] == 'W' && song[i + 1] == 'U' && song[i + 2] == 'B') { i += 2; if(!word.empty()) { cout << word << " "; word.clear(); } } else { word += song[i]; } } if(!word.empty()) cout << word << " "; return 0; } ================================================ FILE: C Programs/C Programs 16/Easy Number Challenge.cpp ================================================ #include #include using namespace std; void precompute(vector &number_of_divisors, int LIMIT) { number_of_divisors[1] = 1; vector largest_prime_factor(LIMIT + 1, 0); for(int i = 2; i <= LIMIT; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple <= LIMIT; multiple += i) largest_prime_factor[multiple] = i; } int exponent = 0; int reduced_i = i; while(reduced_i%largest_prime_factor[i] == 0) { reduced_i /= largest_prime_factor[i]; exponent++; } number_of_divisors[i] = (exponent + 1)*number_of_divisors[reduced_i]; } } int main() { const int LIMIT = 1e6; vector number_of_divisors(LIMIT + 1, 0); precompute(number_of_divisors, LIMIT); int a, b, c; scanf("%d %d %d", &a, &b, &c); int sum = 0; for(int i = 1; i <= a; i++) { for(int j = 1; j <= b; j++) { for(int k = 1; k <= c; k++) { sum += number_of_divisors[i*j*k]; } } } printf("%d\n", sum); return 0; } ================================================ FILE: C Programs/C Programs 16/Fox and Snake.cpp ================================================ #include int main() { int rows, columns; scanf("%d %d", &rows, &columns); for(int i = 1; i <= rows; i++) { int different_cell = -1; char default_char = (i%2 == 0 ? '.' : '#'); if(i%2 == 0) different_cell = (i%4 == 0 ? 1 : columns); for(int j = 1; j <= columns; j++) printf("%c", (j != different_cell ? default_char : '#')); printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 16/Greg and Array.cpp ================================================ #include #include using namespace std; struct operation { int left, right, value; }; int main() { int no_of_elements, no_of_operations, no_of_queries; scanf("%d %d %d", &no_of_elements, &no_of_operations, &no_of_queries); vector element(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &element[i]); vector operations(no_of_operations + 1); for(int i = 1; i <= no_of_operations; i++) scanf("%d %d %d", &operations[i].left, &operations[i].right, &operations[i].value); vector no_of_operations_starting(no_of_operations + 2, 0); while(no_of_queries--) { int left_operation, right_operation; scanf("%d %d", &left_operation, &right_operation); no_of_operations_starting[left_operation]++; no_of_operations_starting[right_operation + 1]--; } vector no_of_uses(no_of_operations + 1, 0); for(int i = 1; i <= no_of_operations; i++) no_of_uses[i] = no_of_uses[i - 1] + no_of_operations_starting[i]; vector no_of_updates_starting(no_of_elements + 2, 0); for(int i = 1; i <= no_of_operations; i++) { int start_point = operations[i].left, end_point = operations[i].right, d = operations[i].value; no_of_updates_starting[start_point] += no_of_uses[i]*1LL*d; no_of_updates_starting[end_point + 1]-= no_of_uses[i]*1LL*d; } vector amount_to_be_added(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) amount_to_be_added[i] = amount_to_be_added[i - 1] + no_of_updates_starting[i]; for(int i = 1; i <= no_of_elements; i++) element[i] += amount_to_be_added[i]; for(int i = 1; i <= no_of_elements; i++) printf("%I64d ", element[i]); return 0; } ================================================ FILE: C Programs/C Programs 16/Hacking Cypher.cpp ================================================ #include #include #include #include using namespace std; int main() { int a, b; string number; cin >> number >> a >> b; int no_of_numbers = number.size(); vector remainder_a_till(no_of_numbers); remainder_a_till[0] = (number[0] - '0')%a; for(int i = 1 ; number[i] != '\0'; i++) { remainder_a_till[i] = (10*remainder_a_till[i - 1] + number[i] - '0')%a; } vector remainder_b_from(no_of_numbers); remainder_b_from[no_of_numbers - 1] = (number[no_of_numbers - 1] - '0')%b; for(int i = no_of_numbers - 2, ten_power = 10; i >= 0; i--) { remainder_b_from[i] = (ten_power*(number[i] - '0') + remainder_b_from[i + 1])%b; ten_power = (ten_power*10)%b; } int end_of_a = -1; for(int i = 0; i + 1 < no_of_numbers; i++) { if(remainder_a_till[i] == 0 && remainder_b_from[i + 1] == 0 && number[i + 1] != '0') end_of_a = i; } if(end_of_a == -1 || number[0] == '0') { printf("NO\n"); return 0; } printf("YES\n"); for(int i = 0; i <= end_of_a; i++) printf("%c", number[i]); printf("\n"); for(int i = end_of_a + 1; i < no_of_numbers; i++) printf("%c", number[i]); return 0; } ================================================ FILE: C Programs/C Programs 16/I Wanna Be The Guy.cpp ================================================ #include int main() { int no_of_levels; scanf("%d", &no_of_levels); int crossed_levels[no_of_levels + 1] = {false}; int x_levels; scanf("%d", &x_levels); while(x_levels--) { int level; scanf("%d", &level); crossed_levels[level] = true; } int y_levels; scanf("%d", &y_levels); while(y_levels--) { int level; scanf("%d", &level); crossed_levels[level] = true; } int possible = true; for(int i = 1; i <= no_of_levels; i++) if(!crossed_levels[i]) possible = false; printf(possible ? "I become the guy." : "Oh, my keyboard!"); return 0; } ================================================ FILE: C Programs/C Programs 16/IQ Test.cpp ================================================ #include int possible_to_make_square(char square[][5], int x, int y) { int black = (square[x][y] == '#') + (square[x - 1][y] == '#') + (square[x - 1][y - 1] == '#') + (square[x][y - 1] == '#'); int white = (square[x][y] == '.') + (square[x - 1][y] == '.') + (square[x - 1][y - 1] == '.') + (square[x][y - 1] == '.'); return (black >= 3 || white >= 3); } int main() { const int N = 4; char square[N + 1][N + 1]; for(int i = 0; i < N; i++) scanf("%s", square[i]); int is_possible = false; for(int i = 1; i < 4; i++) { for(int j = 1; j < 4; j++) { if(possible_to_make_square(square, i, j)) is_possible = true; } } printf(is_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 16/Jeff and Periods.cpp ================================================ #include const int NOT_POSSIBLE = -1, MAX_ELEMENTS = 1e5 + 1; struct number { int last_index, second_last_index, difference; number(){ last_index = second_last_index = 0; difference = NOT_POSSIBLE;} }; int main() { number elements[MAX_ELEMENTS]; int no_of_elements; scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) { int n; scanf("%d", &n); if(elements[n].last_index == 0) { elements[n].last_index = i; elements[n].difference = 0; } else if(elements[n].second_last_index == 0) { elements[n].second_last_index = elements[n].last_index; elements[n].last_index = i; elements[n].difference = elements[n].last_index - elements[n].second_last_index; } else { if(i - elements[n].last_index == elements[n].difference) { elements[n].second_last_index = elements[n].last_index; elements[n].last_index = i; } else { elements[n].difference = NOT_POSSIBLE; } } } int no_of_aps = 0; for(int i = 1; i < MAX_ELEMENTS; i++) no_of_aps += (elements[i].difference != NOT_POSSIBLE); printf("%d\n", no_of_aps); for(int i = 1; i < MAX_ELEMENTS; i++) if(elements[i].difference != NOT_POSSIBLE) printf("%d %d\n", i, elements[i].difference); return 0; } ================================================ FILE: C Programs/C Programs 16/Pashmak and Garden.cpp ================================================ #include #define abs(x) ( (x) > 0 ? (x) : -(x) ) int main() { int x_1, x_2, y_1, y_2; scanf("%d %d %d %d", &x_1, &y_1, &x_2, &y_2); int x_3, y_3, x_4, y_4; if(x_1 == x_2) { int distance = abs(y_1 - y_2); x_3 = x_1 + distance; y_3 = y_1; x_4 = x_2 + distance; y_4 = y_2; } else if(y_1 == y_2) { int distance = abs(x_1 - x_2); y_3 = y_1 + distance; x_3 = x_1; y_4 = y_2 + distance; x_4 = x_2; } else if(abs(x_1 - x_2) == abs(y_1 - y_2)) { x_3 = x_1; y_3 = y_2; x_4 = x_2; y_4 = y_1; } else { printf("-1\n"); return 0; } printf("%d %d %d %d\n", x_3, y_3, x_4, y_4); return 0; } ================================================ FILE: C Programs/C Programs 16/Primes or Palindromes.cpp ================================================ #include #include using namespace std; int reverse(int n) { int rev = 0; while(n) { rev = rev*10 + n%10; n /= 10; } return rev; } int is_palindrome(int n) { return (n == reverse(n)); } void precompute(vector &no_of_primes_till, vector &no_of_palindromes_till, int LIMIT) { vector is_prime(LIMIT + 1, true); is_prime[0] = is_prime[1] = false; vector primes; for(int i = 2; i <= LIMIT; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] < LIMIT; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } for(int i = 1; i <= LIMIT; i++) no_of_primes_till[i] = no_of_primes_till[i - 1] + is_prime[i]; for(int i = 1; i <= LIMIT; i++) no_of_palindromes_till[i] = no_of_palindromes_till[i - 1] + is_palindrome(i); } int main() { const int LIMIT = 2e6; vector no_of_primes_till(LIMIT + 1, 0); vector no_of_palindromes_till(LIMIT + 1, 0); precompute(no_of_primes_till, no_of_palindromes_till, LIMIT); int p, q; scanf("%d %d", &p, &q); for(int n = LIMIT; n >= 1; n--) { if(q*no_of_primes_till[n] <= p*no_of_palindromes_till[n]) { printf("%d\n", n); break; } } return 0; } ================================================ FILE: C Programs/C Programs 16/Quasi Binary.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); const int MAX_SIZE = 7; vector no_of_bits(MAX_SIZE + 1, 0); int greatest_bit = 0; for(int i = 0; n > 0; i++) { no_of_bits[i] = n%10; n /= 10; greatest_bit = max(greatest_bit, no_of_bits[i]); } printf("%d\n", greatest_bit); for(int i = 1; i <= greatest_bit; i++) { int number = 0; for(int j = no_of_bits.size() - 1; j >= 0; j--) { number *= 10; if(no_of_bits[j] > 0) number++; no_of_bits[j]--; } printf("%d ", number); } return 0; } ================================================ FILE: C Programs/C Programs 16/Sereja and Bottles.cpp ================================================ #include #include using namespace std; int main() { int no_of_bottles; scanf("%d", &no_of_bottles); vector brand(no_of_bottles + 1, 0); vector can_open(no_of_bottles + 1, 0); for(int i = 1; i <= no_of_bottles; i++) scanf("%d %d", &brand[i], &can_open[i]); int impossible_bottles = 0; for(int i = 1; i <= no_of_bottles; i++) { int openable = false; for(int j = 1; j <= no_of_bottles; j++) { if(can_open[j] == brand[i] && i != j) openable = true; } impossible_bottles += (!openable); } printf("%d\n", impossible_bottles); return 0; } ================================================ FILE: C Programs/C Programs 16/Team Olympiad.cpp ================================================ #include #include #define min(a, b) (a < b ? a : b) #define min_3(a, b, c) min(a, min(b, c)) using namespace std; int main() { vector mathematician; vector programmer; vector sportsperson; int no_of_players; scanf("%d", &no_of_players); for(int i = 1; i <= no_of_players; i++) { int activity; scanf("%d", &activity); switch(activity) { case 1: mathematician.push_back(i); break; case 2: programmer.push_back(i); break; case 3: sportsperson.push_back(i); break; } } int no_of_teams = min_3(mathematician.size(), programmer.size(), sportsperson.size()); printf("%d\n", no_of_teams); for(int i = 1; i <= no_of_teams; i++) printf("%d %d %d\n", mathematician[i - 1], programmer[i - 1], sportsperson[i - 1]); return 0; } ================================================ FILE: C Programs/C Programs 16/The Fibonacci Segment.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector longest_segment_ending(no_of_elements + 1, 1); int longest_segment = 1; for(int i = 2; i <= no_of_elements; i++) { if(i == 2) longest_segment_ending[i] = 2; else longest_segment_ending[i] = (element[i] == element[i - 1] + element[i - 2] ? longest_segment_ending[i - 1] + 1 : 2); longest_segment = max(longest_segment, longest_segment_ending[i]); } printf("%d\n", longest_segment); return 0; } ================================================ FILE: C Programs/C Programs 16/Twins.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_coins; scanf("%d", &no_of_coins); int total = 0; vector coin(no_of_coins); for(int i = 0; i < no_of_coins; i++) { scanf("%d", &coin[i]); total += coin[i]; } sort(all(coin)); int no_of_coins_taken = 0, sum_of_taken = 0; for(int i = no_of_coins - 1; i >= 0 && sum_of_taken <= total ; i--) { sum_of_taken += coin[i]; total -= coin[i]; no_of_coins_taken++; } printf("%d\n", no_of_coins_taken); return 0; } ================================================ FILE: C Programs/C Programs 16/Valera and Tubes.cpp ================================================ #include #include using namespace std; const int MAX_ROWS = 301, MAX_COLUMNS = 301; int visited[MAX_ROWS][MAX_COLUMNS] = {{false}}; void get_next(int &x, int &y, int columns) { if( (y == 1 && visited[x][y + 1]) || (y == columns && visited[x][y - 1]) ) x++; else if(y < columns && !visited[x][y + 1]) y++; else y--; } int main() { int rows, columns, no_of_tubes; scanf("%d %d %d", &rows, &columns, &no_of_tubes); vector > >tubes(no_of_tubes + 1); int x = 1, y = 1, i = 1; while(x <= rows) { tubes[i].push_back(make_pair(x, y)); if(i != no_of_tubes && tubes[i].size() == 2) i++; visited[x][y] = true; get_next(x, y, columns); } for(int i = 1; i <= no_of_tubes; i++) { printf("%d ", tubes[i].size()); for(int j = 0; j < tubes[i].size(); j++) printf("%d %d ", tubes[i][j].first, tubes[i][j].second); printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 16/Xenia and Bit Operations.cpp ================================================ #include const int OR = 0, XOR = 1, MAX_SIZE = 1e6; int tree[3*MAX_SIZE]; int element[MAX_SIZE]; int perform(int a, int operation, int b) { switch(operation) { case OR : return (a|b); case XOR : return (a^b); } } int other(int operation) { return (operation^1); } void build(int node, int start, int end, int operation) { if(start == end) { tree[node] = element[start]; return; } int mid = (start + end)/2; build(2*node, start, mid, other(operation)); build(2*node + 1, mid + 1, end, other(operation)); tree[node] = perform(tree[2*node], operation, tree[2*node + 1]); } void update(int node, int start, int end, int index, int value, int operation) { if(start == end) { tree[node] = element[index] = value; return; } int mid = (start + end)/2; if(index >= start && index <= mid) { update(2*node, start, mid, index, value, other(operation)); } else if(index > mid && index <= end) { update(2*node + 1, mid + 1, end, index, value, other(operation)); } tree[node] = perform(tree[2*node], operation, tree[2*node + 1]); } int main() { int n, no_of_queries; scanf("%d %d", &n, &no_of_queries); int no_of_elements = (1 << n); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); int first_operation = (n%2 == 0 ? XOR : OR); build(1, 1, no_of_elements, first_operation); while(no_of_queries--) { int index, value; scanf("%d %d", &index, &value); update(1, 1, no_of_elements, index, value, first_operation); printf("%d\n", tree[1]); } return 0; } ================================================ FILE: C Programs/C Programs 16/Xenia and Ringroad.cpp ================================================ #include int get_travel_time(int previous, int current, int no_of_houses) { return (previous <= current ? current - previous : no_of_houses - previous + current); } int main() { int no_of_houses, no_of_tasks; scanf("%d %d", &no_of_houses, &no_of_tasks); int previous_house = 1; long long total_time = 0; while(no_of_tasks--) { int current_house; scanf("%d", ¤t_house); total_time += get_travel_time(previous_house, current_house, no_of_houses); previous_house = current_house; } printf("%I64d\n", total_time); return 0; } ================================================ FILE: C Programs/C Programs 16/k-String.cpp ================================================ #include #include using namespace std; int main() { int k; string input; cin >> k >> input; const int NO_OF_ALPHABETS = 26; int frequency[NO_OF_ALPHABETS] = {0}; for(int i = 0; i < input.length(); i++) frequency[input[i] - 'a']++; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(frequency[i]%k != 0) { cout << "-1"; return 0; } string smaller_string; for(int i = 0; i < NO_OF_ALPHABETS; i++) { for(int j = 0; j < frequency[i]/k; j++) smaller_string += ('a' + i); } for(int i = 1; i <= k; i++) cout << smaller_string; return 0; } ================================================ FILE: C Programs/C Programs 17/Adding Digits.cpp ================================================ #include int main() { int a, b, no_of_operations; scanf("%d %d %d", &a, &b, &no_of_operations); int appended_digit = -1; for(int digit = 0; digit <= 9; digit++) { if((a*10 + digit)%b == 0) { appended_digit = digit; break; } } if(appended_digit == -1) { printf("-1\n"); } else { printf("%d%d", a, appended_digit); for(int i = 2; i <= no_of_operations; i++) printf("0"); } return 0; } ================================================ FILE: C Programs/C Programs 17/Christmas Spruce.cpp ================================================ #include int main() { int no_of_vertices; scanf("%d", &no_of_vertices); int no_of_children[no_of_vertices + 1] = {0}; int parent[no_of_vertices + 1]; for(int i = 2; i <= no_of_vertices; i++) { scanf("%d", &parent[i]); no_of_children[parent[i]]++; } int no_of_leaf_children[no_of_vertices + 1] = {0}; for(int i = 1; i <= no_of_vertices; i++) { if(no_of_children[i] == 0) { no_of_leaf_children[parent[i]]++; } } int is_spruce = true; for(int i = 1; i<= no_of_vertices; i++) { if(no_of_children[i] > 0 && no_of_leaf_children[i] < 3) { is_spruce = false; break; } } printf(is_spruce ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: C Programs/C Programs 17/Dreamoon and Wi-Fi.cpp ================================================ #include int choose(int n, int r) { if(r > n) return 0; int answer = 1; for(int i = 0; i < r; i++) answer = (answer*(n - i))/(i + 1); return answer; } int main() { const int MAX_LENGTH = 11; char sent_commands[MAX_LENGTH], received_commands[MAX_LENGTH]; scanf("%s %s", sent_commands, received_commands); int destination = 0; for(int i = 0; sent_commands[i] != '\0'; i++) destination += (sent_commands[i] == '+' ? 1 : -1); int reached = 0, unrecognised_symbols = 0; for(int i = 0; received_commands[i] != '\0'; i++) { if(received_commands[i] == '?') unrecognised_symbols++; else reached += (received_commands[i] == '+' ? 1 : -1); } int remaining = destination - reached; int no_of_plus = 0, no_of_minus = unrecognised_symbols; while(no_of_plus - no_of_minus != remaining) { no_of_plus++; no_of_minus--; } int no_of_ways = choose(unrecognised_symbols, no_of_plus); int total_ways = (1 << unrecognised_symbols); double probability = (no_of_ways*1.0f)/(total_ways*1.0f); printf("%.9lf", probability); return 0; } ================================================ FILE: C Programs/C Programs 17/Exams - 122.cpp ================================================ #include int main() { int no_of_exams, minimum_marks; scanf("%d %d", &no_of_exams, &minimum_marks); int marks_scored = 2*no_of_exams; int remaining_marks = minimum_marks - marks_scored; int exams_with_2_marks = (remaining_marks >= no_of_exams ? 0 : no_of_exams - remaining_marks); printf("%d\n", exams_with_2_marks); return 0; } ================================================ FILE: C Programs/C Programs 17/Garden.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int n, length; scanf("%d %d", &n, &length); int ans = 1e9; for(int i = 1; i <= n; i++) { int a_i; scanf("%d", &a_i); if(length%a_i == 0) ans = min(ans, length/a_i); } printf("%d\n", ans); return 0; } ================================================ FILE: C Programs/C Programs 17/Jamie and Alarm Snooze.cpp ================================================ #include int is_lucky(int n) { while(n) { if(n%10 == 7) return true; n = n/10; } return false; } int main() { int decrement_time, hour, minute; scanf("%d %d %d", &decrement_time, &hour, &minute); int no_of_hits = 0; while(!is_lucky(hour) && !is_lucky(minute)) { const int NO_OF_MINUTES_IN_HOUR = 60, NO_OF_HOURS_IN_DAY = 24; minute -= decrement_time; if(minute < 0) { minute += NO_OF_MINUTES_IN_HOUR; hour--; } if(hour < 0) { hour += NO_OF_HOURS_IN_DAY; } no_of_hits++; } printf("%d\n", no_of_hits); return 0; } ================================================ FILE: C Programs/C Programs 17/Jamie and Interesting Graph.cpp ================================================ #include int is_prime(int n) { if(n <= 1) return false; for(int i = 2; i*i <= n; i++) if(n%i == 0) return false; return true; } int find_nearest_prime(int n) { int ans = n + 1; while(!is_prime(ans)) ans++; return ans; } int main() { int n, no_of_edges; scanf("%d %d", &n, &no_of_edges); int cost_to_n = find_nearest_prime(n - 2) - (n - 2); int mst_cost = cost_to_n + (n - 2); int min_path = mst_cost; printf("%d %d\n", mst_cost, min_path); for(int i = 1; i < n - 1; i++) printf("%d %d %d\n", i, i + 1, 1); printf("%d %d %d\n", n - 1, n, cost_to_n); int edges = n - 1; for(int u = 1; u <= n - 1 && edges < no_of_edges; u++) { for(int v = u + 2; v <= n && edges < no_of_edges; v++) { printf("%d %d %d\n", u, v, mst_cost); edges++; } } return 0; } ================================================ FILE: C Programs/C Programs 17/Kolya and Tanya.cpp ================================================ #include long long power_mod(long long x, int power, int MOD) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } int main() { int n; scanf("%d", &n); const int MOD = 1e9 + 7; long long no_of_ways = power_mod(27, n, MOD) + (MOD - power_mod(7, n, MOD)); no_of_ways %= MOD; printf("%I64d\n", no_of_ways); return 0; } ================================================ FILE: C Programs/C Programs 17/Mashmokh and ACM.cpp ================================================ #include const int N = 2001; long long no_of_sequences[N][N]; int main() { const int MOD = 1e9 + 7; int max_number, length; scanf("%d %d", &max_number, &length); for(int first_number = 1; first_number <= max_number; first_number++) no_of_sequences[first_number][1] = 1; for(int l = 2; l <= length; l++) { for(int first_number = 1; first_number <= max_number; first_number++) { no_of_sequences[first_number][l] = 0; for(int i = 1; first_number*i <= max_number; i++) { no_of_sequences[first_number][l] += no_of_sequences[first_number*i][l - 1]; } no_of_sequences[first_number][l] %= MOD; } } long long answer = 0; for(int first_number = 1; first_number <= max_number; first_number++) answer += no_of_sequences[first_number][length]; answer %= MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 17/Maximum Splitting.cpp ================================================ #include int main() { int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int n; scanf("%d", &n); int no_of_parts = -1; if( !(n <= 3 || n == 5 || n == 7 || n == 11) ) { switch(n%4) { case 0: no_of_parts = n/4; break; case 1: no_of_parts = (n - 9)/4 + 1; break; case 2: no_of_parts = (n - 6)/4 + 1; break; case 3: no_of_parts = (n - 15)/4 + 2; break; } } printf("%d\n", no_of_parts); } return 0; } ================================================ FILE: C Programs/C Programs 17/Minimum Sum.cpp ================================================ #include #define all(v) (v).begin(), (v).end() using namespace std; struct code { int is_first_digit, coefficient; code(){ is_first_digit = false, coefficient = 0; } }; int compare(const code &A, const code &B) { return (A.coefficient < B.coefficient); } int main() { const int NO_OF_DIGITS = 10; vector letter(NO_OF_DIGITS); int no_of_numbers; scanf("%d", &no_of_numbers); while(no_of_numbers--) { string number; cin >> number; letter[number[0] - 'a'].is_first_digit = true; int power_of_10 = 1; for(int i = number.size() - 1; i >= 0; i--) { letter[number[i] - 'a'].coefficient += power_of_10; power_of_10 *= 10; } } sort(all(letter), compare); vector assigned(NO_OF_DIGITS, false); int sum = 0; for(int i = NO_OF_DIGITS - 1; i >= 0; i--) { int digit = (letter[i].is_first_digit ? 1 : 0); while(assigned[digit]) digit++; assigned[digit] = true; sum += letter[i].coefficient*digit; } printf("%d\n", sum); return 0; } ================================================ FILE: C Programs/C Programs 17/Modular Exponentiation.cpp ================================================ #include int main() { int n, m; scanf("%d %d", &n, &m); int answer = (n > 31 ? m : m%(1 << n)); printf("%d ", answer); return 0; } ================================================ FILE: C Programs/C Programs 17/New Year and Domino.cpp ================================================ #include #include int main() { int rows, columns; scanf("%d %d", &rows, &columns); char cell[rows + 1][columns + 2]; for(int i = 1; i <= rows; i++) scanf("%s", cell[i] + 1); int horizontal_dominos[rows + 1][columns + 2] = {{0}}; int vertical_dominos[rows + 1][columns + 2] = {{0}}; memset(vertical_dominos, 0, sizeof(vertical_dominos)); memset(horizontal_dominos, 0, sizeof(horizontal_dominos)); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns + 1; j++) { horizontal_dominos[i][j] = (cell[i][j] == '.' && cell[i][j - 1] == '.'); horizontal_dominos[i][j] += horizontal_dominos[i - 1][j] + horizontal_dominos[i][j - 1] - horizontal_dominos[i - 1][j - 1]; vertical_dominos[i][j] = (cell[i][j] == '.' && cell[i - 1][j] == '.'); vertical_dominos[i][j] += vertical_dominos[i][j - 1] + vertical_dominos[i - 1][j] - vertical_dominos[i - 1][j - 1]; } } int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int row_1, column_1, row_2, column_2; scanf("%d %d %d %d", &row_1, &column_1, &row_2, &column_2); int total_horizontal = horizontal_dominos[row_2][column_2] - horizontal_dominos[row_2][column_1] - horizontal_dominos[row_1 - 1][column_2] +horizontal_dominos[row_1 - 1][column_1]; int total_vertical = vertical_dominos[row_2][column_2] - vertical_dominos[row_2][column_1 - 1] - vertical_dominos[row_1][column_2] + vertical_dominos[row_1][column_1 - 1]; int total_dominos = total_horizontal + total_vertical; printf("%d\n", total_dominos); } return 0; } ================================================ FILE: C Programs/C Programs 17/New Year's Eve.cpp ================================================ #include int no_of_bits(long long n) { int bit_count = 0; while(n) { n = n >> 1; bit_count++; } return bit_count; } int main() { long long n, k; scanf("%I64d %I64d", &n, &k); long long answer; if(k == 1) { answer = n; } else { answer = (1LL << no_of_bits(n) ) - 1; } printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 17/Palindrome Pairs.cpp ================================================ #include #include #include #include using namespace std; int main() { string A; cin >> A; int length = A.size(); int is_palindrome[length + 1][length + 1] = {{false}}; vector palindrome_starts(length + 1, 0); vector palindrome_ends(length + 1, 0); for(int i = 0; i < length; i++) { is_palindrome[i][i] = true; palindrome_starts[i] = palindrome_ends[i] = 1; } for(int substring_length = 2; substring_length < length; substring_length++) { for(int start = 0, end = start + substring_length - 1; end < length; start++, end++) { if(A[start] == A[end] && (substring_length == 2 || is_palindrome[start + 1][end - 1])) { is_palindrome[start][end] = true; palindrome_starts[start]++; palindrome_ends[end]++; } } } vector palindromes_from(length + 1, 0); for(int i = length - 1; i >= 0; i--) palindromes_from[i] = palindromes_from[i + 1] + palindrome_starts[i]; long long palindromic_pairs = 0; for(int i = 0; i < length; i++) palindromic_pairs += palindrome_ends[i]*1LL*palindromes_from[i + 1]; printf("%I64d\n", palindromic_pairs); return 0; } ================================================ FILE: C Programs/C Programs 17/Perfect Number.cpp ================================================ #include #include using namespace std; int sum_of_digits(int n) { int sum = 0; while(n) { sum += n%10; n /= 10; } return sum; } int main() { vector perfect_number; for(int i = 19; perfect_number.size() <= 1e4; i+=9) { if(sum_of_digits(i) == 10) perfect_number.push_back(i); } int k; scanf("%d", &k); printf("%d\n", perfect_number[k - 1]); return 0; } ================================================ FILE: C Programs/C Programs 17/QAQ.cpp ================================================ #include #include using namespace std; int main() { const int N = 101; char input[N]; scanf("%s", input); int length = strlen(input); int no_of_Q_till[length] = {0}; no_of_Q_till[0] = (input[0] == 'Q'); for(int i = 1; i < length; i++) no_of_Q_till[i] = no_of_Q_till[i - 1] + (input[i] == 'Q'); int no_of_Q_after[length] = {0}; no_of_Q_after[length - 1] = (input[length - 1] == 'Q'); for(int i = length - 2; i >= 0; i--) no_of_Q_after[i] = no_of_Q_after[i + 1] + (input[i] == 'Q'); int no_of_QAQ = 0; for(int i = 0; i < length; i++) if(input[i] == 'A') no_of_QAQ += no_of_Q_till[i]*no_of_Q_after[i]; printf("%d\n", no_of_QAQ); return 0; } ================================================ FILE: C Programs/C Programs 17/Seat Arrangements.cpp ================================================ #include #include int main() { int no_of_rows, no_of_columns, k; scanf("%d %d %d", &no_of_rows, &no_of_columns, &k); char seat[no_of_rows + 1][no_of_columns + 2]; for(int row = 1; row <= no_of_rows; row++) scanf("%s", seat[row] + 1); int up_empty_seats[no_of_rows + 1][no_of_columns + 1]; memset(up_empty_seats, 0, sizeof(up_empty_seats)); int left_empty_seats[no_of_rows + 1][no_of_columns + 1]; memset(left_empty_seats, 0, sizeof(left_empty_seats)); int total_seatings = 0; for(int row = 1; row <= no_of_rows; row++) { for(int column = 1; column <= no_of_columns; column++) { up_empty_seats[row][column] = (seat[row][column] == '.' ? 1 + up_empty_seats[row - 1][column] : 0); left_empty_seats[row][column] = (seat[row][column] == '.' ? 1 + left_empty_seats[row][column - 1] : 0); total_seatings += (up_empty_seats[row][column] >= k) + (left_empty_seats[row][column] >= k); } } if(k == 1) total_seatings = total_seatings >> 1; printf("%d\n", total_seatings); return 0; } ================================================ FILE: C Programs/C Programs 17/Supermarket.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int n, m; scanf("%d %d", &n, &m); double ans = 1E9; while(n--) { int a, b; scanf("%d %d", &a, &b); ans = min(ans, (a*1.0*m)/(b*1.0)); } printf("%lf\n", ans); return 0; } ================================================ FILE: C Programs/C Programs 17/Swap Adjacent Elements.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); vector permutation(n + 1, 0); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); vector ones_till(n + 1, 0); for(int i = 1; i <= n - 1; i++) { int digit; scanf("%1d", &digit); ones_till[i] = (digit == 1) + ones_till[i - 1]; } int is_sortable = true; for(int i = 1; i <= n; i++) { if(permutation[i] != i) { int right = max(i, permutation[i]); int left = min(i, permutation[i]); int distance = (right - 1) - (left - 1); if(ones_till[right - 1] - ones_till[left - 1] != distance) is_sortable = false; } } printf(is_sortable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 17/Tea Queue.cpp ================================================ #include #include using namespace std; void solve() { int number_of_students; scanf("%d", &number_of_students); vector left(number_of_students + 1); vector right(number_of_students + 1); for(int i = 1; i <= number_of_students; i++) scanf("%d %d", &left[i], &right[i]); vector served_time(number_of_students + 1, 0); for(int current_time = left[1], student = 1; student <= number_of_students; student++) { current_time = max(current_time, left[student]); if(current_time <= right[student]) { served_time[student] = current_time++; } } for(int i = 1; i <= number_of_students; i++) printf("%d ", served_time[i]); printf("\n"); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 17/Testing Pants for Sadness.cpp ================================================ #include int main() { int no_of_questions; scanf("%d", &no_of_questions); long long no_of_clicks = 0; for(int i = 1; i <= no_of_questions; i++) { int no_of_options; scanf("%d", &no_of_options); no_of_clicks += 1 + i*1LL*(no_of_options - 1); } printf("%I64d\n", no_of_clicks); return 0; } ================================================ FILE: C Programs/C Programs 17/The World is a Theatre.cpp ================================================ #include int main() { const int N = 60; long long combinations[N + 1][N + 1]; combinations[0][0] = 1; for(int n = 1; n <= N; n++) { for(int r = 0; r <= n; r++) { if(r == 0 || r == n) combinations[n][r] = 1; else combinations[n][r] = combinations[n - 1][r] + combinations[n - 1][r - 1]; } } int no_of_actors, boys, girls; scanf("%d %d %d", &boys, &girls, &no_of_actors); long long no_of_ways = 0; for(int i = 4; i < no_of_actors; i++) no_of_ways += combinations[boys][i]*combinations[girls][no_of_actors - i]; printf("%I64d\n", no_of_ways); return 0; } ================================================ FILE: C Programs/C Programs 17/Tricky Alchemy.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { int yellow, blue; scanf("%d %d", &yellow, &blue); int x, y, z; scanf("%d %d %d", &x, &y, &z); long long required_yellow = 2LL*x + y; long long required_blue = y + 3LL*z; long long required = max(0LL, required_yellow - yellow) + max(0LL, required_blue - blue); printf("%I64d\n", required); return 0; } ================================================ FILE: C Programs/C Programs 17/Water the Gardens.cpp ================================================ #include #include using namespace std; void solve() { int number_of_taps, number_of_beds; scanf("%d %d", &number_of_beds, &number_of_taps); vector tap(number_of_taps + 1, 0); for(int i = 1; i <= number_of_taps; i++) scanf("%d", &tap[i]); int time = tap[1]; for(int i = 1; i < number_of_taps; i++) { int distance = tap[i + 1] - tap[i] + 1; int time_for_this_patch = distance/2 + distance%2 ; time = max(time, time_for_this_patch); } time = max(time, number_of_beds - tap.back() + 1); printf("%d\n", time); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 18/Art Union.cpp ================================================ #include #include #define max(a, b) (a > b ? a : b) int main() { int number_of_paintings, number_of_painters; scanf("%d %d", &number_of_paintings, &number_of_painters); int time[number_of_paintings + 1][number_of_painters + 1]; for(int i = 1; i <= number_of_paintings; i++) for(int j = 1; j <= number_of_painters; j++) scanf("%d", &time[i][j]); int time_for[number_of_paintings + 1][number_of_painters + 1]; memset(time_for, 0, sizeof(time_for)); for(int painter_i = 1; painter_i <= number_of_painters; painter_i++) { for(int painting = 1; painting <= number_of_paintings; painting++) { time_for[painting][painter_i] = max(time_for[painting - 1][painter_i], time_for[painting][painter_i - 1]) + time[painting][painter_i]; } } int all_painters = number_of_painters; for(int i = 1; i <= number_of_paintings; i++) printf("%d ", time_for[i][all_painters]); return 0; } ================================================ FILE: C Programs/C Programs 18/Bear and Colours.cpp ================================================ #include #include using namespace std; int main() { int no_of_balls; scanf("%d", &no_of_balls); vector colour(no_of_balls + 1, 0); for(int i = 1; i <= no_of_balls; i++) scanf("%d", &colour[i]); vector no_of_winning_intervals(no_of_balls + 1); for(int start = 1; start <= no_of_balls; start++) { vector frequency(no_of_balls + 1, 0); int winner = 0; for(int i = start; i <= no_of_balls; i++) { frequency[colour[i]]++; if(frequency[colour[i]] > frequency[winner] || (frequency[colour[i]] == frequency[winner] && colour[i] < winner)) winner = colour[i]; no_of_winning_intervals[winner]++; } } for(int ball_i = 1; ball_i <= no_of_balls; ball_i++) printf("%d ", no_of_winning_intervals[ball_i]); return 0; } ================================================ FILE: C Programs/C Programs 18/Cave Painting.cpp ================================================ #include int main() { long long n, k; scanf("%I64d %I64d", &n, &k); const int LIMIT = 43; int divisible_by_lcm_1_till_k = true; if(k < LIMIT) { for(int i = 1; i <= k; i++) { if( (n + 1)%i != 0) { divisible_by_lcm_1_till_k = false; break; } } } printf(k < LIMIT && divisible_by_lcm_1_till_k ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: C Programs/C Programs 18/Cloning Toys.cpp ================================================ #include int main() { int originals, copies; scanf("%d %d", &copies, &originals); originals--; printf( (originals == 0 && copies == 0) || (originals >= 1 && copies >= originals && (copies - originals)%2 == 0) ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: C Programs/C Programs 18/Eternal Victory.cpp ================================================ #include #include using namespace std; const int MAX_CITIES = 1e5 + 5; vector > tree[MAX_CITIES]; int max_distance[MAX_CITIES]; void dfs(int v, int parent_v) { max_distance[v] = 0; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i].first; int child_distance = tree[v][i].second; if(child_v == parent_v) continue; dfs(child_v, v); max_distance[v] = max(max_distance[v], child_distance + max_distance[child_v]); } } int main() { int no_of_cities; scanf("%d", &no_of_cities); long long sum_of_edges = 0; for(int i = 1; i < no_of_cities; i++) { int x, y, weight; scanf("%d %d %d", &x, &y, &weight); tree[x].push_back(make_pair(y, weight)); tree[y].push_back(make_pair(x, weight)); sum_of_edges += weight; } dfs(1, 0); long long total_travel_distance = (sum_of_edges == max_distance[1] ? sum_of_edges : 2*sum_of_edges - max_distance[1]); printf("%I64d\n", total_travel_distance); return 0; } ================================================ FILE: C Programs/C Programs 18/Hard Problem.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; string rev(string s) { reverse(all(s)); return s; } int main() { int no_of_strings; scanf("%d", &no_of_strings); vector cost(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) scanf("%d", &cost[i]); vector s(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) cin >> s[i]; const long long oo = 1e16; const int WITHOUT_REVERSING = 0, REVERSING = 1; long long minimum_till[no_of_strings + 1][2]; minimum_till[0][REVERSING] = minimum_till[0][WITHOUT_REVERSING] = 0; for(int i = 1; i <= no_of_strings; i++) { minimum_till[i][REVERSING] = minimum_till[i][WITHOUT_REVERSING] = oo; if(s[i] >= s[i - 1]) minimum_till[i][WITHOUT_REVERSING] = minimum_till[i - 1][WITHOUT_REVERSING]; if(s[i] >= rev(s[i - 1])) minimum_till[i][WITHOUT_REVERSING] = min(minimum_till[i][WITHOUT_REVERSING], minimum_till[i - 1][REVERSING]); if(rev(s[i]) >= s[i - 1]) minimum_till[i][REVERSING] = cost[i] + minimum_till[i - 1][WITHOUT_REVERSING]; if(rev(s[i]) >= rev(s[i - 1])) minimum_till[i][REVERSING] = min(minimum_till[i][REVERSING], cost[i] + minimum_till[i - 1][REVERSING]); } long long answer = min(minimum_till[no_of_strings][REVERSING], minimum_till[no_of_strings][WITHOUT_REVERSING]); printf("%I64d\n", answer >= oo ? -1 : answer); return 0; } ================================================ FILE: C Programs/C Programs 18/Joystick.cpp ================================================ #include #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) int main() { int charge_a, charge_b; scanf("%d %d", &charge_a, &charge_b); int no_of_minutes = 0; while(max(charge_a, charge_b) > 1 && min(charge_a, charge_b) > 0) { if(charge_a < charge_b) charge_a++, charge_b -= 2; else charge_a -= 2, charge_b++; no_of_minutes++; } printf("%d\n", no_of_minutes); return 0; } ================================================ FILE: C Programs/C Programs 18/K-Special Tables.cpp ================================================ #include int main() { int N, k; scanf("%d %d", &N, &k); int special_table[N + 1][N + 1]; int front_ptr = 1, back_ptr = N*N; for(int row = 1; row <= N; row++) { for(int column = N; column >= k; column--) special_table[row][column] = back_ptr--; for(int column = 1; column < k; column++) special_table[row][column] = front_ptr++; } int k_column_sum = 0; for(int row = 1; row <= N; row++) k_column_sum += special_table[row][k]; printf("%d\n", k_column_sum); for(int row = 1; row <= N; row++) { for(int column = 1; column <= N; column++) { printf("%d ", special_table[row][column]); } printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 18/Lucky Sum.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() #define min(a, b) (a < b ? a : b) using namespace std; void compute(vector &lucky_numbers, long long last_lucky_number) { lucky_numbers.push_back(last_lucky_number); if(last_lucky_number > 1e10) return ; compute(lucky_numbers, last_lucky_number*10 + 4); compute(lucky_numbers, last_lucky_number*10 + 7); } long long get_answer(vector &lucky_numbers, int limit) { long long answer = 0; for(int i = 1; i < lucky_numbers.size() && lucky_numbers[i - 1] < limit; i++) { long long next_lucky_number = lucky_numbers[i]; long long range = min(limit, lucky_numbers[i]) - lucky_numbers[i - 1]; answer += next_lucky_number*range; } return answer; } int main() { vector lucky_numbers; compute(lucky_numbers, 0); sort(all(lucky_numbers)); int left, right; scanf("%d %d", &left, &right); long long answer = get_answer(lucky_numbers, right) - get_answer(lucky_numbers, left - 1); printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 18/Magic Forest.cpp ================================================ #include int is_nondegenerate_triangle(int a, int b, int c) { return (a + b > c); } int main() { int n; scanf("%d", &n); int no_of_triangles = 0; for(int a = 1; a <= n; a++) { for(int b = a; b <= n; b++) { int c = a^b; if(c >= b && c <= n && is_nondegenerate_triangle(a, b, c)) no_of_triangles++; } } printf("%d\n", no_of_triangles); } ================================================ FILE: C Programs/C Programs 18/Marvolo Gaunt's Ring Alternate Solution.cpp ================================================ #include #include #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) using namespace std; int main() { int no_of_elements; long long p, q, r; scanf("%d %I64d %I64d %I64d", &no_of_elements, &p, &q, &r); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector left_min(no_of_elements + 1); vector left_max(no_of_elements + 1); left_min[1] = left_max[1] = A[1]; for(int i = 2; i <= no_of_elements; i++) { left_min[i] = min(left_min[i - 1], A[i]); left_max[i] = max(left_max[i - 1], A[i]); } vector right_min(no_of_elements + 1); vector right_max(no_of_elements + 1); right_min[no_of_elements] = right_max[no_of_elements] = A[no_of_elements]; for(int i = no_of_elements - 1; i >= 1; i--) { right_max[i] = max(right_max[i + 1], A[i]); right_min[i] = min(right_min[i + 1], A[i]); } long long ans = p*A[1] + q*A[1] + r*A[1]; for(int i = 1; i <= no_of_elements; i++) { long long y = q*A[i]; long long x = (p > 0 ? p*left_max[i] : p*left_min[i]); long long z = (r > 0 ? r*right_max[i] : r*right_min[i]); ans = max(ans, x + y + z); } printf("%I64d\n", ans); return 0; } ================================================ FILE: C Programs/C Programs 18/Marvolo Gaunt's Ring.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; long long p, q, r; scanf("%d %I64d %I64d %I64d", &no_of_elements, &p, &q, &r); vector a(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &a[i]); vector max_P(no_of_elements); max_P[0] = p*a[0]; for(int i = 1; i < no_of_elements; i++) max_P[i] = max(max_P[i - 1], p*a[i]); vector max_Q(no_of_elements); max_Q[0] = q*a[0] + p*a[0]; for(int i = 1; i < no_of_elements; i++) max_Q[i] = max(max_Q[i - 1], q*a[i] + max_P[i]); vector max_R(no_of_elements); max_R[0] = r*a[0] + q*a[0] + p*a[0]; for(int i = 1; i < no_of_elements; i++) max_R[i] = max(max_R[i - 1], r*a[i] + max_Q[i]); printf("%I64d\n", max_R[no_of_elements - 1]); return 0; } ================================================ FILE: C Programs/C Programs 18/Not Equal on a Segment.cpp ================================================ #include #include using namespace std; int main() { int number_of_elements, number_of_queries; scanf("%d %d", &number_of_elements, &number_of_queries); vector A(number_of_elements + 1, 0); for(int i = 1; i <= number_of_elements; i++) scanf("%d", &A[i]); vector first_unequal_position_left(number_of_elements + 1, 0); for(int i = 1; i <= number_of_elements; i++) first_unequal_position_left[i] = (A[i] != A[i - 1] ? i - 1 : first_unequal_position_left[i - 1]); while(number_of_queries--) { int left, right, x; scanf("%d %d %d", &left, &right, &x); int answer; if(A[right] != x) answer = right; else if(A[right] == x) answer = (first_unequal_position_left[right] >= left ? first_unequal_position_left[right] : -1); printf("%d\n", answer); } return 0; } ================================================ FILE: C Programs/C Programs 18/Perfect Squares.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int n; scanf("%d", &n); vector A(n); for(int i = 0; i < n; i++) scanf("%d", &A[i]); sort(all(A)); vector is_square(1e6 + 1, false); for(int i = 0; i*i <= 1e6; i++) is_square[i*i] = true; int answer; for(int i = n - 1; i >= 0; i--) { if(A[i] < 0 || !is_square[A[i]]) { answer = A[i]; break; } } printf("%d ", answer); return 0; } ================================================ FILE: C Programs/C Programs 18/Petya and Inequiations.cpp ================================================ #include int main() { int n, sum_limit; long long square_sum_lower_bound; scanf("%d %I64d %d", &n, &square_sum_lower_bound, &sum_limit); long long largest_element = sum_limit - (n - 1); long long max_square_sum = (n - 1) + largest_element*largest_element; if(max_square_sum < square_sum_lower_bound || n > sum_limit) { printf("-1\n"); return 0; } for(int i = 1; i <= n; i++) printf("%I64d\n", (i == n ? largest_element : 1)); return 0; } ================================================ FILE: C Programs/C Programs 18/Polo the Penguin and Matrix.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_rows, no_of_columns, difference; scanf("%d %d %d", &no_of_rows, &no_of_columns, &difference); vector A(no_of_rows*no_of_columns, 0); set remainder; int possible = true; for(int i = 0; i < no_of_rows*no_of_columns; i++) { scanf("%d", &A[i]); remainder.insert(A[i]%difference); } if(remainder.size() > 1) possible = false; sort(all(A)); int middle = A.size()/2; int median = A[middle]; int minimum_no_of_moves = 0; for(int i = 0; i < A.size(); i++) minimum_no_of_moves += abs(A[i] - median)/difference; printf("%d\n", possible ? minimum_no_of_moves : -1); return 0; } ================================================ FILE: C Programs/C Programs 18/Polo the Penguin and Strings.cpp ================================================ #include #include #include using namespace std; int main() { int length, distinct_letters; scanf("%d %d", &length, &distinct_letters); if(length < distinct_letters || (length > 1 && distinct_letters == 1)) { printf("-1\n"); return 0; } string answer; for(int i = 0; i < length; i++) answer += ('a' + i%2); for(int i = length - 1, letter = distinct_letters - 1; letter >= 2; i--, letter--) answer[i] = ('a' + letter); cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 18/Replacement.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); sort(all(element)); if(no_of_elements == 1) { printf("%d", element[0] == 1 ? 2 : 1); return 0; } printf("1 "); for(int i = 1; i < no_of_elements - 1; i++) printf("%d ", element[i - 1]); if(element[no_of_elements - 1] == 1) printf("2"); else printf("%d", element[no_of_elements - 2]); return 0; } ================================================ FILE: C Programs/C Programs 18/Robot Vaccuum Cleaner.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct info { long long no_of_s, no_of_h; string text; }; int compare(const info &A, const info &B) { long long no_of_new_sh_if_A_front = A.no_of_s*B.no_of_h; long long no_of_new_sh_if_B_front = B.no_of_s*A.no_of_h; if(no_of_new_sh_if_A_front > no_of_new_sh_if_B_front) return true; else return false; } int main() { int no_of_strings; cin >> no_of_strings; vector A(no_of_strings); for(int i = 0; i < no_of_strings; i++) { cin >> A[i].text; A[i].no_of_s = 0; A[i].no_of_h = 0; for(int j = 0; j < A[i].text.size(); j++) { A[i].no_of_s += (A[i].text[j] == 's'); A[i].no_of_h += (A[i].text[j] == 'h'); } } sort(all(A), compare); string final_text; for(int i = 0; i < no_of_strings; i++) final_text += A[i].text; long long no_of_s_till_here = 0, no_of_sh = 0; for(int i = 0; i < final_text.size(); i++) { no_of_s_till_here += (final_text[i] == 's'); if(final_text[i] == 'h') no_of_sh += no_of_s_till_here; } cout << no_of_sh; return 0; } ================================================ FILE: C Programs/C Programs 18/Rumour.cpp ================================================ #include #include #include #define min(a, b) (a < b ? a : b) using namespace std; const int MAX_N = 1e5 + 5; vector graph[MAX_N]; vector component[MAX_N]; int visited[MAX_N]; void dfs_and_mark_component(int v, int component_no) { visited[v] = true; component[component_no].push_back(v); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) dfs_and_mark_component(child, component_no); } } int main() { int no_of_people, no_of_friendships; scanf("%d %d", &no_of_people, &no_of_friendships); vector gold(no_of_people + 1, 0); for(int i = 1; i <= no_of_people; i++) scanf("%d", &gold[i]); for(int i = 1; i <= no_of_friendships; i++) { int person_1, person_2; scanf("%d %d", &person_1, &person_2); graph[person_1].push_back(person_2); graph[person_2].push_back(person_1); } memset(visited, false, sizeof(visited)); int component_no = 1; for(int i = 1; i <= no_of_people; i++) { if(!visited[i]) { dfs_and_mark_component(i, component_no++); } } long long total_cost = 0; for(int component_i = 1; component_i < component_no; component_i++) { long long min_cost_for_this_component = 1e15; for(int v = 0; v < component[component_i].size(); v++) { int person = component[component_i][v]; min_cost_for_this_component = min(min_cost_for_this_component, gold[person]); } total_cost += min_cost_for_this_component; } printf("%I64d\n", total_cost); return 0; } ================================================ FILE: C Programs/C Programs 18/Search for Pretty Integers.cpp ================================================ #include #include using namespace std; int main() { int list_1_size, list_2_size; scanf("%d %d", &list_1_size, &list_2_size); vector in_A(10, false); for(int i = 1; i <= list_1_size; i++) { int a_i; scanf("%d", &a_i); in_A[a_i] = true; } vector in_B(10, false); for(int i = 1; i <= list_2_size; i++) { int b_i; scanf("%d", &b_i); in_B[b_i] = true; } int answer = -1; for(int i = 1; i <= 9; i++) { if(in_A[i] && in_B[i]) { answer = i; break; } } if(answer != -1) { printf("%d\n", answer); return 0; } for(int i = 1; i <= 9 && answer == -1; i++) { for(int j = i + 1; j <= 9; j++) { if( (in_A[i] && in_B[j]) || (in_A[j] && in_B[i]) ) { answer = 10*i + j; break; } } } printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 18/Tom Riddle's Diary.cpp ================================================ #include #include #include #include using namespace std; int main() { int no_of_people; scanf("%d", &no_of_people); set people; while(no_of_people--) { string current_possesser; cin >> current_possesser; printf(people.count(current_possesser) == 1 ? "YES\n" : "NO\n"); people.insert(current_possesser); } return 0; } ================================================ FILE: C Programs/C Programs 18/Two Substrings.cpp ================================================ #include #include #include using namespace std; int main() { string A; cin >> A; vector ab; vector ba; for(int i = 0; i < A.size() - 1; i++) { if(A[i] == 'A' && A[i + 1] == 'B') ab.push_back(i); if(A[i] == 'B' && A[i + 1] == 'A') ba.push_back(i); } if(ab.size() == 0 || ba.size() == 0 || !(ab[0] + 1 < ba.back() || ba[0] + 1 < ab.back())) cout << "NO\n"; else cout << "YES\n"; return 0; } ================================================ FILE: C Programs/C Programs 18/Vladik and Fractions.cpp ================================================ #include int main() { int n; scanf("%d", &n); int x = n; int y = n + 1; int z = n*(n + 1); printf(n == 1 ? "-1\n" : "%d %d %d\n", x, y, z); return 0; } ================================================ FILE: C Programs/C Programs 18/Woodcutter.cpp ================================================ #include #define max(a, b) (a > b ? a : b) #define max_3(a, b, c) max(a, max(b, c)) int main() { int no_of_trees; scanf("%d", &no_of_trees); long long height[no_of_trees + 1]; long long x[no_of_trees + 1]; for(int i = 1; i <= no_of_trees; i++) scanf("%I64d %I64d", &x[i], &height[i]); const int RIGHT = 1, STRAIGHT = 0, LEFT = 2; int max_cut[no_of_trees + 1][3]; max_cut[0][RIGHT] = max_cut[0][STRAIGHT] = max_cut[0][LEFT] = 0; for(int i = 1; i <= no_of_trees; i++) { max_cut[i][STRAIGHT] = max_3(max_cut[i - 1][LEFT], max_cut[i - 1][STRAIGHT], max_cut[i - 1][RIGHT]); max_cut[i][LEFT] = max_cut[i][RIGHT] = max_cut[i][STRAIGHT]; if(i == 1 || x[i] - height[i] > x[i - 1]) max_cut[i][LEFT] = 1 + max(max_cut[i - 1][LEFT], max_cut[i - 1][STRAIGHT]); if(height[i - 1] + height[i] + x[i - 1] < x[i]) max_cut[i][LEFT] = max(max_cut[i][LEFT], 1 + max_cut[i - 1][RIGHT]); if(i == no_of_trees || height[i] + x[i] < x[i + 1]) max_cut[i][RIGHT] = 1 + max_cut[i][STRAIGHT]; } int answer = max_3(max_cut[no_of_trees][RIGHT], max_cut[no_of_trees][STRAIGHT], max_cut[no_of_trees][LEFT]); printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 19/A Compatible Pair.cpp ================================================ #include using namespace std; int main() { int a_elements, b_elements; scanf("%d %d", &a_elements, &b_elements); vector A(a_elements); for(int i =0; i < a_elements; i++) scanf("%I64d", &A[i]); vector B(b_elements); for(int i = 0; i < b_elements; i++) scanf("%I64d", &B[i]); long long max_product = -1e18; int best_choice_A; for(int i = 0; i < a_elements; i++) { for(int j = 0; j < b_elements; j++) { if(A[i]*1LL*B[j] > max_product) { best_choice_A = i; max_product = A[i]*1LL*B[j]; } } } long long max_product_without_best_A = -1e18; for(int i = 0; i < a_elements; i++) { if(i == best_choice_A) continue; for(int j = 0; j < b_elements; j++) { max_product_without_best_A = max(max_product_without_best_A, A[i]*1LL*B[j]); } } printf("%I64d\n", max_product_without_best_A); return 0; } ================================================ FILE: C Programs/C Programs 19/A Prosperous Lot.cpp ================================================ #include int main() { int no_of_loops; scanf("%d", &no_of_loops); const int MAX_LOOPS = 36; if(no_of_loops > MAX_LOOPS) { printf("-1\n"); return 0; } while(no_of_loops >= 2) { printf("8"); no_of_loops -= 2; } if(no_of_loops == 1) printf("9\n"); return 0; } ================================================ FILE: C Programs/C Programs 19/Almost Identity Permutations.cpp ================================================ #include long long choose(int n, int r) { if(r == 0 || r == n) return 1; if(r == 1 || r == n - 1) return n; return choose(n - 1, r) + choose(n - 1, r - 1); } long long derangements(int n) { if(n == 0) return 1; if(n == 1) return 0; if(n == 2) return 1; return (n - 1)*(derangements(n - 1) + derangements(n - 2)); } int main() { int n, k; scanf("%d %d", &n, &k); long long answer = 0; for(int i = 0; i <= k; i++) { answer += choose(n, i)*derangements(i); } printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 19/Amr and Large Array.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); const int LIMIT = 1e6; vector A(no_of_elements + 1, 0); vector frequency(LIMIT + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); frequency[A[i]]++; } int max_frequency = 0; for(int i = 1; i <= LIMIT; i++) max_frequency = max(max_frequency, frequency[i]); vector rightmost_occurence(LIMIT + 1, 0); for(int i = 1; i <= no_of_elements; i++) rightmost_occurence[A[i]] = i; vector leftmost_occurence(LIMIT + 1, 0); for(int i = no_of_elements; i >= 1; i--) leftmost_occurence[A[i]] = i; int minimum_segment_length = no_of_elements + 1; int answer; for(int i = 1; i <= LIMIT; i++) { if(frequency[i] == max_frequency) { int subsegment_length = rightmost_occurence[i] - (leftmost_occurence[i] - 1); if(subsegment_length < minimum_segment_length) { answer = i; minimum_segment_length = subsegment_length; } } } printf("%d %d\n", leftmost_occurence[answer], rightmost_occurence[answer]); return 0; } ================================================ FILE: C Programs/C Programs 19/Beautiful Sets of Points.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int m, n; scanf("%d %d", &m, &n); int limit = min(m, n) + 1; printf("%d\n", limit); for(int i = 0; i < limit; i++) printf("%d %d\n", i, limit - i - 1); return 0; } ================================================ FILE: C Programs/C Programs 19/Buggy Robot.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_instructions; string instructions; cin >> no_of_instructions >> instructions; int lefts = 0, rights = 0, ups = 0, downs = 0; for(int i = 0; i < no_of_instructions; i++) { lefts += (instructions[i] == 'L'); rights += (instructions[i] == 'R'); downs += (instructions[i] == 'D'); ups += (instructions[i] == 'U'); } int max_correct_instructions = 2*min(lefts, rights) + 2*min(ups, downs); cout << max_correct_instructions; return 0; } ================================================ FILE: C Programs/C Programs 19/Cellular Network.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int number_of_cities, number_of_towers; scanf("%d %d", &number_of_cities, &number_of_towers); vector city(number_of_cities); for(int i = 0; i < number_of_cities; i++) scanf("%d", &city[i]); vector tower(number_of_towers); for(int i = 0; i < number_of_towers; i++) scanf("%d", &tower[i]); int min_range = 0; for(int i = 0; i < number_of_cities; i++) { int position = lower_bound(all(tower), city[i]) - tower.begin(); int closest_tower = 2e9; if(position != number_of_towers) closest_tower = min(closest_tower, abs(tower[position] - city[i])); if(position != 0) closest_tower = min(closest_tower, abs(tower[position - 1] - city[i])); min_range = max(min_range, closest_tower); } printf("%d\n", min_range); return 0; } ================================================ FILE: C Programs/C Programs 19/Coder.cpp ================================================ #include int main() { int no_of_rows; scanf("%d", &no_of_rows); int maximum_pieces = (no_of_rows)*(no_of_rows/2) + (no_of_rows%2)*(no_of_rows/2 + no_of_rows%2); printf("%d\n", maximum_pieces); for(int i = 1; i <= no_of_rows; i++) { if(i%2 == 1) { for(int j = 1; j <= no_of_rows; j++) printf("%c", j%2 == 0 ? '.' : 'C'); } else { for(int j = 1; j <= no_of_rows; j++) printf("%c", j%2 == 0 ? 'C' : '.'); } printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 19/Diversity.cpp ================================================ #include #define NO_OF_ALPHABETS 26 #define MAX_LENGTH 1000 + 5 #define max(a, b) (a > b ? a : b) int main() { char string[MAX_LENGTH]; int min_distinct_characters; scanf("%s %d", string, &min_distinct_characters); int frequency[NO_OF_ALPHABETS] = {0}; for(int i = 0; string[i] != '\0'; i++) { frequency[string[i] - 'a']++; } int no_of_distinct_characters = 0, no_of_changeable_characters = 0; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency[i] > 0) { no_of_distinct_characters++; no_of_changeable_characters += (frequency[i] - 1); //Keep one character } } int minimum_changes = max(min_distinct_characters - no_of_distinct_characters, 0); //printf("NO of changes = %d\n", no_of_changeable_characters); printf(minimum_changes > no_of_changeable_characters ? "impossible\n" : "%d\n",minimum_changes); return 0; } ================================================ FILE: C Programs/C Programs 19/Guest From The Past.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { long long money, plastic_bottle_price, glass_bottle_price, return_amount; scanf("%I64d %I64d %I64d %I64d", &money, &plastic_bottle_price, &glass_bottle_price, &return_amount); long long effective_glass_bottle_price = glass_bottle_price - return_amount; long long no_of_bottles = 0; if(plastic_bottle_price <= effective_glass_bottle_price || glass_bottle_price > money) { no_of_bottles = money/plastic_bottle_price; } else if(effective_glass_bottle_price < plastic_bottle_price && glass_bottle_price <= money) { no_of_bottles = (money - return_amount)/effective_glass_bottle_price; long long remaining_money = money - no_of_bottles*effective_glass_bottle_price; long long remaining_bottles = remaining_money/plastic_bottle_price; no_of_bottles += remaining_bottles; } printf("%I64d\n", no_of_bottles); return 0; } ================================================ FILE: C Programs/C Programs 19/Hamster Farm.cpp ================================================ #include int main() { long long no_of_hamsters; int no_of_boxes; scanf("%I64d %d", &no_of_hamsters, &no_of_boxes); long long leftover_hamsters = 1e18, boxes_bought; int box_type; for(int i = 1; i <= no_of_boxes; i++) { long long box_i; scanf("%I64d", &box_i); if(no_of_hamsters%box_i < leftover_hamsters) { leftover_hamsters = no_of_hamsters%box_i; boxes_bought = no_of_hamsters/box_i; box_type = i; } } printf("%d %I64d\n", box_type, boxes_bought); return 0; } ================================================ FILE: C Programs/C Programs 19/K-Dominant Character.cpp ================================================ #include #include using namespace std; int main() { string S; cin >> S; const int NO_OF_LETTERS = 26; int length = S.size(), answer = S.size(); for(int alphabet = 0; alphabet < NO_OF_LETTERS; alphabet++) { int last_occurence = -1, largest_gap_for_this_alphabet = 0; for(int i = 0; S[i] != '\0'; i++) { if(S[i] == 'a' + alphabet) { largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, i - last_occurence); last_occurence = i; } } largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, length - last_occurence); answer = min(answer, largest_gap_for_this_alphabet); } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 19/Little Artem and Grasshopper.cpp ================================================ #include #define NO_OF_STRIPS 100000 + 2 int main() { int no_of_strips; char strip[NO_OF_STRIPS]; scanf("%d %s", &no_of_strips, strip); int jump[no_of_strips + 1]; int visited[no_of_strips + 1] = {false}; for(int i = 0; i < no_of_strips; i++) scanf("%d", &jump[i]); int square = 0, stuck_forever; while(true) { if(visited[square] == true) { stuck_forever = true; break; } visited[square] = true; if(strip[square] == '<') { if(square - jump[square] < 0) { stuck_forever = false; break; } square -= jump[square]; } else { if(square + jump[square] >= no_of_strips) { stuck_forever = false; break; } square += jump[square]; } } printf(stuck_forever ? "INFINITE\n" : "FINITE\n"); return 0; } ================================================ FILE: C Programs/C Programs 19/Longest K-Good Segment.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, k; scanf("%d %d", &no_of_elements, &k); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); const int MAX = 1e6 + 1; vector frequency(MAX, 0); int left = 1, right = 1, best_left, best_right, distinct_elements = 0, maximum_length = 0; while(right <= no_of_elements) { frequency[element[right]]++; distinct_elements += (frequency[element[right]] == 1); while(distinct_elements > k) { frequency[element[left]]--; distinct_elements -= (frequency[element[left]] == 0); left++; } int current_segment_length = right - (left - 1); if(current_segment_length > maximum_length) { maximum_length = current_segment_length; best_left = left; best_right = right; } right++; } printf("%d %d\n", best_left, best_right); return 0; } ================================================ FILE: C Programs/C Programs 19/Love Triangle.cpp ================================================ #include #include using namespace std; int main() { int no_of_planes; scanf("%d", &no_of_planes); vector liked_by(no_of_planes + 1); for(int i = 1; i <= no_of_planes; i++) scanf("%d", &liked_by[i]); int love_triangle_exists = false; for(int i = 1; i <= no_of_planes; i++) { int a = i; int b = liked_by[a]; int c = liked_by[b]; if(a == liked_by[c]) { love_triangle_exists = true; } } printf(love_triangle_exists ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 19/Nuts.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int k, total_nuts, dividers, capacity; scanf("%d %d %d %d", &k, &total_nuts, ÷rs, &capacity); int boxes_used = 0, nuts_stored_till_here = 0; while(nuts_stored_till_here < total_nuts) { boxes_used++; int dividers_used_in_this_box = min(dividers, k - 1); int nuts_in_this_box = (dividers_used_in_this_box + 1)*capacity; dividers -= dividers_used_in_this_box; nuts_stored_till_here += nuts_in_this_box; } printf("%d\n", boxes_used); return 0; } ================================================ FILE: C Programs/C Programs 19/Palindrome Transformation.cpp ================================================ #include #include #include using namespace std; int main() { int n; string A; int cursor; cin >> n >> cursor >> A; cursor--; n--; cursor = min(cursor, n - cursor); int middle = n/2; int leftmost = cursor, rightmost = cursor; for(int i = cursor; i <= middle; i++) if(A[i] != A[n - i]) rightmost = i; for(int i = cursor; i >= 0; i--) if(A[i] != A[n - i]) leftmost = i; int vertical_moves = 0; for(int i = leftmost; i <= rightmost; i++) vertical_moves += min(abs(A[i] - A[n - i]), 26 - abs(A[i] - A[n - i])); int horizontal_moves = min((cursor - leftmost) + (rightmost - leftmost), (rightmost - cursor) + (rightmost - leftmost)); int total_moves = horizontal_moves + vertical_moves; cout << total_moves; return 0; } ================================================ FILE: C Programs/C Programs 19/Palindromic Supersequence.cpp ================================================ #include #include using namespace std; string reverse(string A) { string rev; for(int i = A.size() - 1; i >= 0; i--) rev += A[i]; return rev; } int main() { string A; cin >> A; string A_rev = reverse(A); string B = A_rev + A; cout << B; return 0; } ================================================ FILE: C Programs/C Programs 19/Recursive Queries.cpp ================================================ #include #include using namespace std; const int LIMIT = 1e6 + 5; int answer[LIMIT][10]; int non_zero_digit_product(int n) { int product = 1; while(n) { product *= (n%10 != 0 ? n%10 : 1); n /= 10; } return product; } void precompute() { vector g(LIMIT, 0); for(int i = 1; i < LIMIT; i++) g[i] = (i < 10 ? i : g[non_zero_digit_product(i)]); for(int i = 1; i < LIMIT; i++) answer[i][0] = 0; for(int i = 1; i < LIMIT; i++) { for(int digit = 1; digit < 10; digit++) { answer[i][digit] = answer[i - 1][digit]; } if(g[i] < 10) answer[i][g[i]]++; } } int main() { precompute(); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int left, right, k; scanf("%d %d %d", &left, &right, &k); printf("%d\n", answer[right][k] - answer[left - 1][k]); } return 0; } ================================================ FILE: C Programs/C Programs 19/Run For Your Prize.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector items(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &items[i]); const int A_POSITION = 1; vector time_A(no_of_elements + 2, 0); for(int i = 1; i <= no_of_elements; i++) time_A[i] = (items[i] - A_POSITION); const int B_POSITION = 1e6; vector time_B(no_of_elements + 2, 0); for(int i = 1; i <= no_of_elements; i++) time_B[i] = (B_POSITION - items[i]); int minimum_time = B_POSITION + A_POSITION; for(int i = 0; i <= no_of_elements; i++) { int time_if_A_picks_first_i = max(time_A[i], time_B[i + 1]); minimum_time = min(minimum_time, time_if_A_picks_first_i); } printf("%d\n", minimum_time); return 0; } ================================================ FILE: C Programs/C Programs 19/Simple Strings.cpp ================================================ #include #include using namespace std; char some_char_other_than(char a, char b) { for(char ch = 'a'; ch <= 'z' ; ch++) if(ch != a && ch != b) return ch; } int main() { string A; cin >> A; string answer; answer += A[0]; for(int i = 1; i < A.size(); i++) { char predecessor = answer[answer.size() - 1]; char successor = (i + 1 == A.size() ? predecessor : A[i + 1]); if(A[i] == predecessor) { answer += some_char_other_than(predecessor, successor); } else { answer += A[i]; } } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 19/The Useless Toy.cpp ================================================ #include #include using namespace std; int main() { map positions; positions['v'] = 0; positions['<'] = 1; positions['^'] = 2; positions['>'] = 3; char start_position, end_position; int no_of_spins; scanf("%c %c %d", &start_position, &end_position, &no_of_spins); int first_position = positions[start_position]; int final_position = positions[end_position]; if( (first_position + no_of_spins%4)%4 == final_position && (first_position + (4 - no_of_spins%4))%4 == final_position) printf("undefined\n"); else if( (first_position + no_of_spins%4)%4 == final_position) printf("cw\n"); else if( (first_position + (4 - no_of_spins%4))%4 == final_position) printf("ccw\n"); else printf("undefined\n"); return 0; } ================================================ FILE: C Programs/C Programs 19/Vasya and Socks.cpp ================================================ #include int main() { int socks, new_sock_day; scanf("%d %d", &socks, &new_sock_day); int no_of_days = 0; while(socks > 0) { no_of_days++; if(no_of_days%new_sock_day == 0) socks++; socks--; } printf("%d\n", no_of_days); return 0; } ================================================ FILE: C Programs/C Programs 19/Watchmen.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_watchmen; scanf("%d", &no_of_watchmen); map x_frequency; map y_frequency; map , int> x_and_y_frequency; for(int i = 1; i <= no_of_watchmen; i++) { int x, y; scanf("%d %d", &x, &y); x_frequency[x]++; y_frequency[y]++; x_and_y_frequency[make_pair(x,y)]++; } long long same_x_pairs = 0; for(map :: iterator it = x_frequency.begin(); it != x_frequency.end(); it++) { long long current_frequency = it->second; same_x_pairs += (current_frequency*(current_frequency - 1))/2; } long long same_y_pairs = 0; for(map :: iterator it = y_frequency.begin(); it != y_frequency.end(); it++) { long long current_frequency = it->second; same_y_pairs += (current_frequency*(current_frequency - 1))/2; } long long same_x_and_y_pairs = 0; for(map , int> :: iterator it = x_and_y_frequency.begin(); it != x_and_y_frequency.end(); it++) { long long current_frequency = it->second; same_x_and_y_pairs += (current_frequency*(current_frequency - 1))/2; } long long answer = same_x_pairs + same_y_pairs - same_x_and_y_pairs; printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 19/Word Correction.cpp ================================================ #include #include using namespace std; int is_vowel(char ch) { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': return true; } return false; } int main() { int length; string text; cin >> length >> text; string final_text; final_text += text[0]; for(int i = 1; i < length; i++) { if(is_vowel(text[i]) && is_vowel(final_text[final_text.size() - 1])) { continue; } final_text += text[i]; } cout << final_text; return 0; } ================================================ FILE: C Programs/C Programs 20/Alena and the Heater.cpp ================================================ #include #include #include #include #define max_4(a, b, c, d) max(max(a, b), max(c, d)) #define min_4(a, b, c, d) min(min(a, b), min(c, d)) #define max_5(a, b, c, d, e) max(max_4(a, b, c, d), e) #define min_5(a, b, c, d, e) min(min_4(a, b, c, d), e) using namespace std; int main() { int length; cin >> length; vector A(length + 1); for(int i = 0; i < length; i++) cin >> A[i]; string B; cin >> B; int left = -1e9, right = 1e9; for(int i = 4; i < length; i++) { if(B[i] == B[i - 1]) continue; if(B[i] == '1') left = max(left, max_5(A[i], A[i - 1], A[i - 2], A[i - 3], A[i - 4]) + 1); if(B[i] == '0') right = min(right, min_5(A[i], A[i - 1], A[i - 2], A[i - 3], A[i - 4]) - 1); } cout << left << " " << right; return 0; } ================================================ FILE: C Programs/C Programs 20/Fafa and Ancient Alphabet.cpp ================================================ #include #include using namespace std; long long power(long long n, long long power, int MOD) { long long result = 1; while(power) { if(power%2 == 1) result = (result*n)%MOD; n = (n*n)%MOD; power = power >> 1; } return result; } long long inverse(long long n, long long m) { return power(n, m - 2, m); } long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { const int MOD = 1e9 + 7; int length, no_of_alphabets; scanf("%d %d", &length, &no_of_alphabets); vector A(length + 1); for(int i = 1; i <= length; i++) scanf("%d", &A[i]); vector B(length + 1); for(int i = 1; i <= length; i++) scanf("%d", &B[i]); int no_of_zeroes = 0; for(int i = 1; i <= length; i++) no_of_zeroes += (A[i] == 0) + (B[i] == 0); const int ANY_WAY = 0, GREATER = 1; typedef vector v_ll; vector no_of_ways(length + 5, v_ll(2, 1)); no_of_ways[length + 1][ANY_WAY] = 1; no_of_ways[length + 1][GREATER] = 0; for(int i = length; i >= 1; i--) { no_of_ways[i][ANY_WAY] = no_of_ways[i + 1][ANY_WAY]; if(A[i] == 0) no_of_ways[i][ANY_WAY] = (no_of_ways[i][ANY_WAY]*no_of_alphabets)%MOD; if(B[i] == 0) no_of_ways[i][ANY_WAY] = (no_of_ways[i][ANY_WAY]*no_of_alphabets)%MOD; if(A[i] == 0 && B[i] == 0) { long long choose_different_alphabets = choose_2(no_of_alphabets); long long choose_same_alphabet = no_of_alphabets; no_of_ways[i][GREATER] = choose_different_alphabets*no_of_ways[i + 1][ANY_WAY] + choose_same_alphabet*no_of_ways[i + 1][GREATER]; } else if(A[i] == 0) { no_of_ways[i][GREATER] = (no_of_alphabets - B[i])*no_of_ways[i + 1][ANY_WAY] + no_of_ways[i + 1][GREATER]; } else if(B[i] == 0) { no_of_ways[i][GREATER] = (A[i] - 1)*no_of_ways[i + 1][ANY_WAY] + no_of_ways[i + 1][GREATER]; } else if(A[i] > B[i]) { no_of_ways[i][GREATER] = no_of_ways[i + 1][ANY_WAY]; } else if(A[i] == B[i]) { no_of_ways[i][GREATER] = no_of_ways[i + 1][GREATER]; } else if(A[i] < B[i]) { no_of_ways[i][GREATER] = 0; } no_of_ways[i][ANY_WAY] %= MOD; no_of_ways[i][GREATER] %= MOD; } long long numerator = no_of_ways[1][GREATER]; long long denominator = power(no_of_alphabets, no_of_zeroes, MOD); long long answer = numerator*inverse(denominator, MOD); answer %= MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 20/Fafa and His Company.cpp ================================================ #include int main() { int n; scanf("%d", &n); int answer = 1; for(int i = 2; i*i <= n; i++) if(n%i == 0) answer += (i*i == n ? 1 : 2); printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 20/Fafa and the Gates.cpp ================================================ #include #include using namespace std; int main() { int no_of_steps; string steps; cin >> no_of_steps >> steps; int x = 0, y = 0, no_of_changes = 0; for(int i = 0; i < no_of_steps - 1; i++) { if(steps[i] == 'U') y++; if(steps[i] == 'R') x++; no_of_changes += (x == y && steps[i] == steps[i + 1]); } cout << no_of_changes; return 0; } ================================================ FILE: C Programs/C Programs 20/Fixing Typos.cpp ================================================ #include #include using namespace std; int main() { string A; cin >> A; string answer; for(int i = 0; i < A.size(); i++) { char last_character, second_last_character, third_last_character; if(answer.size() >= 1) last_character = answer[answer.size() - 1]; if(answer.size() >= 2) second_last_character = answer[answer.size() - 2]; if(answer.size() >= 3) third_last_character = answer[answer.size() - 3]; if(answer.size() >= 2 && A[i] == last_character && last_character == second_last_character) continue; if(answer.size() >= 3 && A[i] == last_character && second_last_character == third_last_character) continue; answer += A[i]; } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 20/Gargari and Bishops.cpp ================================================ #include #include const int WHITE = 1, BLACK = 0, MAX_N = 2015; int points[MAX_N][MAX_N]; long long principal_diagonal_sum[2*MAX_N]; long long secondary_diagonal_sum[2*MAX_N]; int colour(int x, int y) { int sum = x + y; return (sum%2 == 0 ? WHITE : BLACK); } int get_principal_diagonal_no(int x, int y, int n) { return (x - y + n); } int get_secondary_diagonal_no(int x, int y) { return (x + y); } int main() { int n; scanf("%d", &n); memset(principal_diagonal_sum, 0, sizeof(principal_diagonal_sum)); memset(secondary_diagonal_sum, 0, sizeof(secondary_diagonal_sum)); for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { scanf("%d", &points[x][y]); int principal_diagonal_no = get_principal_diagonal_no(x, y, n); int secondary_diagonal_no = get_secondary_diagonal_no(x, y); principal_diagonal_sum[principal_diagonal_no] += points[x][y]; secondary_diagonal_sum[secondary_diagonal_no] += points[x][y]; } } int white_x, white_y; long long white_best = 0; int black_x, black_y; long long black_best = 0; for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { int principal_diagonal_no = get_principal_diagonal_no(x, y, n); int secondary_diagonal_no = get_secondary_diagonal_no(x, y); long long bishop_score = principal_diagonal_sum[principal_diagonal_no] + secondary_diagonal_sum[secondary_diagonal_no] - points[x][y]; if(colour(x, y) == WHITE) { if(bishop_score >= white_best) { white_best = bishop_score, white_x = x, white_y = y; } } else if(colour(x, y) == BLACK) { if(bishop_score >= black_best) { black_best = bishop_score, black_x = x, black_y = y; } } } } long long best = black_best + white_best; printf("%I64d\n", best); printf("%d %d %d %d", white_x, white_y, black_x, black_y); return 0; } ================================================ FILE: C Programs/C Programs 20/Gargari and Permutations Alternate Solution.cpp ================================================ #include #define max(a, b) (a > b ? a : b) const int MAX_N = 1005, MAX_PERMUTATIONS = 5; int P[MAX_PERMUTATIONS + 1][MAX_N], maximum_length_till[MAX_N]; int position[MAX_PERMUTATIONS + 1][MAX_N]; int main() { int no_of_permutations, length; scanf("%d %d", &length, &no_of_permutations); for(int k = 1; k <= no_of_permutations; k++) { for(int i = 1; i <= length; i++) { scanf("%d", &P[k][i]); int element = P[k][i]; position[k][element] = i; } } int answer = 1; for(int i = 1; i <= length; i++) { maximum_length_till[i] = 1; for(int j = 1; j < i; j++) { int current = P[1][i], previous = P[1][j]; int previous_always_before_current = true; for(int k = 1; k <= no_of_permutations; k++) { if(position[k][previous] > position[k][current]) { previous_always_before_current = false; } } if(previous_always_before_current) { maximum_length_till[i] = max(maximum_length_till[i], 1 + maximum_length_till[j]); } } answer = max(answer, maximum_length_till[i]); } printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 20/Gargari and Permutations.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1005, MAX_PERMUTATIONS = 5; int P[MAX_PERMUTATIONS + 1][MAX_N]; int position[MAX_PERMUTATIONS + 1][MAX_N]; vector graph[MAX_N]; int longest_path[MAX_N]; int get_longest_path(int v) { if(longest_path[v] != -1) return longest_path[v]; longest_path[v] = 1; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; longest_path[v] = max(longest_path[v], 1 + get_longest_path(child)); } return longest_path[v]; } int main() { int no_of_permutations, length; scanf("%d %d", &length, &no_of_permutations); for(int k = 1; k <= no_of_permutations; k++) { for(int i = 1; i <= length; i++) { int element; scanf("%d", &element); position[k][element] = i; } } for(int i = 1; i <= length; i++) { for(int j = i + 1; j <= length; j++) { int i_always_before_j = true, j_always_before_i = true; for(int k = 1; k <= no_of_permutations; k++) { if(position[k][i] > position[k][j]) { i_always_before_j = false; } if(position[k][j] > position[k][i]) { j_always_before_i = false; } } if(i_always_before_j) { graph[i].push_back(j); } if(j_always_before_i) { graph[j].push_back(i); } } } memset(longest_path, -1, sizeof(longest_path)); int graph_longest_path = 0; for(int i = 1; i <= length; i++) graph_longest_path = max(graph_longest_path, get_longest_path(i)); printf("%d\n", graph_longest_path); return 0; } ================================================ FILE: C Programs/C Programs 20/Hard Process.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, max_zeroes; scanf("%d %d", &no_of_elements, &max_zeroes); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int no_of_0s = 0; int change_left = 0, change_right = 0, left = 1, right = 1, max_window_size = 0; while(right <= no_of_elements) { if(A[right] == 0) no_of_0s++; while(no_of_0s > max_zeroes) { if(A[left] == 0) no_of_0s--; left++; } int window_size = right - (left - 1); if(window_size > max_window_size) { max_window_size = window_size, change_left = left, change_right = right; } right++; } for(int i = change_left; i <= change_right; i++) A[i] = 1; printf("%d\n", max_window_size); for(int i = 1; i <= no_of_elements; i++) printf("%d ", A[i]); return 0; } ================================================ FILE: C Programs/C Programs 20/Lisa and Dima.cpp ================================================ #include #include using namespace std; int is_prime(int n) { for(int i = 2; i*i <= n; i++) if(n%i == 0) return false; return true; } void sieve(vector &is_prime) { int N = is_prime.size(); is_prime[0] = is_prime[1] = false; for(int i = 2; i*i <= N; i++) { if(is_prime[i]) { for(int multiple = i*i; multiple <= N; multiple += i) { is_prime[multiple] = false; } } } } void break_into_sum_of_primes(int N, int &prime_1, int &prime_2) { vector is_prime(N + 1, true); sieve(is_prime); for(int i = 2; i <= N; i++) { if(is_prime[i] && is_prime[N - i]) { prime_1 = i; prime_2 = N - i; return; } } } int main() { int n; scanf("%d", &n); if(is_prime(n)) { printf("1\n%d\n", n); return 0; } if(is_prime(n - 2)) { printf("2\n%d %d", 2, n - 2); return 0; } int prime_1, prime_2, prime_3; for(int i = n - 4; ; i--) { if(is_prime(i)) { prime_3 = i; break; } } break_into_sum_of_primes(n - prime_3, prime_1, prime_2); printf("3\n%d %d %d\n", prime_1, prime_2, prime_3); return 0; } ================================================ FILE: C Programs/C Programs 20/Love Rescue.cpp ================================================ #include #include using namespace std; const int MAX_N = 26; vector graph[MAX_N]; vector visited(MAX_N, false); vector component[MAX_N] ; void mark(int v, int component_no) { visited[v] = true; component[component_no].push_back(v); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) mark(child, component_no); } } int main() { int length; string A, B; cin >> length >> A >> B; for(int i = 0; i < length; i++) { if(A[i] != B[i]) { graph[A[i] - 'a'].push_back(B[i] - 'a'); graph[B[i] - 'a'].push_back(A[i] - 'a'); } } int component_no = 0, no_of_edges = 0; for(int i = 0; i < MAX_N; i++) { if(graph[i].size() != 0 && !visited[i]) { mark(i, component_no); no_of_edges += component[component_no].size() - 1; component_no++; } } cout << no_of_edges << "\n"; for(int i = 0; i < component_no; i++) { for(int j = 1; j < component[i].size(); j++) { cout << char('a' + component[i][j - 1]) << " " << char('a' + component[i][j]) << "\n"; } } return 0; } ================================================ FILE: C Programs/C Programs 20/Mashmokh and Numbers.cpp ================================================ #include #define min(a, b) (a < b ? a : b) int main() { int n, score; scanf("%d %d", &n, &score); int minimum_score = n/2; if(n == 1 && score == 0) {printf("1\n"); return ;} if(n == 1 || score < minimum_score) { printf("-1\n"); return 0; } int score_except_last_two = (n - 2)/2; int second_term = score - score_except_last_two; printf("%d %d ", second_term, 2*second_term); for(int i = 3; i <= n; i++) printf("%d ", 2*second_term + i); return 0; } ================================================ FILE: C Programs/C Programs 20/Non-Secret Cypher.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements, no_of_equal_elements; scanf("%d %d", &no_of_elements, &no_of_equal_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int left = 1, right = 1; long long no_of_subarrays = 0; map frequency; while(right <= no_of_elements) { frequency[A[right]]++; while(frequency[A[right]] == no_of_equal_elements) { no_of_subarrays += (no_of_elements - right + 1); frequency[A[left]]--; left++; } right++; } printf("%I64d\n", no_of_subarrays); return 0; } ================================================ FILE: C Programs/C Programs 20/Olympiad.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); set awards; for(int i = 1; i <= n; i++) { int score; scanf("%d", &score); if(score > 0) awards.insert(score); } printf("%u\n", awards.size()); return 0; } ================================================ FILE: C Programs/C Programs 20/Partition.cpp ================================================ #include #define abs(x) (x > 0 ? x : -x) int main() { int no_of_elements; scanf("%d", &no_of_elements); int answer = 0; while(no_of_elements--) { int element; scanf("%d", &element); answer += abs(element); } printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 20/Petya and His Friends Alternate Solution.cpp ================================================ #include #include using namespace std; void precompute(vector &primes, int LIMIT) { vector is_prime(LIMIT + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= LIMIT; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] <= LIMIT; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } } int nearest_power_of_2_greater_than(int n) { int power = 1; while(power <= n) power = power << 1; return power; } int is_bit_set(int n, int position) { return ( (n & (1 << position)) != 0); } int main() { const int LIMIT = 300; vector primes; precompute(primes, LIMIT); int n; scanf("%d", &n); if(n == 2) { printf("-1\n"); return 0; } int N = nearest_power_of_2_greater_than(n); vector A(N + 5, 1); int first_free_prime = 0; for(int bit = 0; (1 << bit) < N; bit++) { int set_bit_prime = primes[first_free_prime++]; int unset_bit_prime = primes[first_free_prime++]; for(int i = 1; i <= N; i++) { if(is_bit_set(i, bit)) A[i] *= set_bit_prime; else A[i] *= unset_bit_prime; } } for(int i = 1; 2*i <= N; i++, first_free_prime++) { A[i] *= primes[first_free_prime]; A[(N - 1)^i] *= primes[first_free_prime]; } for(int i = 1; i <= n; i++) printf("%I64d\n", A[i]); return 0; } ================================================ FILE: C Programs/C Programs 20/Petya and His Friends.cpp ================================================ #include int main() { int n; scanf("%d", &n); if(n == 2) { printf("-1\n"); return 0; } printf("6\n10\n15\n"); for(int i = 4; i <= n; i++) { printf("6"); for(int zero = 1; zero <= i - 4 + 1; zero++) printf("0"); printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 20/Phone Numbers.cpp ================================================ #include #include #include using namespace std; int main() { int length, answer_length; string A; cin >> length >> answer_length >> A; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < A.size(); i++) present[A[i] - 'a'] = true; char smallest_alphabet; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(present[i]) { smallest_alphabet = 'a' + i; break; } } if(answer_length > length) { cout << A; for(int i = A.size(); i < answer_length; i++) cout << smallest_alphabet; return 0; } int first_change_point, greater_char_available = false; char char_at_first_change_point; for(int i = answer_length - 1; i >= 0 && !greater_char_available; i--) { for(char alphabet = A[i] + 1; alphabet <= 'z'; alphabet++) { if(present[alphabet - 'a']) { greater_char_available = true; first_change_point = i; char_at_first_change_point = alphabet; break; } } } for(int i = 0; i < first_change_point; i++) cout << A[i]; cout << char_at_first_change_point; for(int i = first_change_point + 1; i < answer_length; i++) cout << smallest_alphabet; return 0; } ================================================ FILE: C Programs/C Programs 20/Pocket Book.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_names, length; cin >> no_of_names >> length; set distinct_characters[length]; while(no_of_names--) { string name; cin >> name; for(int i = 0; i < length; i++) distinct_characters[i].insert(name[i]); } const int MOD = 1e9 + 7; long long total_strings = 1; for(int i = 0; i < length; i++) { total_strings = (total_strings*distinct_characters[i].size())%MOD; } cout << total_strings; return 0; } ================================================ FILE: C Programs/C Programs 20/Points on the Line.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int n, d; scanf("%d %d", &n, &d); vector A(n + 1, 0); for(int i = 1; i <= n; i++) scanf("%d", &A[i]); sort(all(A)); int removed_elements = n; for(int i = 1; i <= n; i++) { int removed_elements_to_start_at_i = i - 1, j = i; while(j <= n && A[j] - A[i] <= d) j++; removed_elements_to_start_at_i += (n - j + 1); removed_elements = min(removed_elements, removed_elements_to_start_at_i); } printf("%d\n", removed_elements); return 0; } ================================================ FILE: C Programs/C Programs 20/Protect Sheep.cpp ================================================ #include int main() { int rows, columns; scanf("%d %d", &rows, &columns); char pasture[rows + 5][columns + 5]; for(int r = 1; r <= rows; r++) scanf("%s", pasture[r] + 1); int is_possible = true; for(int r = 1; r <= rows; r++) { for(int c = 1; c <= columns; c++) { if(pasture[r][c] == 'W') { if(pasture[r + 1][c] == 'S' || pasture[r][c + 1] == 'S' || pasture[r - 1][c] == 'S' || pasture[r][c - 1] == 'S') { is_possible = false; } } } } if(!is_possible) { printf("No\n"); return 0; } printf("Yes\n"); for(int r = 1; r <= rows; r++) { for(int c = 1; c <= columns; c++) { char current_cell = (pasture[r][c] == '.' ? 'D' : pasture[r][c]); printf("%c", current_cell); } printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 20/String Transformation.cpp ================================================ #include using namespace std; int main() { string S; cin >> S; int last_found = 'a' - 1; for(int i = 0; i < S.size() && last_found < 'z'; i++) { if(S[i] <= last_found + 1) { S[i] = last_found + 1; last_found = S[i]; } } cout << (last_found == 'z' ? S : "-1"); return 0; } ================================================ FILE: C Programs/C Programs 20/Sum and Replace.cpp ================================================ #include #include #define LEFT(n) ( (n << 1) ) #define RIGHT(n) ( (n << 1)|1 ) using namespace std; const int MAX_N = 1e6 + 10, MAX_ELEMENTS = 5e5 + 6; vector no_of_divisors(MAX_N, 0); int max_tree[3*MAX_ELEMENTS]; long long sum_tree[3*MAX_ELEMENTS]; int A[MAX_ELEMENTS]; void precompute_divisors() { vector largest_prime_factor(MAX_N, 0); no_of_divisors[1] = 1; for(int i = 2; i < MAX_N; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple < MAX_N; multiple += i) { largest_prime_factor[multiple] = i; } } int exponent = 0, reduced_i = i; while(reduced_i%largest_prime_factor[i] == 0) { reduced_i /= largest_prime_factor[i]; exponent++; } no_of_divisors[i] = (exponent + 1)*no_of_divisors[reduced_i]; } } void build(int n, int left, int right) { if(left == right) { max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } long long get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; long long left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); long long right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } void update(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || max_tree[n] <= 2) return; if(left == right) { A[left] = no_of_divisors[A[left]]; max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, query_left, query_right); update(RIGHT(n), mid + 1, right, query_left, query_right); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int main() { precompute_divisors(); int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); build(1, 1, no_of_elements); while(no_of_queries--) { const int SUM = 2, REPLACE = 1; int query_type, left, right; scanf("%d %d %d", &query_type, &left, &right); if(query_type == SUM) { long long sum = get_sum(1, 1, no_of_elements, left, right); printf("%I64d\n", sum); } else if(query_type == REPLACE) { update(1, 1, no_of_elements, left, right); } } return 0; } ================================================ FILE: C Programs/C Programs 20/Vile Grasshoppers.cpp ================================================ #include int main() { int p, y; scanf("%d %d", &p, &y); int answer = y; while(answer > p) { int coprime_till_p = true; for(int i = 2; i <= p && i*i <= y; i++) { if(answer%i == 0) { coprime_till_p = false; break; } } if(coprime_till_p) break; answer--; } printf("%d\n", answer == p ? -1 : answer); return 0; } ================================================ FILE: C Programs/C Programs 20/Weird Subtraction Process.cpp ================================================ #include using namespace std; int main() { long long a, b; cin >> a >> b; while(a != 0 && b != 0 && (a >= 2*b || b >= 2*a)) { if(a >= 2*b) { a %= (2*b); } else if(b >= 2*a) { b %= (2*a); } } cout << a << " " << b; return 0; } ================================================ FILE: C Programs/C Programs 21/Aramic Script Bitmask Solution.cpp ================================================ #include #include using namespace std; int main() { int no_of_words; cin >> no_of_words; set mask; while(no_of_words--) { string word; cin >> word; int current_mask = 0; for(int i = 0; i < word.size(); i++) current_mask |= (1 << (word[i] - 'a')); mask.insert(current_mask); } cout << mask.size(); return 0; } ================================================ FILE: C Programs/C Programs 21/Aramic Script.cpp ================================================ #include #include #include #include #include #define all (v) (v).begin(), (v).end() using namespace std; int main() { int no_of_words; cin >> no_of_words; set distinct_words; while(no_of_words--) { string word; cin >> word; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < word.size(); i++) present[word[i] - 'a'] = true; string root; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(present[i]) root += (char)('a' + i); distinct_words.insert(root); } cout << distinct_words.size(); return 0; } ================================================ FILE: C Programs/C Programs 21/Arithmetic Progression.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_cards; scanf("%d", &no_of_cards); vector card(no_of_cards); for(int i = 0; i < no_of_cards; i++) scanf("%d", &card[i]); if(no_of_cards == 1) { printf("-1\n"); return 0; } vector new_cards; if(no_of_cards == 2 && (card[0] != card[1]) && (card[0] + card[1])%2 == 0) { new_cards.push_back( (card[0] + card[1])/2 ); } sort(all(card)); int min_difference = card[1] - card[0]; for(int i = 2; i < no_of_cards; i++) min_difference = min(min_difference, card[i] - card[i - 1]); int ap_possible = true, new_middle_cards = 0; for(int i = 1; i < no_of_cards; i++) { if(card[i] - card[i - 1] != min_difference) { if(card[i] - card[i - 1] == 2*min_difference) { new_middle_cards++; } else { ap_possible = false; } } } if(ap_possible) { if(min_difference == 0) { new_cards.push_back(card[0]); } else if(new_middle_cards == 0) { new_cards.push_back(card[0] - min_difference); new_cards.push_back(card[no_of_cards - 1] + min_difference); } else if(new_middle_cards == 1) { for(int i = 1; i < no_of_cards; i++) if(card[i] - card[i - 1] == 2*min_difference) new_cards.push_back(card[i - 1] + min_difference); } } sort(all(new_cards)); printf("%d\n", new_cards.size()); for(int i = 0; i < new_cards.size(); i++) printf("%d ", new_cards[i]); return 0; } ================================================ FILE: C Programs/C Programs 21/Bash and a Tough Math Puzzle.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 5e5 + 15, NOT_FOUND = -1; int gcd_tree[3*MAX_N], A[MAX_N], no_of_elements; int gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } void build(int n, int left, int right) { if(left == right) { gcd_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); gcd_tree[n] = gcd(gcd_tree[LEFT(n)], gcd_tree[RIGHT(n)]); } void update(int n, int left, int right, int index, int value) { if(right < index || index < left) return; if(left == right) { gcd_tree[n] = value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, index, value); update(RIGHT(n), mid + 1, right, index, value); gcd_tree[n] = gcd(gcd_tree[LEFT(n)], gcd_tree[RIGHT(n)]); } int get_first_indivisible_element(int n, int left, int right, int query_left, int query_right, int x) { if(gcd_tree[n]%x == 0 || right < query_left || query_right < left || right < left || query_right < query_left) return NOT_FOUND; if(left == right) //Leaf node and it's not divisible. So, it has to be this element. return left; int mid = (left + right) >> 1; int left_answer = get_first_indivisible_element(LEFT(n), left, mid, query_left, query_right, x); if(left_answer != NOT_FOUND) return left_answer; int right_answer = get_first_indivisible_element(RIGHT(n), mid + 1, right, query_left, query_right, x); return right_answer; } void solve() { const int GUESS_GCD = 1, UPDATE = 2; int query_type; scanf("%d ", &query_type); if(query_type == GUESS_GCD) { int left, right, x; scanf("%d %d %d", &left, &right, &x); int first_indivisible_element = get_first_indivisible_element(1, 1, no_of_elements, left, right, x); if(first_indivisible_element == NOT_FOUND) //Entire range divisible by x. { printf("YES\n"); } else if(first_indivisible_element != NOT_FOUND) //If 2 elements are not divisible by x, answer is NO. Else, if it is <= 1, answer is YES { int second_indivisible_element = get_first_indivisible_element(1, 1, no_of_elements, first_indivisible_element + 1, right, x); printf(second_indivisible_element == NOT_FOUND ? "YES\n" : "NO\n"); } } else if(query_type == UPDATE) { int index, value; scanf("%d %d", &index, &value); update(1, 1, no_of_elements, index, value); } } int main() { scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); build(1, 1, no_of_elements); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 21/Consecutive Subsequences.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int last_element, longest_sequence = 0; map answer_with_last_element; for(int i = 1; i <= no_of_elements; i++) { answer_with_last_element[A[i]] = 1 + answer_with_last_element[A[i] - 1]; if(answer_with_last_element[A[i]] > longest_sequence) { longest_sequence = answer_with_last_element[A[i]]; last_element = A[i]; } } vector index; for(int i = 1; i <= no_of_elements; i++) { if(index.size() == 0) { if(A[i] == last_element - longest_sequence + 1) index.push_back(i); } else if(A[i] == A[index.back()] + 1) { index.push_back(i); } } printf("%d\n", longest_sequence); for(int i = 0; i < longest_sequence; i++) printf("%d ", index[i]); return 0; } ================================================ FILE: C Programs/C Programs 21/Cyclic Components.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 2e5 + 15, UNMARKED = -1; vector graph[MAX_N]; vector component[MAX_N]; int component_no[MAX_N]; void dfs_and_mark_component(int v, int no) { component[no].push_back(v); component_no[v] = no; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(component_no[child] == UNMARKED) dfs_and_mark_component(child, no); } } int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } memset(component_no, UNMARKED, sizeof(component_no)); int no_of_components = 0; for(int i = 1; i <= no_of_vertices; i++) { if(component_no[i] == UNMARKED) dfs_and_mark_component(i, no_of_components++); } int no_of_cycles = 0; for(int i = 0; i < no_of_components; i++) { int is_cycle = true; for(int j = 0; j < component[i].size(); j++) { int v = component[i][j]; if(graph[v].size() != 2) { is_cycle = false; } } no_of_cycles += (is_cycle == true); } printf("%d\n", no_of_cycles); return 0; } ================================================ FILE: C Programs/C Programs 21/Divide by Three, Multiply by Two Alternate Solution.cpp ================================================ #include #include #include typedef unsigned long long ULL; using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); map present; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64u", &A[i]); present[A[i]] = true; } ULL first_element; for(int i = 1; i <= no_of_elements; i++) { int comes_from_multiplication = (A[i]%2 == 0 && present[A[i]/2]); int comes_from_division = (A[i] <= 1e18 && present[3*A[i]]); if(!comes_from_multiplication && !comes_from_division) { first_element = A[i]; } } vector solution; solution.push_back(first_element); while(solution.size() < no_of_elements) { ULL last_element = solution.back(); if(last_element%3 == 0 && present[last_element/3]) { solution.push_back(last_element/3); } else { solution.push_back(2*last_element); } } for(int i = 0; i < no_of_elements; i++) printf("%I64u ", solution[i]); return 0; } ================================================ FILE: C Programs/C Programs 21/Divide by Three, Multiply by Two.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct info { int two, three; unsigned long long number; }; int compare(const info &A, const info &B) { if(A.two - A.three < B.two - B.three) return true; else return false; } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { unsigned long long element; scanf("%I64u", &element); A[i].number = element; A[i].two = 0, A[i].three = 0; while(element%2 == 0) A[i].two++, element /= 2; while(element%3 == 0) A[i].three++, element /= 3; } sort(all(A), compare); for(int i = 0; i < no_of_elements; i++) printf("%I64u ", A[i].number); return 0; } ================================================ FILE: C Programs/C Programs 21/Dreamoon and Sets.cpp ================================================ #include int main() { int no_of_sets, k; scanf("%d %d", &no_of_sets, &k); int maximum_number = (6*(no_of_sets - 1) + 5)*k; printf("%d\n", maximum_number); for(int i = 0; i < no_of_sets; i++) { const int NO_OF_TERMS = 4; int mod[NO_OF_TERMS] = {1, 2, 3, 5}; for(int m = 0; m < NO_OF_TERMS; m++) { int term = (6*i + mod[m])*k; printf("%d ", term); } printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 21/File Name.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; int removable_characters = 0; for(int i = 2; i < length; i++) removable_characters += (S[i] == 'x' && S[i - 1] == 'x' && S[i - 2] == 'x'); cout << removable_characters; return 0; } ================================================ FILE: C Programs/C Programs 21/Fox and Box Accumulation.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int is_possible(vector &strength, int no_of_piles) { priority_queue pile_tops; int box_ptr = strength.size() - 1; for(int i = 1; i <= no_of_piles; i++) pile_tops.push(strength[box_ptr--]); while(box_ptr >= 0) { int strongest_pile = pile_tops.top(); pile_tops.pop(); if(strongest_pile == 0) return false; int next_box = strength[box_ptr]; pile_tops.push(min(strongest_pile - 1, next_box)); box_ptr--; } return true; } int main() { int no_of_boxes; scanf("%d", &no_of_boxes); vector strength(no_of_boxes); for(int i = 0; i < no_of_boxes; i++) scanf("%d", &strength[i]); sort(all(strength)); int left = 1, right = no_of_boxes, answer; while(left <= right) { int mid = (left + right) >> 1; if(is_possible(strength, mid)) { if(mid == 1 || !is_possible(strength, mid - 1)) { answer = mid; break; } else { right = mid - 1; } } else { left = mid + 1; } } printf("%d", answer); return 0; } ================================================ FILE: C Programs/C Programs 21/Ghosts.cpp ================================================ #include #include using namespace std; int main() { int no_of_points, a, b; scanf("%d %d %d", &no_of_points, &a, &b); long long total_collisions = 0; map < pair, int > slope_count; map intersections; for(int i = 1; i <= no_of_points; i++) { int x, vx, vy; scanf("%d %d %d", &x, &vx, &vy); total_collisions += intersections[a*1LL*vx - vy] - slope_count[make_pair(vx, vy)]; //Parallel points don't meet. slope_count[make_pair(vx, vy)]++; intersections[a*1LL*vx - vy]++; } total_collisions *= 2; printf("%I64d\n", total_collisions); return 0; } ================================================ FILE: C Programs/C Programs 21/Less or Equal.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, position; scanf("%d %d", &no_of_elements, &position); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); sort(all(A)); int answer; if(position == 0) { answer = (A[1] > 1 ? 1 : -1); } else { answer = (position < no_of_elements && A[position] == A[position + 1] ? -1 : A[position]); } printf("%d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 21/Little Girl and Maximum XOR.cpp ================================================ #include long long all_ones(int n) { return (1LL << (n + 1)) - 1; } int main() { long long left, right; scanf("%I64d %I64d", &left, &right); if(left == right) { printf("0\n"); return 0; } int largest_unequal_bit_position; for(int i = 0; left > 0 || right > 0; i++) { if(left%2 != right%2) largest_unequal_bit_position = i; left >>= 1; right >>= 1; } long long answer = all_ones(largest_unequal_bit_position); //This gives a number consisting of n 1's in binary printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 21/Lucky Sum of Digits.cpp ================================================ #include int main() { int sum; scanf("%d", &sum); int possible = false; int no_of_4s = 0, no_of_7s = sum/7; while(no_of_7s >= 0) { if( (sum - 7*no_of_7s)%4 == 0) { no_of_4s = (sum - 7*no_of_7s)/4; possible = true; break; } no_of_7s--; } if(!possible) { printf("-1\n"); return 0; } for(int i = 1; i <= no_of_4s; i++) printf("4"); for(int i = 1; i <= no_of_7s; i++) printf("7"); return 0; } ================================================ FILE: C Programs/C Programs 21/Mahmoud and Ehab and another array construction task.cpp ================================================ #include #include using namespace std; void sieve(vector &is_prime, int LIMIT) { is_prime[0] = is_prime[1] = false; for(long long i = 2; i*i <= LIMIT; i++) { if(is_prime[i]) { for(long long multiple = i*i; multiple <= LIMIT; multiple += i) { is_prime[multiple] = false; } } } } int all_prime_factors_available(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { if(used[p] == true) return false; n /= p; } } if(n > 1 && used[n]) return false; return true; } void mark_prime_factors(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { used[p] = true; n /= p; } } if(n > 1) used[n] = true; } int main() { const int LIMIT = 2e6; vector is_prime(LIMIT, true); sieve(is_prime, LIMIT); int no_of_elements; scanf("%d", &no_of_elements); vector original(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original[i]); vector solution; vector used(LIMIT, false); for(int i = 0; i < no_of_elements; i++) { if(all_prime_factors_available(original[i], used)) { solution.push_back(original[i]); mark_prime_factors(original[i], used); } else { int x = original[i] + 1; while(!all_prime_factors_available(x, used)) x++; mark_prime_factors(x, used); solution.push_back(x); break; } } for(int i = 2; i < LIMIT && solution.size() < no_of_elements; i++) { //printf("i = %d, u %d, p %d\n", i, used[i], is_prime[i]); if(!used[i] && is_prime[i]) solution.push_back(i); } for(int i = 0; i < no_of_elements; i++) printf("%d ", solution[i]); return 0; } ================================================ FILE: C Programs/C Programs 21/Mahmoud and Ehab and Even Odd Game.cpp ================================================ #include int main() { int n; scanf("%d", &n); printf(n%2 == 0 ? "Mahmoud\n" : "Ehab\n"); return 0; } ================================================ FILE: C Programs/C Programs 21/Mahmoud and a Triangle.cpp ================================================ #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() int main() { int no_of_sides; cin >> no_of_sides; const int FIBO_LIMIT_MAX_SIDES = 45; if(no_of_sides > FIBO_LIMIT_MAX_SIDES) { cout << "YES\n"; return 0; } vector side(no_of_sides); for(int i = 0; i < no_of_sides; i++) cin >> side[i]; sort(all(side)); int triangle_possible = false; for(int i = no_of_sides - 1; i >= 2; i--) { if(side[i] < side[i - 1] + side[i - 2]) { triangle_possible = true; break; } } cout << (triangle_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 21/Make a Square Alternate Solution.cpp ================================================ #include int no_of_digits(int n) { int digits = 0; while(n) { n /= 10; digits++; } return digits; } long long square(long long n) { return n*n; } int is_subsequence(int sequence, int n) { while(sequence > 0 && n > 0) { if(n%10 == sequence%10) { sequence /= 10; if(sequence == 0) return true; } n /= 10; } return false; } int main() { int n; scanf("%d", &n); int digit_count = no_of_digits(n), maximum_digits = 0; for(int i = 0; square(i) <= n; i++) { if(is_subsequence(square(i), n) && no_of_digits(square(i)) > maximum_digits) { maximum_digits = no_of_digits(square(i)); } } int deleted_digits = digit_count - maximum_digits; printf(deleted_digits == digit_count ? "-1\n" : "%d\n", deleted_digits); return 0; } ================================================ FILE: C Programs/C Programs 21/Make a Square.cpp ================================================ #include int is_bit_set(int n, int position) { return ( ( (1LL << position)&n ) != 0); } int no_of_ones(int n) { int ones = 0; while(n) { if(n&1) ones++; n >>= 1; } return ones; } int no_of_digits(int n) { int digits = 0; while(n) { n /= 10; digits++; } return digits; } long long square(long long n) { return n*n; } int is_square(int n) { int left = 0, right = 1e5, mid = (left + right) >> 1; while(left <= right) { mid = (left + right) >> 1; if(square(mid) <= n) { if(square(mid + 1) > n) { break; } else { left = mid + 1; } } else { right = mid - 1; } } return (square(mid) == n); } int main() { int n; scanf("%d", &n); int digit_count = no_of_digits(n), maximum_digits = 0; int digit[11]; for(int i = 0; i < digit_count; i++, n /= 10) digit[i] = n%10; for(int mask = (1 << digit_count) - 1; mask > 0; mask--) { int number = 0; for(int i = digit_count - 1; i >= 0; i--) { if(is_bit_set(mask, i)) number = number*10 + digit[i]; } if(is_square(number) && no_of_digits(number) > maximum_digits) maximum_digits = no_of_digits(number); } int deleted_digits = digit_count - maximum_digits; printf(deleted_digits == digit_count ? "-1\n" : "%d\n", deleted_digits); return 0; } ================================================ FILE: C Programs/C Programs 21/Mancala.cpp ================================================ #include #include using namespace std; long long score_by_distributing(int chosen, vector stone, int no_of_holes) { int quotient = stone[chosen]/no_of_holes, remainder = stone[chosen]%no_of_holes; stone[chosen] = 0; int current = chosen; do { stone[current] += quotient; current = (current + 1)%no_of_holes; } while(current != chosen); current = (chosen + 1)%no_of_holes; while(remainder > 0) { stone[current]++; remainder--; current = (current + 1)%no_of_holes; } long long score = 0; for(int i = 0; i < stone.size(); i++) if(stone[i]%2 == 0) score += stone[i]; return score; } int main() { const int NO_OF_HOLES = 14; vector stone(NO_OF_HOLES); for(int i = 0; i < NO_OF_HOLES; i++) cin >> stone[i]; long long maximum_score = 0; for(int i = 0; i < NO_OF_HOLES; i++) maximum_score = max(maximum_score, score_by_distributing(i, stone, NO_OF_HOLES)); cout << maximum_score; return 0; } ================================================ FILE: C Programs/C Programs 21/Mentors.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_programmers, no_of_pairs; scanf("%d %d", &no_of_programmers, &no_of_pairs); vector skill(no_of_programmers + 1, 0); for(int i = 1; i <= no_of_programmers; i++) scanf("%d", &skill[i]); vector sorted_skill(no_of_programmers + 1, 0); for(int i = 1; i <= no_of_programmers; i++) sorted_skill[i] = skill[i]; sort(all(sorted_skill)); vector no_of_juniors(no_of_programmers + 1); for(int i = 1; i <= no_of_programmers; i++) { no_of_juniors[i] = upper_bound(all(sorted_skill), skill[i] - 1) - sorted_skill.begin() - 1; } for(int i = 1; i <= no_of_pairs; i++) { int u, v; scanf("%d %d", &u, &v); if(skill[u] > skill[v]) { no_of_juniors[u]--; } else if(skill[v] - skill[u]) { no_of_juniors[v]--; } } for(int i = 1; i <= no_of_programmers; i++) printf("%d ", no_of_juniors[i]); return 0; } ================================================ FILE: C Programs/C Programs 21/Pairs of Lines.cpp ================================================ #include #include using namespace std; struct Point{ long long x, y; }; int is_on_line(Point a, Point b, Point c) { //Checking slope product to avoid division return ( (c.y - b.y)*(b.x - a.x) == (b.y - a.y)*(c.x - b.x) ); } int check_line(vector &line) { for(int i = 2; i < line.size(); i++) if(!is_on_line(line[0], line[1], line[i])) return false; return true; } int check_one_line_passing_through(int a, int b, vector &P) { vector line_2; for(int i = 1; i < P.size(); i++) { if(!is_on_line(P[a], P[b], P[i])) line_2.push_back(P[i]); } int two_lines_possible = check_line(line_2); return two_lines_possible; } int main() { int no_of_points; scanf("%d", &no_of_points); vector P(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) scanf("%I64d %I64d", &P[i].x, &P[i].y); int two_lines_possible = (no_of_points <= 4 || check_one_line_passing_through(1, 2, P) || check_one_line_passing_through(2, 3, P) || check_one_line_passing_through(3, 1, P)); printf(two_lines_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 21/Two Gram.cpp ================================================ #include #include #include using namespace std; int main() { int length; string S; cin >> length >> S; map frequency; int max_frequency = 0; string answer; for(int i = 0; i + 1 < length; i++) { string two_gram = S.substr(i, 2); frequency[two_gram]++; if(frequency[two_gram] > max_frequency) max_frequency = frequency[two_gram], answer = two_gram; } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 21/Valhalla Seige.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_soldiers, no_of_queries; scanf("%d %d", &no_of_soldiers, &no_of_queries); vector strength(no_of_soldiers + 1); for(int i = 1; i <= no_of_soldiers; i++) scanf("%I64d", &strength[i]); vector sum(no_of_soldiers + 1, 0); for(int i = 1; i <= no_of_soldiers; i++) sum[i] = sum[i - 1] + strength[i]; long long total_arrows = 0; while(no_of_queries--) { long long arrows; scanf("%I64d", &arrows); total_arrows += arrows; if(total_arrows >= sum[no_of_soldiers]) total_arrows = 0; int no_of_dead_soldiers = upper_bound(all(sum), total_arrows) - sum.begin() - 1; int no_of_alive_soldiers = no_of_soldiers - no_of_dead_soldiers; printf("%d\n", no_of_alive_soldiers); } return 0; } ================================================ FILE: C Programs/C Programs 21/Wrong Subtraction.cpp ================================================ #include int main() { int n, no_of_operations; scanf("%d %d", &n, &no_of_operations); while(no_of_operations--) { n = (n%10 == 0 ? n/10 : n - 1); } printf("%d\n", n); return 0; } ================================================ FILE: C Programs/C Programs 22/AND Graph.cpp ================================================ #include #include using namespace std; const int MAX_N = (1LL << 22); vector visited(MAX_N, false); vector is_present(MAX_N, false); int complement(int x, int no_of_bits) { return ( ( (1LL << no_of_bits) - 1) - x); } void dfs(int mask, int no_of_bits) { if(visited[mask]) return; visited[mask] = true; for(int bit = 0; bit < no_of_bits; bit++) { if(mask&(1LL << bit)) { int submask = mask - (1LL << bit); dfs(submask, no_of_bits); } } if(is_present[mask]) dfs(complement(mask, no_of_bits), no_of_bits); } int main() { int no_of_bits, no_of_vertices; scanf("%d %d", &no_of_bits, &no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { int x; scanf("%d", &x); is_present[x] = true; } int no_of_components = 0; for(int i = 0; i < (1LL << no_of_bits); i++) { if(is_present[i] && !visited[i]) { dfs(complement(i, no_of_bits), no_of_bits); no_of_components++; } } printf("%d\n", no_of_components); return 0; } ================================================ FILE: C Programs/C Programs 22/Almost Arithmetic Progression.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &A[i]); const int oo = 1e7; int add[3] = {-1, 0, 1}, min_operations = oo; for(int i = 0; i < 3; i++) { int term_1 = A[0] + add[i]; for(int j = 0; j < 3; j++) { int term_2 = A[1] + add[j]; int difference = term_2 - term_1; int no_of_operations = (term_1 != A[0]) + (term_2 != A[1]); for(int k = 2; k < no_of_elements; k++) { if(abs(term_1 + k*difference - A[k]) == 1) { no_of_operations++; } else if(abs(term_1 + k*difference - A[k]) > 1) { no_of_operations = oo; } } min_operations = min(min_operations, no_of_operations); } } printf("%d\n", min_operations >= oo ? -1 : min_operations); return 0; } ================================================ FILE: C Programs/C Programs 22/Antipalindrome Alternate Solution.cpp ================================================ #include #include using namespace std; int is_palindrome(string S, int left, int right) { while(left <= right) { if(S[left++] != S[right--]) return false; } return true; } int main() { string S; cin >> S; int length = S.size(); if(!is_palindrome(S, 0, length - 1)) cout << length; else if(!is_palindrome(S, 0, length - 2) || !is_palindrome(S, 1, length - 1)) cout << length - 1; else cout << "0"; return 0; } ================================================ FILE: C Programs/C Programs 22/Antipalindrome.cpp ================================================ #include using namespace std; int is_palindrome(string S) { for(int i = 0; i < S.size(); i++) if(S[i] != S[S.size() - 1 - i]) return false; return true; } int main() { string S; cin >> S; for(int length = S.size(); length >= 1; length--) { for(int i = 0; i + length - 1 < S.size(); i++) { if(!is_palindrome(S.substr(i, length))) { cout << length; return 0; } } } cout << "0"; return 0; } ================================================ FILE: C Programs/C Programs 22/Ball.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin() + 1, (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; const int MAX_N = 5e5 + 15; int max_tree[3*MAX_N]; struct info { int beauty, richness, intellect; }; int sort_by_beauty(info &A, info &B) { return (A.beauty < B.beauty); } void insert_richness(int n, int left, int right, int index, int value) { if(index < left || right < index) return; if(left == right) { max_tree[n] = max(max_tree[n], value); return ; } int mid = (left + right) >> 1; insert_richness(LEFT(n), left, mid, index, value); insert_richness(RIGHT(n), mid + 1, right, index, value); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } int get_max_richness(int n, int left, int right, int query_left, int query_right) { if(right < query_left || query_right < left || right < left) return 0; if(query_left <= left && right <= query_right) return max_tree[n]; int mid = (left + right) >> 1; int left_max = get_max_richness(LEFT(n), left, mid, query_left, query_right); int right_max = get_max_richness(RIGHT(n), mid + 1, right, query_left, query_right); return max(left_max, right_max); } int main() { int no_of_ladies; scanf("%d", &no_of_ladies); vector lady(no_of_ladies + 1); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].beauty); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].richness); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].intellect); sort(all(lady), sort_by_beauty); vector intelligence(no_of_ladies + 1, 0); for(int i = 1; i <= no_of_ladies; i++) intelligence[i] = lady[i].intellect; sort(all(intelligence)); map iq_rank; for(int i = 1; i <= no_of_ladies; i++) { iq_rank[intelligence[i]] = (intelligence[i] == intelligence[i - 1] ? iq_rank[intelligence[i - 1]] : i); } memset(max_tree, 0, sizeof(max_tree)); int suicides = 0; for(int i = no_of_ladies; i >= 1; ) { int j; for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { int max_richness_with_other_2_greater = get_max_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect] + 1, no_of_ladies); if(max_richness_with_other_2_greater > lady[j].richness) suicides++; } for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { insert_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect], lady[j].richness); } i = j; } printf("%d", suicides); return 0; } ================================================ FILE: C Programs/C Programs 22/Bits.cpp ================================================ #include long long all_ones(int n) { return (1LL << n) - 1; } int is_set(long long n, int bit) { return ((n & (1LL << bit)) != 0); } int no_of_bits(long long n) { int answer = 0; while(n) { n >>= 1; answer++; } return answer; } void solve() { long long left, right; scanf("%I64d %I64d", &left, &right); long long answer = 0; if(all_ones(no_of_bits(right)) == right) { answer = right; } else if(no_of_bits(left) != no_of_bits(right)) { answer = all_ones(no_of_bits(right) - 1); } else if(no_of_bits(left) == no_of_bits(right)) { for(int bit = 63; bit >= 0; bit--) { if(is_set(left, bit) && is_set(right, bit)) { answer |= (1LL << bit); } else if(!is_set(left, bit) && is_set(right, bit)) //If L[i] = 0, and R[i] = 1 { answer |= all_ones(bit); //Setting the current bit to 0, and then padding with 1s till the end. if((answer|(1LL << bit)) <= right) //Checking if the current bit can also be 1 answer |= (1LL << bit); } } } printf("%I64d\n", answer); } int main() { int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 22/Bookshelves.cpp ================================================ #include #include const int MAX_BIT = 61, MAX_N = 55; typedef long long LL; int no_of_elements, no_of_parts; LL A[MAX_N], sum[MAX_N]; int possible[MAX_N][MAX_N]; int is_possible(LL goal) { memset(possible, false, sizeof(possible)); possible[0][0] = true; for(int part = 1; part <= no_of_parts; part++) { for(int right = 1; right <= no_of_elements; right++) { for(int left = 0; left < right; left++) { if( possible[left][part - 1] && ( ( (sum[right] - sum[left])&goal ) == goal ) ) { possible[right][part] = true; break; } } } } return possible[no_of_elements][no_of_parts]; } int main() { scanf("%d %d", &no_of_elements, &no_of_parts); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); sum[0] = 0; for(int i = 1; i <= no_of_elements; i++) sum[i] = sum[i - 1] + A[i]; LL answer = 0; for(int bit = MAX_BIT; bit >= 0; bit--) { if(is_possible(answer|(1LL << bit))) { answer |= (1LL << bit); } } printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 22/Businessman Problems.cpp ================================================ #include #include using namespace std; int main() { int a_element_is; scanf("%d", &a_element_is); map cost; for(int i = 1; i <= a_element_is; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = cost_i; } int b_element_is; scanf("%d", &b_element_is); for(int i = 1; i <= b_element_is; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = max(cost[element_i], cost_i); } long long total_cost = 0; for(map :: iterator it = cost.begin(); it != cost.end(); it++) { total_cost += it->second; } printf("%I64d\n", total_cost); return 0; } ================================================ FILE: C Programs/C Programs 22/Chess Placing.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int n; cin >> n; vector A(n/2 + 1); for(int i = 1; 2*i <= n; i++) cin >> A[i]; sort(all(A)); int black_moves = 0; for(int i = 1; 2*i <= n; i++) black_moves += abs(A[i] - (2*i - 1)); int white_moves = 0; for(int i = 1; 2*i <= n; i++) white_moves += abs(A[i] - 2*i); int minimum_moves = min(black_moves, white_moves); cout << minimum_moves; return 0; } ================================================ FILE: C Programs/C Programs 22/Correct Solution.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; string solve(string S) { vector digits; for(int i = 0; i < S.size(); i++) digits.push_back(S[i]); sort(all(digits)); if(digits[0] == '0' && digits.size() > 1) { int first_nonzero = 1; while(digits[first_nonzero] == '0') first_nonzero++; swap(digits[0], digits[first_nonzero]); } string answer; for(int i = 0; i < digits.size(); i++) answer += digits[i]; return answer; } int main() { string A, B; cin >> A >> B; string answer = solve(A); cout << ((answer == B) ? "OK\n" : "WRONG_ANSWER\n"); return 0; } ================================================ FILE: C Programs/C Programs 22/Counting Kangaroos is Fun.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_kangaroos; scanf("%d", &no_of_kangaroos); vector kangaroo_size(no_of_kangaroos); for(int i = 0; i < no_of_kangaroos; i++) scanf("%d", &kangaroo_size[i]); sort(all(kangaroo_size)); int no_of_pairs = 0; int front_i = 0, back_i = no_of_kangaroos/2; for( ; front_i < no_of_kangaroos/2 && back_i < no_of_kangaroos; front_i++) { while(back_i < no_of_kangaroos) { if(kangaroo_size[front_i]*2 <= kangaroo_size[back_i]) { back_i++; no_of_pairs++; break; } else { back_i++; } } } int no_of_visible_kangaroos = no_of_pairs + (no_of_kangaroos - 2*no_of_pairs); printf("%d\n", no_of_visible_kangaroos); return 0; } ================================================ FILE: C Programs/C Programs 22/Fruits.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_prices, no_of_fruits; cin >> no_of_prices >> no_of_fruits; vector price(no_of_prices, 0); for(int i = 0; i < no_of_prices; i++) cin >> price[i]; sort(all(price)); map frequency; for(int i = 1; i <= no_of_fruits; i++) { string fruit; cin >> fruit; frequency[fruit]++; } vector fruit_frequency; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) fruit_frequency.push_back(it->second); sort(all(fruit_frequency)); reverse(all(fruit_frequency)); long long min_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) min_price += price[i]*1LL*fruit_frequency[i]; reverse(all(price)); long long max_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) max_price += price[i]*1LL*fruit_frequency[i]; cout << min_price << " " << max_price; return 0; } ================================================ FILE: C Programs/C Programs 22/High School Become Human.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) int main() { long long x, y; scanf("%I64d %I64d", &x, &y); if(x == y || (min(x, y) == 2 && max(x, y) == 4)) { printf("="); } else if(min(x, y) == 1) { printf(x == 1 ? "<" : ">"); } else if(min(x, y) == 2) { if(x == 2) { printf(y < 4 ? "<" : ">"); } else if(y == 2) { printf(x < 4? ">" : "<"); } } else if(min(x, y) >= 3) //Both greater than e { printf(x < y ? ">" : "<"); } return 0; } ================================================ FILE: C Programs/C Programs 22/Infinity Gauntlet.cpp ================================================ #include #include #include using namespace std; int main() { map power; power["red"] = "Reality"; power["purple"] = "Power"; power["green"] = "Time"; power["yellow"] = "Mind"; power["orange"] = "Soul"; power["blue"] = "Space"; map present; int no_of_names; cin >> no_of_names; while(no_of_names--) { string colour; cin >> colour; present[colour] = true; } vector answer; for(map :: iterator it = power.begin(); it != power.end(); it++) { if(!present[it->first]) answer.push_back(it->second); } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) cout << answer[i] << "\n"; return 0; } ================================================ FILE: C Programs/C Programs 22/Knights of a Polygonal Table.cpp ================================================ #include #include #include #include #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; struct knight { int position, power, coin; }; int sort_by_power(const knight &A, const knight &B) { return (A.power < B.power); } int main() { int no_of_knights, max_coins; scanf("%d %d", &no_of_knights, &max_coins); vector knights(no_of_knights + 1); for(int i = 1; i <= no_of_knights; i++) knights[i].position = i; for(int i = 1; i <= no_of_knights; i++) scanf("%d", &knights[i].power); for(int i = 1; i <= no_of_knights; i++) scanf("%d", &knights[i].coin); sort(all(knights), sort_by_power); vector answer(no_of_knights + 1, 0); multiset best_coin; for(int i = 1; i <= no_of_knights; i++) { if(knights[i].power == knights[i - 1].power) { answer[knights[i].position] = answer[knights[i - 1].position] - knights[i - 1].coin + knights[i].coin; } else { int c = 1; answer[knights[i].position] = knights[i].coin; for(multiset :: reverse_iterator it = best_coin.rbegin(); it != best_coin.rend() && c <= max_coins; it++, c++) { answer[knights[i].position] += *it; } } best_coin.insert(knights[i].coin); } for(int i = 1; i <= no_of_knights; i++) printf("%I64d ", answer[i]); return 0; } ================================================ FILE: C Programs/C Programs 22/Letters.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector A(no_of_elements + 1); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); sum_till[i] = sum_till[i - 1] + A[i]; } while(no_of_queries--) { long long x; scanf("%I64d", &x); int dorm_no = upper_bound(all(sum_till), x - 1) - sum_till.begin(); long long room_no = x - sum_till[dorm_no - 1]; printf("%d %I64d\n", dorm_no, room_no); } return 0; } ================================================ FILE: C Programs/C Programs 22/Local Extrema.cpp ================================================ #include #include using namespace std; int is_extrema(int mid, int start, int end) { return ((start < mid && end < mid) || (mid < start && mid < end)); } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int local_extrema = 0; for(int i = 2; i < no_of_elements; i++) local_extrema += is_extrema(A[i], A[i - 1], A[i + 1]); printf("%d\n", local_extrema); return 0; } ================================================ FILE: C Programs/C Programs 22/Remove Duplicates.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); const int MAX = 1015; vector used(MAX, false); vector ans; for(int i = no_of_elements; i >= 1; i--) { if(!used[A[i]]) { used[A[i]] = true; ans.push_back(A[i]); } } reverse(all(ans)); printf("%d\n", ans.size()); for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]); return 0; } ================================================ FILE: C Programs/C Programs 22/Super Agent.cpp ================================================ #include int main() { const int N = 3; char grid[N + 2][N + 2]; for(int i = 1; i <= N; i++) scanf("%s", grid[i] + 1); int symmetric = (grid[1][1] == grid[3][3]) && (grid[1][2] == grid[3][2]) && (grid[1][3] == grid[3][1]) && (grid[2][3] == grid[2][1]); printf(symmetric ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 22/Switches and Lamps.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_switches, no_of_lamps; cin >> no_of_switches >> no_of_lamps; vector switches(no_of_switches); for(int i = 0; i < no_of_switches; i++) cin >> switches[i]; vector no_of_switches_for(no_of_lamps, 0); for(int i = 0; i < no_of_switches; i++) for(int lamp = 0; lamp < no_of_lamps; lamp++) no_of_switches_for[lamp] += (switches[i][lamp] == '1'); int one_ignorable = false; for(int i = 0; i < no_of_switches; i++) { int can_ignore_this_one = true; for(int lamp = 0; lamp < no_of_lamps; lamp++) { if(switches[i][lamp] == '1' && no_of_switches_for[lamp] == 1) can_ignore_this_one = false; } if(can_ignore_this_one) one_ignorable = true; } cout << (one_ignorable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 22/Tafurama.cpp ================================================ #include using namespace std; #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 2e5 + 15; int sum_tree[3*MAX_N]; void update(int n, int left, int right, int index, int value) { if(right < left || right < index || index < left) return; if(right == left) { sum_tree[n] = value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, index, value); update(RIGHT(n), mid + 1, right, index, value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int get_sum(int n, int left, int right, int query_left, int query_right) { if(right < left || right < query_left || query_right < left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; int left_answer = get_sum(LEFT(n), left, mid, query_left, query_right); int right_answer = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_answer + right_answer); } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); vector index[no_of_elements + 1]; memset(sum_tree, 0, sizeof(sum_tree)); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); A[i] = min(A[i], no_of_elements); update(1, 1, no_of_elements, i, 1); index[A[i]].push_back(i); } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer += get_sum(1, 1, no_of_elements, i + 1, A[i]); for(int j = 0; j < index[i].size(); j++) { update(1, 1, no_of_elements, index[i][j], 0); } } printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 22/Three Displays Segment Tree Solution.cpp ================================================ #include #include #include using namespace std; #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 3015; const long long oo = 1e10; struct info { int font_size, cost, position; }; long long min_tree[4*MAX_N]; long long max_tree[4*MAX_N]; int compare_by_size(const info &A, const info &B) { if(A.font_size == B.font_size) return (A.position > B.position); else return (A.font_size < B.font_size); } void build_min_tree(int n, int left, int right) { if(left == right) { min_tree[n] = oo; return; } int mid = (left + right) >> 1; build_min_tree(LEFT(n), left, mid); build_min_tree(RIGHT(n), mid + 1, right); min_tree[n] = min(min_tree[LEFT(n)], min_tree[RIGHT(n)]); } void update_min(int n, int left, int right, int position, int value) { if(position < left || right < position) return; if(left == right) { min_tree[n] = value; return; } int mid = (left + right) >> 1; update_min(LEFT(n), left, mid, position, value); update_min(RIGHT(n), mid + 1, right, position, value); min_tree[n] = min(min_tree[LEFT(n)], min_tree[RIGHT(n)]); } long long get_min(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || query_right < query_left) return oo; if(query_left <= left && right <= query_right) return min_tree[n]; int mid = (left + right) >> 1; long long left_min = get_min(LEFT(n), left, mid, query_left, query_right); long long right_min = get_min(RIGHT(n), mid + 1, right, query_left, query_right); return min(left_min, right_min); } int main() { int no_of_displays; scanf("%d", &no_of_displays); vector A(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) A[i].position = i; for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].font_size); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].cost); sort(A.begin() + 1, A.end(), compare_by_size); build_min_tree(1, 1, no_of_displays); vector best_left(no_of_displays + 1, oo); for(int i = 1; i <= no_of_displays; i++) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_left[i] = get_min(1, 1, no_of_displays, 1, A[i].position - 1); } build_min_tree(1, 1, no_of_displays); vector best_right(no_of_displays + 1, oo); for(int i = no_of_displays; i >= 1; i--) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_right[i] = get_min(1, 1, no_of_displays, A[i].position + 1, no_of_displays); } long long best_cost = oo; for(int i = 1; i <= no_of_displays; i++) best_cost = min(best_cost, best_left[i] + A[i].cost + best_right[i]); printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: C Programs/C Programs 22/Three Displays.cpp ================================================ #include #include #define min(a, b) (a < b ? a : b) using namespace std; int main() { int no_of_displays; scanf("%d", &no_of_displays); vector text_size(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &text_size[i]); vector cost(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &cost[i]); const long long oo = 1e10; vector best_left(no_of_displays + 1, oo); vector best_right(no_of_displays + 1, oo); long long best_cost = oo; for(int mid = 1; mid <= no_of_displays; mid++) { for(int right = mid + 1; right <= no_of_displays; right++) { if(text_size[mid] < text_size[right]) best_right[mid] = min(best_right[mid], cost[right]); } for(int left = 1; left < mid; left++) { if(text_size[left] < text_size[mid]) best_left[mid] = min(best_left[mid], cost[left]); } best_cost = min(best_cost, best_right[mid] + cost[mid] + best_left[mid]); } printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: C Programs/C Programs 22/Useful Decomposition.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 15; vector graph[MAX_N]; int dfs_leaf_from(int v, int parent) { if(graph[v].size() == 1) return v; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(child == parent) continue; return dfs_leaf_from(child, v); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int i = 1; i < no_of_vertices; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } int no_of_roots = 0, root = 1; for(int i = 1; i <= no_of_vertices; i++) { if(graph[i].size() > 2) { no_of_roots++; root = i; } } if(no_of_roots > 1) { printf("No\n"); return 0; } printf("Yes\n"); int no_of_paths = graph[root].size(); printf("%d\n", no_of_paths); for(int i = 0; i < graph[root].size(); i++) { int child = graph[root][i]; int leaf = dfs_leaf_from(child, root); printf("%d %d\n", root, leaf); } return 0; } ================================================ FILE: C Programs/C Programs 23/An Impassioned Circulation of Affection.cpp ================================================ #include #include const int MAX_ALPHABETS = 26, MAX_N = 1505; int maximum_segment[MAX_ALPHABETS][MAX_N]; using namespace std; int main() { int length; string S; cin >> length >> S; for(int ch = 0; ch < MAX_ALPHABETS; ch++) { for(int left = 0; left < length; left++) { int replacements = 0; for(int right = left; right < length; right++) { replacements += (S[right] != 'a' + ch); maximum_segment[ch][replacements] = max(maximum_segment[ch][replacements], right - left + 1); } } } for(int ch = 0; ch < MAX_ALPHABETS; ch++) { for(int replacements = 1; replacements <= length; replacements++) { maximum_segment[ch][replacements] = max(maximum_segment[ch][replacements], maximum_segment[ch][replacements - 1]); } } int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { int max_replacements; char character; cin >> max_replacements >> character; cout << maximum_segment[character - 'a'][max_replacements] << '\n'; } return 0; } ================================================ FILE: C Programs/C Programs 23/Another Problem on Strings.cpp ================================================ #include #include #include using namespace std; int main() { int target_no_of_1s; scanf("%d", &target_no_of_1s); const int MAX = 1e6 + 3; char S[MAX]; scanf("%s", S); vector sum(MAX, 0); sum[0] = (S[0] == '1'); for(int i = 1; S[i] != '\0'; i++) sum[i] = sum[i - 1] + (S[i] == '1'); vector sum_frequency(MAX, 0); sum_frequency[0] = 1; //Empty string long long no_of_good_substrings = 0; for(int i = 0; S[i] != '\0'; i++) { if(sum[i] >= target_no_of_1s) no_of_good_substrings += (sum_frequency[sum[i] - target_no_of_1s]); sum_frequency[sum[i]]++; } printf("%I64d\n", no_of_good_substrings); return 0; } ================================================ FILE: C Programs/C Programs 23/Babaei and Birthday Cake.cpp ================================================ #include #include #include #include using namespace std; #define all(v) (v).begin() + 1, (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 1e5 + 5; double max_tree[3*MAX_N]; void insert(int n, int left, int right, double value, int position) { if(right < position || position < left) return; if(left == right) { max_tree[n] = value; return; } int mid = (left + right) >> 1; insert(LEFT(n), left, mid, value, position); insert(RIGHT(n), mid + 1, right, value, position); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } double get_max(int n, int left, int right, int query_left, int query_right) { if(query_right < query_left || query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return max_tree[n]; int mid = (left + right) >> 1; double left_max = get_max(LEFT(n), left, mid, query_left, query_right); double right_max = get_max(RIGHT(n), mid + 1, right, query_left, query_right); return max(left_max, right_max); } int main() { int no_of_cylinders; scanf("%d", &no_of_cylinders); vector volume(no_of_cylinders + 1); vector sorted_volume(no_of_cylinders + 1); for(int i = 1; i <= no_of_cylinders; i++) { int radius, height; scanf("%d %d", &radius, &height); const double PI = 3.14159; volume[i] = (PI*radius*radius*1LL*height); sorted_volume[i] = volume[i]; } sort(all(sorted_volume)); map rank; for(int i = 1; i <= no_of_cylinders; i++) rank[sorted_volume[i]] = i; map answer_with_last; for(int i = 1; i <= no_of_cylinders; i++) { answer_with_last[volume[i]] = volume[i] + get_max(1, 1, no_of_cylinders, 1, rank[volume[i]] - 1); insert(1, 1, no_of_cylinders, answer_with_last[volume[i]], rank[volume[i]]); } double answer = 0; for(int i = 1; i <= no_of_cylinders; i++) answer = max(answer, answer_with_last[volume[i]]); printf("%.10f\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 23/Bear and Prime Numbers.cpp ================================================ #include #include using namespace std; void precompute(vector &is_prime, int N) { is_prime[0] = is_prime[1] = false; vector primes; for(int i = 2; i <= N; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] <= N; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } } int main() { int no_of_elements; scanf("%d", &no_of_elements); const int MAX_N = 1e7; vector frequency(MAX_N + 1, 0); while(no_of_elements--) { int element; scanf("%d", &element); frequency[element]++; } vector is_prime(MAX_N + 1, true); precompute(is_prime, MAX_N); vector no_of_multiples(MAX_N + 1, 0); for(int i = 1; i <= MAX_N; i++) { if(!is_prime[i]) continue; for(int multiple = i; multiple <= MAX_N; multiple += i) { no_of_multiples[i] += frequency[multiple]; } } vector answer(MAX_N + 1, 0); for(int i = 1; i <= MAX_N; i++) answer[i] = answer[i - 1] + no_of_multiples[i]; int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int left, right; scanf("%d %d", &left, &right); right = min(right, MAX_N); left = min(left, MAX_N); printf("%d\n", answer[right] - answer[left - 1]); } return 0; } ================================================ FILE: C Programs/C Programs 23/Cirriculum Vitae.cpp ================================================ #include #include using namespace std; int main() { int no_of_games; scanf("%d", &no_of_games); vector won(no_of_games + 1); for(int i = 1; i <= no_of_games; i++) scanf("%d", &won[i]); vector wins_from(no_of_games + 2, 0); for(int i = no_of_games; i >= 1; i--) wins_from[i] = wins_from[i + 1] + (won[i]); int final_no_of_games = 0; int losses_so_far = 0; for(int i = 1; i <= no_of_games; i++) { losses_so_far += (!won[i]); final_no_of_games = max(final_no_of_games, losses_so_far + wins_from[i]); } printf("%d\n", final_no_of_games); return 0; } ================================================ FILE: C Programs/C Programs 23/Classy Numbers Precomputing Solution.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_DIGITS = 18; vector classy_numbers; void precompute(int position, int non_zero_count, long long current_num) { if(non_zero_count > 3) return; if(position == MAX_DIGITS) { classy_numbers.push_back(current_num); return; } for(int digit = 0; digit <= 9; digit++) { precompute(position + 1, non_zero_count + (digit != 0), current_num*10 + digit); } } int main() { precompute(0, 0, 0); classy_numbers.push_back(1e18); //This has 19 digits int no_of_tests; scanf("%d", &no_of_tests); while(no_of_tests--) { long long left, right; scanf("%I64d %I64d", &left, &right); int classy_number_count = upper_bound(all(classy_numbers), right) - lower_bound(all(classy_numbers), left); printf("%d\n", classy_number_count); } return 0; } ================================================ FILE: C Programs/C Programs 23/Counting Arrays.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 2e6, MOD =1e9 + 7; vector factorial(MAX_N + 1), inverse_factorial(MAX_N + 1); vector primes; void sieve() { vector is_prime(MAX_N + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= MAX_N; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] <= MAX_N; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } } long long power_mod(long long x, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } void precompute() { factorial[0] = 1; for(int i = 1; i <= MAX_N; i++) factorial[i] = (i*factorial[i - 1])%MOD; inverse_factorial[MAX_N] = power_mod(factorial[MAX_N], MOD - 2); for(int i = MAX_N - 1; i >= 0; i--) inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } long long choose(long long n, long long r) { long long numerator = factorial[n]; long long inverse_denominator = (inverse_factorial[r]*inverse_factorial[n - r])%MOD; return (numerator*inverse_denominator)%MOD; } void factorise(int n, map &exponent) { for(int i = 0; primes[i]*primes[i] <=n; i++) { while(n%primes[i] == 0) { exponent[primes[i]]++; n /= primes[i]; } } if(n > 1) exponent[n]++; } void solve() { int x, no_of_summands; cin >> x >> no_of_summands; map prime_exponents; factorise(x, prime_exponents); long long answer = 1; for(map :: iterator it = prime_exponents.begin(); it != prime_exponents.end(); it++) { int exponent = it->second; answer *= choose(no_of_summands + exponent - 1, no_of_summands - 1); answer %= MOD; } long long ways_to_distribute_signs = power_mod(2, no_of_summands - 1); answer = (answer*ways_to_distribute_signs)%MOD; cout << answer << "\n"; } int main() { sieve(); precompute(); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 23/Crazy Town.cpp ================================================ #include int main() { int start_x, start_y, end_x, end_y; scanf("%d %d %d %d", &start_x, &start_y, &end_x, &end_y); int no_of_lines; scanf("%d", &no_of_lines); int crossed_lines = 0; while(no_of_lines--) { long long a, b, c; scanf("%I64d %I64d %I64d", &a, &b, &c); long long start_side = a*start_x + b*start_y + c; long long end_side = a*end_x + b*end_y + c; if( (start_side > 0 && end_side < 0) || (start_side < 0 && end_side > 0) ) crossed_lines++; } printf("%d\n", crossed_lines); return 0; } ================================================ FILE: C Programs/C Programs 23/Find Maximum.cpp ================================================ #include #include #include using namespace std; int main() { int n; scanf("%d", &n); vector A(n + 1); for(int i = 1; i <= n; i++) scanf("%d", &A[i]); vector prefix_sum(n + 1, 0); for(int i = 1; i <= n; i++) prefix_sum[i] = prefix_sum[i - 1] + A[i]; const int MAX_N = 1e5 + 5; char S[MAX_N]; scanf("%s", S + 1); long long answer = 0, set_bit_sum = 0; for(int i = n; i > 0; i--) { if(S[i] == '1') { answer = max(answer, set_bit_sum + prefix_sum[i - 1]); set_bit_sum += A[i]; } } answer = max(answer, set_bit_sum); printf("%I64d\n", answer); return 0; } ================================================ FILE: C Programs/C Programs 23/Fish.cpp ================================================ #include const int MAX_FISH = 20; double probability[(1 << MAX_FISH)]; double eat_probability[MAX_FISH][MAX_FISH]; int is_alive(int n, int bit) { return ( (n&(1LL << bit)) != 0); } int kill(int n, int bit) { return (n^(1LL << bit)); } int no_of_set_bits(int n) { int no_of_1s = 0; while(n) { no_of_1s += n%2; n /= 2; } return no_of_1s; } int choose_2(int n) { return (n*(n - 1))/2; } int main() { int no_of_fish; scanf("%d", &no_of_fish); for(int i = 0; i < no_of_fish; i++) for(int j = 0; j < no_of_fish; j++) scanf("%lf", &eat_probability[i][j]); int max_mask = (1LL << no_of_fish) - 1; //Mask has a bit set if fish i is alive. probability[max_mask] = 1.0; //All fish alive in the beginning for(int mask = max_mask; mask >= 1; mask--) { for(int eating_fish = 0; eating_fish < no_of_fish; eating_fish++) { if(is_alive(mask, eating_fish)) //Eating fish is alive { for(int victim_fish = 0; victim_fish < no_of_fish; victim_fish++) { if(is_alive(mask, victim_fish) && eating_fish != victim_fish) { int mask_without_victim = kill(mask, victim_fish); int no_of_alive_fish = no_of_set_bits(mask); int no_of_combinations = choose_2(no_of_alive_fish); probability[mask_without_victim] += (probability[mask]*eat_probability[eating_fish][victim_fish])/no_of_combinations; } } } } } for(int i = 0; i < no_of_fish; i++) printf("%.12lf ", probability[(1LL << i)]); return 0; } ================================================ FILE: C Programs/C Programs 23/Garbage Disposal.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_days, k; cin >> no_of_days >> k; vector A(no_of_days + 1); for(int i = 1; i <= no_of_days; i++) cin >> A[i]; long long minimum_bags = 0; for(int i = 1; i <= no_of_days; i++) { minimum_bags += A[i]/k; A[i] %= k; if(A[i] > 0) { minimum_bags++; if(i + 1 <= no_of_days) A[i + 1] = max(0LL, A[i + 1] - (k - A[i])); } } cout << minimum_bags; return 0; } ================================================ FILE: C Programs/C Programs 23/Guest From The Past.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { long long money, plastic_bottle_price, glass_bottle_price, return_amount; scanf("%I64d %I64d %I64d %I64d", &money, &plastic_bottle_price, &glass_bottle_price, &return_amount); long long effective_glass_bottle_price = glass_bottle_price - return_amount; long long no_of_bottles = 0; if(plastic_bottle_price <= effective_glass_bottle_price || glass_bottle_price > money) { no_of_bottles = money/plastic_bottle_price; } else if(effective_glass_bottle_price < plastic_bottle_price && glass_bottle_price <= money) { no_of_bottles = (money - return_amount)/effective_glass_bottle_price; long long remaining_money = money - no_of_bottles*effective_glass_bottle_price; long long remaining_bottles = remaining_money/plastic_bottle_price; no_of_bottles += remaining_bottles; } printf("%I64d\n", no_of_bottles); return 0; } ================================================ FILE: C Programs/C Programs 23/Ice Skater.cpp ================================================ #include #include using namespace std; const int MAX_N = 105; vector visited(MAX_N, false); vector graph[MAX_N]; void dfs(int v) { visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) dfs(child); } } int main() { int no_of_points; scanf("%d", &no_of_points); vector X(no_of_points + 1); vector Y(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) scanf("%d %d", &X[i], &Y[i]); int no_of_components = 0; for(int i = 1; i <= no_of_points; i++) { for(int j = 1; j < i; j++) { if(X[i] == X[j] || Y[i] == Y[j]) { graph[i].push_back(j); graph[j].push_back(i); } } } for(int i = 1; i <= no_of_points; i++) { if(!visited[i]) { no_of_components++; dfs(i); } } printf("%d\n", no_of_components - 1); return 0; } ================================================ FILE: C Programs/C Programs 23/Lazyland.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_people, distinct_targets; scanf("%d %d", &no_of_people, &distinct_targets); vector A(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &A[i]); vector time(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &time[i]); map max_time_for_task; vector free_time; for(int i = 1; i <= no_of_people; i++) { if(max_time_for_task[A[i]] != 0) free_time.push_back(min(time[i], max_time_for_task[A[i]])); max_time_for_task[A[i]] = max(max_time_for_task[A[i]], time[i]); } sort(all(free_time)); int distinct_numbers = max_time_for_task.size(); int required_new_distinct_numbers = distinct_targets - distinct_numbers; long long total_time = 0; for(int i = 0; i < required_new_distinct_numbers; i++) total_time += free_time[i]; printf("%I64d\n", total_time); return 0; } ================================================ FILE: C Programs/C Programs 23/Lesha and Array Splitting.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector prefix_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) prefix_sum[i] = prefix_sum[i - 1] + A[i]; vector suffix_sum(no_of_elements + 2, 0); for(int i = no_of_elements; i>= 1; i--) suffix_sum[i] = suffix_sum[i + 1] + A[i]; int all_zeroes = true; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != 0) all_zeroes = false; } if(all_zeroes) { printf("NO\n"); } else { printf("YES\n"); if(no_of_elements == 1 || prefix_sum[no_of_elements] != 0) { printf("1\n1 %d\n", no_of_elements); } else { int division_point; for(int i = 1; i < no_of_elements; i++) { if(prefix_sum[i] != 0 && suffix_sum[i + 1] != 0) { division_point = i; break; } } printf("2\n"); printf("1 %d\n", division_point); printf("%d %d\n", division_point + 1, no_of_elements); } } return 0; } ================================================ FILE: C Programs/C Programs 23/Lost Array.cpp ================================================ #include #include using namespace std; int is_possible(vector &A, int k) { for(int i = 1; i < A.size(); i++) { if(A[i] != A[(i%k)]) return false; } return true; } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector X(no_of_elements); for(int i = 0; i < no_of_elements; i++) X[i] = A[i + 1] - A[i]; vector answer; for(int i = 1; i <= no_of_elements; i++) { if(is_possible(X, i)) { answer.push_back(i); } } printf("%d\n", answer.size() == 0 ? -1 : answer.size()); for(int i = 0; i < answer.size(); i++) printf("%d ", answer[i]); return 0; } ================================================ FILE: C Programs/C Programs 23/Maximum Value.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); const int MAX = 2e6 + 5; vector A(no_of_elements + 1); vector is_present(MAX, false); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); is_present[A[i]] = true; } vector nearest(MAX, 0); for(int i = 1; i < MAX; i++) { nearest[i] = (is_present[i - 1] ? i - 1 : nearest[i - 1]); } int max_mod = 0; for(int i = 1; i < MAX; i++) { if(!is_present[i]) continue; for(int j = 2*i; j < MAX; j += i) { max_mod = max(max_mod, nearest[j]%i); } } printf("%d\n", max_mod); return 0; } ================================================ FILE: C Programs/C Programs 23/Maze.cpp ================================================ #include #include const int MAX_N = 505; int visited[MAX_N][MAX_N]; char grid[MAX_N][MAX_N]; int no_of_visits = 0, rows, columns; void dfs(int r, int c, int target) { if(no_of_visits >= target) return; visited[r][c] = true; no_of_visits++; const int NO_OF_NEIGHBOURS = 4; int next_x[NO_OF_NEIGHBOURS] = {-1, 0, 0, 1}; int next_y[NO_OF_NEIGHBOURS] = {0, 1, -1, 0}; for(int i = 0; i < NO_OF_NEIGHBOURS; i++) { int next_r = r + next_x[i], next_c = c + next_y[i]; if(0 < next_r && next_r <= rows && 0 < next_c && next_c <= columns && !visited[next_r][next_c] && grid[next_r][next_c] == '.') { dfs(next_r, next_c, target); } } } int main() { int k; scanf("%d %d %d", &rows, &columns, &k); for(int i = 1; i <= rows; i++) scanf("%s", grid[i] + 1); memset(visited, sizeof(visited), false); int total_free = 0; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { total_free += (grid[i][j] == '.'); } } for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == '.') { dfs(i, j, total_free - k); break; } } } for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { printf("%c", (grid[i][j] == '.' && !visited[i][j]) ? 'X' : grid[i][j]); } printf("\n"); } return 0; } ================================================ FILE: C Programs/C Programs 23/Minesweeper.cpp ================================================ #include const int MAX_N = 105; const char BOMB = '*', EMPTY = '.'; char grid[MAX_N][MAX_N]; int neighbour_bomb_count(int x, int y) { const int NO_OF_NEIGHBOURS = 8; int step_x[NO_OF_NEIGHBOURS] = {-1, 0, 1, -1, 1, - 1, 0, 1}; int step_y[NO_OF_NEIGHBOURS] = {-1, -1, -1, 0, 0, 1, 1, 1}; int no_of_bombs = 0; for(int i = 0; i < NO_OF_NEIGHBOURS; i++) { no_of_bombs += (grid[x + step_x[i]][y + step_y[i]] == BOMB); } return no_of_bombs; } int main() { int rows, columns; scanf("%d %d", &rows, &columns); for(int i = 1; i <= rows; i++) scanf("%s", grid[i] + 1); int valid = true; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == EMPTY) { if(neighbour_bomb_count(i, j) != 0) valid = false; } else if('0' <= grid[i][j] && grid[i][j] <= '9') { if(neighbour_bomb_count(i, j) != grid[i][j] - '0') valid = false; } } } printf(valid ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: C Programs/C Programs 23/Minimum Diameter Tree.cpp ================================================ #include #include using namespace std; int main() { int no_of_vertices, total_weight; scanf("%d %d", &no_of_vertices, &total_weight); vector degree(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices - 1; i++) { int u, v; scanf("%d %d", &u, &v); degree[u]++; degree[v]++; } int no_of_leafs = 0; for(int i = 1; i <= no_of_vertices; i++) no_of_leafs += (degree[i] == 1); double leaf_weight = ( (double) total_weight)/ no_of_leafs; double diameter = leaf_weight*2; printf("%.12f\n", diameter); return 0; } ================================================ FILE: C Programs/C Programs 23/No To Palindromes.cpp ================================================ #include #include using namespace std; int main() { int length, max_alphabet; cin >> length >> max_alphabet; string S; cin >> S; if( (max_alphabet == 1 && length > 1) || (max_alphabet == 2 && length > 2) ) { cout << "NO\n"; return 0; } const int NOT_FOUND = -1; int first_greater_position = NOT_FOUND; char replacement; for(int i = length - 1; first_greater_position == NOT_FOUND && i >= 0; i--) { for(char new_ch = S[i] + 1; new_ch <= 'a' + max_alphabet - 1; new_ch++) { int possible = true; for(int j = i - 1; j >= max(i - 2, 0); j--) { if(new_ch == S[j]) possible = false; } if(possible) { first_greater_position = i; replacement = new_ch; break; } } } if(first_greater_position == NOT_FOUND) { cout << "NO\n"; return 0; } string next_good_string; for(int i = 0 ; i < first_greater_position; i++) next_good_string += S[i]; next_good_string += replacement; for(int i = first_greater_position + 1; i < length; i++) { char current_char; for(current_char = 'a'; current_char <= 'c'; current_char++) { if( (i - 1 >= 0 && next_good_string[i - 1] == current_char) || (i - 2 >= 0 && next_good_string[i - 2] == current_char) ) { continue; } else { next_good_string += current_char; break; } } } cout << next_good_string; return 0; } ================================================ FILE: C Programs/C Programs 23/On Number of Decompositions into Multipliers.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e5, MOD =1e9 + 7; vector factorial(MAX_N + 1), inverse_factorial(MAX_N + 1); vector primes; void sieve() { const int L = 1e5; vector is_prime(L + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= L; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] <= MAX_N; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } } long long power_mod(long long x, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } void precompute() { factorial[0] = 1; for(int i = 1; i <= MAX_N; i++) factorial[i] = (i*factorial[i - 1])%MOD; inverse_factorial[MAX_N] = power_mod(factorial[MAX_N], MOD - 2); for(int i = MAX_N - 1; i >= 0; i--) inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%MOD; } long long choose(long long n, long long r) { long long numerator = factorial[n]; long long inverse_denominator = (inverse_factorial[r]*inverse_factorial[n - r])%MOD; return (numerator*inverse_denominator)%MOD; } void factorise(int n, map &exponent) { for(int i = 0; primes[i]*primes[i] <=n; i++) { while(n%primes[i] == 0) { exponent[primes[i]]++; n /= primes[i]; } } if(n > 1) exponent[n]++; } int main() { sieve(); precompute(); int no_of_elements; cin >> no_of_elements; map prime_exponents; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; factorise(element, prime_exponents); } const int MOD = 1e9 + 7; long long answer = 1; for(map :: iterator it = prime_exponents.begin(); it != prime_exponents.end(); it++) { int exponent = it->second; answer *= choose(no_of_elements + exponent - 1, no_of_elements - 1); answer %= MOD; } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 23/Summarise to Powers of Two.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); map frequency; for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); frequency[A[i]]++; } int no_of_deletions = 0; for(int i = 1; i <= no_of_elements; i++) { int complement_exists = false; for(int power = 0; power <= 32; power++) { int complement = (1LL << power) - A[i]; if(complement == A[i]) { if(frequency[A[i]] >= 2) complement_exists = true; } else if(frequency.find(complement) != frequency.end()) { complement_exists = true; } } if(!complement_exists) no_of_deletions++; } printf("%d\n", no_of_deletions); return 0; } ================================================ FILE: C Programs/C Programs 23/The Fair Nut and String.cpp ================================================ #include #include using namespace std; int main() { string S; cin >> S; const int MOD = 1e9 + 7; long long total_sequences = 1, current_block_of_a = 0; for(int i = 0; i <= S.size(); i++) { if(S[i] == 'a') { current_block_of_a++; } else if(i == S.size() || S[i] == 'b') { total_sequences = (total_sequences*(current_block_of_a + 1))%MOD; current_block_of_a = 0; } } total_sequences = (total_sequences + MOD - 1)%MOD; cout << total_sequences; return 0; } ================================================ FILE: C Programs/C Programs 23/The Meaningless Game.cpp ================================================ #include #include using namespace std; int main() { map cube_root; const int MAX_CUBE_ROOT = 1e6; for(long long i = 1; i <= MAX_CUBE_ROOT; i++) cube_root[i*i*i] = i; int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { long long a, b; scanf("%I64d %I64d", &a, &b); int possible = true; if(cube_root[a*b] == 0) { possible = false; printf("No\n"); continue; } long long winnings_a = (a)/cube_root[a*b]; long long winnings_b = (b)/cube_root[a*b]; long long expected_a = (winnings_a*winnings_a*winnings_b); long long expected_b = (winnings_b*winnings_b*winnings_a); if(a != expected_a || b != expected_b) possible = false; printf(possible ? "Yes\n" : "No\n"); } return 0; } ================================================ FILE: C Programs/C Programs 24/Brutality.cpp ================================================ #include #include #include #define min(a, b) (a < b ? a : b) #define all(v) (v).begin(), (v).end() using namespace std; const int NO_OF_ALPHABETS = 26; vector cost[NO_OF_ALPHABETS]; int main() { int length, max_elements; cin >> length >> max_elements; vector A(length); for(int i = 0; i < length; i++) cin >> A[i]; string S; cin >> S; long long total = 0; vector last_pressed_costs; char last_pressed = '#'; for(int i = 0; i <= length; i++) { if(i == length ||S[i] != last_pressed) { sort(all(last_pressed_costs)); reverse(all(last_pressed_costs)); for(int j = 0; j < min(max_elements, last_pressed_costs.size()); j++) { total += last_pressed_costs[j]; } last_pressed_costs.clear(); } if(i == length) continue; last_pressed = S[i]; last_pressed_costs.push_back(A[i]); } cout << total; return 0; } ================================================ FILE: C Programs/C Programs 24/Connect.cpp ================================================ #include #include #include #include using namespace std; struct Point { int x, y; Point(){} Point(int X, int Y) { x = X, y = Y; } }; const int NO_OF_NEIGHBOURS = 4, MAX_N = 55, oo = 1e9; int next_x[NO_OF_NEIGHBOURS] = {-1, 0, 0 , 1}; int next_y[NO_OF_NEIGHBOURS] = {0, 1, -1, 0}; int component_no[MAX_N][MAX_N], is_water[MAX_N][MAX_N]; int calculate_distance(Point P, Point Q) { return (P.x - Q.x)*(P.x - Q.x) + (P.y - Q.y)*(P.y - Q.y); } int is_outside(int x, int y, int n) { return (x < 1 || n < x || y < 1 || n < y); } void dfs(int x, int y, int n, int number) { if(is_water[x][y] || is_outside(x, y, n) || component_no[x][y] != 0) return; component_no[x][y] = number; for(int i = 0; i < NO_OF_NEIGHBOURS; i++) { dfs(x + next_x[i], y + next_y[i], n, number); } } int main() { int n; cin >> n; Point start, finish; cin >> start.x >> start.y >> finish.x >> finish.y; memset(is_water, false, sizeof(is_water)); for(int i = 0; i < n; i++) { string row; cin >> row; for(int j = 0; j < n; j++) { if(row[j] == '1') { is_water[i + 1][j + 1] = true; } } } memset(component_no, 0, sizeof(component_no)); int last_component_no = 0; for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { if(component_no[x][y] == 0) { dfs(x, y, n, ++last_component_no); } } } vector start_component, finish_component; for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { if(component_no[x][y] == component_no[start.x][start.y]) start_component.push_back(Point(x, y)); if(component_no[x][y] == component_no[finish.x][finish.y]) finish_component.push_back(Point(x, y)); } } int distance = oo; for(int i = 0; i < start_component.size(); i++) { for(int j = 0; j < finish_component.size(); j++) { distance = min(distance, calculate_distance(start_component[i], finish_component[j])); } } cout << distance; return 0; } ================================================ FILE: C Programs/C Programs 24/Div Times Mod.cpp ================================================ #include using namespace std; int main() { int n, k; cin >> n >> k; const int oo = 1e9; int answer = oo; for(int i = 1; i*i <= n; i++) { if(n%i == 0) { int quotient = i, remainder = n/i; if(remainder < k) answer = min(answer, quotient*k + remainder); quotient = n/i, remainder = i; if(remainder < k) answer = min(answer, quotient*k + remainder); } } cout << answer; return 0; } ================================================ FILE: C Programs/C Programs 24/Diverse Garland.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; string colour = "RGB"; int replacements = 0; for(int i = 1; i < length; i++) { if(S[i] == S[i - 1]) { for(int j = 0; j < colour.size(); j++) { if( (i + 1 == length && colour[j] != S[i - 1]) || (colour[j] != S[i + 1] && colour[j] != S[i - 1]) ) { replacements++; S[i] = colour[j]; break; } } } } cout << replacements << "\n" << S; return 0; } ================================================ FILE: C Programs/C Programs 24/Division and Union.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct line { int left, right, position; line(int l, int r, int p) { left = l, right = r, position = p; } int operator <(const line &L) { return (right < L.right); } }; void solve() { int no_of_segments; cin >> no_of_segments; vector L; for(int i = 0; i < no_of_segments; i++) { int left, right; cin >> left >> right; L.push_back(line(left, right, i)); } sort(all(L)); vector minimum_left_from(no_of_segments); for(int i = no_of_segments - 1; i >= 0; i--) { if(i == no_of_segments - 1) minimum_left_from[i] = L[i].left; else minimum_left_from[i] = min(minimum_left_from[i + 1], L[i].left); } const int NOT_FOUND = -1; int first_group_ending = NOT_FOUND; for(int i = 0; i < no_of_segments - 1; i++) { if(L[i].right < minimum_left_from[i + 1]) first_group_ending = i; } if(first_group_ending == NOT_FOUND) { cout << NOT_FOUND << "\n"; return ; } vector group(no_of_segments); for(int i = 0; i < no_of_segments; i++) group[L[i].position] = (i <= first_group_ending ? 1 : 2); for(int i = 0; i < no_of_segments; i++) cout << group[i] << " "; cout << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 24/Finite or Not.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) typedef long long LL; LL gcd(LL x, LL y) { if(x == 0 || y == 0) return (x + y); else return gcd(min(x, y), max(x, y)%min(x, y)); } void solve() { LL numerator, denominator, base; scanf("%I64d %I64d %I64d", &numerator, &denominator, &base); LL gcd_fraction = gcd(numerator, denominator); numerator /= gcd_fraction; denominator /= gcd_fraction; base = gcd(base, denominator); while(base > 1) { while(denominator%base == 0) denominator /= base; base = gcd(base, denominator); } printf(denominator == 1 ? "Finite\n" : "Infinite\n"); } int main() { int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: C Programs/C Programs 24/Illya and Escalator.cpp ================================================ #include #include #include #include using namespace std; const int MAX_N = 2005; double probability[MAX_N][MAX_N]; int main() { int no_of_people, total_time; double new_person_probability; cin >> no_of_people >> new_person_probability >> total_time; double no_new_person_probability = 1 - new_person_probability; memset(probability, 0, sizeof(probability)); probability[0][0] = 1; for(int t = 1; t <= total_time; t++) { probability[0][t] = no_new_person_probability*probability[0][t - 1]; for(int i = 1; i < no_of_people; i++) { probability[i][t] = new_person_probability*probability[i - 1][t - 1] + no_new_person_probability*probability[i][t - 1]; } probability[no_of_people][t] = probability[no_of_people][t - 1] + new_person_probability*probability[no_of_people - 1][t - 1]; } double expectation = 0; for(int i = 1; i <= no_of_people; i++) expectation += i*probability[i][total_time]; cout << setprecision(7) << expectation; return 0; } ================================================ FILE: C Programs/C Programs 24/Increasing by Modulo.cpp ================================================ #include #include using namespace std; int possible(int operations, int m, vector &A) { int minimum = 0; for(int i = 1; i < A.size(); i++) { if( (A[i] <= minimum && A[i] + operations >= minimum) || (A[i] > minimum && A[i] + operations - m >= minimum) ) continue; if(A[i] < minimum) return false; minimum = A[i]; } return true; } int main() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; int left = -1, right = m; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, m, A)) right = mid; else left = mid; } cout << right; return 0; } ================================================ FILE: C Programs/C Programs 24/Nice Garland.cpp ================================================ #include #include using namespace std; int replacements(string &R, string &S) { int difference_count = 0; for(int i = 0; i < S.size(); i++) difference_count += (S[i] != R[i%3]); return difference_count; } int main() { int length; cin >> length; string S; cin >> S; const int NO_OF_OPTIONS = 6, oo = 1e9; string option[NO_OF_OPTIONS] = {"RGB", "RBG", "BRG", "BGR", "GRB", "GBR"}; int minimum_replacement = oo, best_option = 0; for(int i = 0; i < NO_OF_OPTIONS; i++) { int replacements_here = replacements(option[i], S); if(replacements_here < minimum_replacement) { minimum_replacement = replacements_here; best_option = i; } } cout << minimum_replacement << "\n"; for(int i = 0; i < length; i++) cout << option[best_option][i%3]; return 0; } ================================================ FILE: C Programs/C Programs 24/Planning the Expedition.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int possible(vector A, int days, int min_participants) { int participants = 0; for(int i = 0; i < A.size(); i++) { participants += A[i]/days; A[i] %= days; } return (participants >= min_participants); } int main() { int no_of_participants, no_of_packages; scanf("%d %d", &no_of_participants, &no_of_packages); const int MAX = 100; vector frequency(MAX + 1, 0); for(int i = 1; i <= no_of_packages; i++) { int type; scanf("%d", &type); frequency[type]++; } if(no_of_packages < no_of_participants) { printf("0"); return 0; } int left_days = 1, right_days = MAX; while(left_days <= right_days) { int mid_days = (left_days + right_days) >> 1; if(possible(frequency, mid_days, no_of_participants)) { if(mid_days == right_days || !possible(frequency, mid_days + 1, no_of_participants)) { printf("%d\n", mid_days); return 0; } else { left_days = mid_days + 1; } } else { right_days = mid_days - 1; } } return 0; } ================================================ FILE: C Programs/C Programs 24/Playing Piano.cpp ================================================ #include #include #include using namespace std; const int NO_OF_FINGERS = 5, MAX_NOTES = 2e5 + 5; int is_possible[MAX_NOTES][NO_OF_FINGERS]; int main() { int no_of_notes; cin >> no_of_notes; vector notes(no_of_notes + 1); for(int i = 1; i <= no_of_notes; i++) cin >> notes[i]; memset(is_possible, false, sizeof(is_possible)); for(int i = 1; i <= no_of_notes; i++) { for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(i == 1) { is_possible[i][finger] = true; continue; } if(notes[i - 1] <= notes[i]) { for(int previous_finger = 1; previous_finger < finger; previous_finger++) { if(is_possible[i - 1][previous_finger]) { is_possible[i][finger] = true; } } } if(notes[i - 1] >= notes[i]) { for(int previous_finger = NO_OF_FINGERS; previous_finger > finger; previous_finger--) { if(is_possible[i - 1][previous_finger]) { is_possible[i][finger] = true; } } } } } int fingering_possible = false; for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[no_of_notes][finger]) fingering_possible = true; } if(!fingering_possible) { cout << "-1\n"; return 0; } vector playing_finger(no_of_notes + 1); for(int i = no_of_notes; i >= 1; i--) { if(i == no_of_notes) { for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[i][finger]) { playing_finger[i] = finger; break; } } continue; } if(notes[i] < notes[i + 1]) { for(int finger = playing_finger[i + 1] - 1; finger >= 1; finger--) { if(is_possible[i][finger]) { playing_finger[i] = finger; break; } } } if(notes[i] > notes[i + 1]) { for(int finger = playing_finger[i + 1] + 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[i][finger]) { playing_finger[i] = finger; break; } } } if(notes[i] == notes[i + 1]) { for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[i][finger] && finger != playing_finger[i + 1]) { playing_finger[i] = finger; break; } } } } for(int i = 1; i <= no_of_notes; i++) cout << playing_finger[i] << " "; return 0; } ================================================ FILE: C Programs/C Programs 24/Posterized.cpp ================================================ #include #include using namespace std; int main() { int no_of_colours, group_size; scanf("%d %d", &no_of_colours, &group_size); const int MAX_COLOUR = 255; vector colour(no_of_colours + 1); for(int i = 1; i <= no_of_colours; i++) scanf("%d", &colour[i]); vector key(MAX_COLOUR + 1); vector used(MAX_COLOUR + 1, false); for(int i = 1; i <= no_of_colours; i++) { int current_colour = colour[i]; if(!used[current_colour]) { int first_colour = max(0, current_colour - group_size + 1); while(used[first_colour] && key[first_colour] + group_size - 1 < current_colour) first_colour++; if(!used[first_colour]) key[first_colour] = first_colour, used[first_colour] = true; for(int j = first_colour + 1; j <= current_colour; j++) { key[j] = key[first_colour]; used[j] = true; } } } for(int i = 1; i <= no_of_colours; i++) printf("%d ", key[colour[i]]); return 0; } ================================================ FILE: C Programs/C Programs 24/Powers of Two.cpp ================================================ #include #include using namespace std; int is_bit_set(int position, int n) { return ( (n&(1 << position)) != 0); } int main() { int n, no_of_summands; cin >> n >> no_of_summands; int no_of_summands_made = 0; const int MAX_POWER = 32; vector frequency(MAX_POWER, 0); for(int i = 0; i < MAX_POWER; i++) { if(is_bit_set(i, n)) { frequency[i]++; no_of_summands_made++; } } if(no_of_summands < no_of_summands_made || no_of_summands > n) { cout << "NO\n"; return 0; } cout << "YES\n"; while(no_of_summands_made < no_of_summands) { for(int i = 1; i < MAX_POWER; i++) { if(frequency[i] > 0) //Break 2^i into 2^{i - 1} and 2^{i - 1} { frequency[i]--; frequency[i - 1] += 2; no_of_summands_made++; break; } } } for(int i = 0; i < MAX_POWER; i++) { for(int j = 0; j < frequency[i]; j++) { cout << (1 << i) << " "; } } return 0; } ================================================ FILE: C Programs/C Programs 24/Splitting into Digits.cpp ================================================ #include using namespace std; int main() { int n; cin >> n; cout << n << "\n"; for(int i = 1; i <= n; i++) cout << "1 "; return 0; } ================================================ FILE: C Programs/C Programs 24/Stages.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_letters, required_letters; string S; cin >> no_of_letters >> required_letters >> S; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < no_of_letters; i++) present[S[i] - 'a'] = true; int sum = 0, chosen = 0; for(int i = 0; i < NO_OF_ALPHABETS && chosen < required_letters; i++) { if(present[i]) { chosen++; sum += i + 1; i++; } } cout << (chosen < required_letters ? -1 : sum); return 0; } ================================================ FILE: C Programs/C Programs 24/Tanya and Candies.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 5, EVEN = 0, ODD = 1; long long sum_till[MAX_N][2], sum_from[MAX_N][2]; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; sum_till[0][ODD] = sum_till[0][EVEN] = 0; for(int i = 1; i <= no_of_elements; i++) { sum_till[i][ODD] = sum_till[i - 1][ODD]; sum_till[i][EVEN] = sum_till[i - 1][EVEN]; sum_till[i][i%2] += A[i]; } sum_from[no_of_elements + 1][ODD] = sum_from[no_of_elements + 1][EVEN] = 0; for(int i = no_of_elements; i >= 1; i--) { sum_from[i][ODD] = sum_from[i + 1][ODD]; sum_from[i][EVEN] = sum_from[i + 1][EVEN]; sum_from[i][i%2] += A[i]; } int no_of_points = 0; for(int i = 1; i <= no_of_elements; i++) { no_of_points += (sum_till[i - 1][EVEN] + sum_from[i + 1][ODD] == sum_till[i - 1][ODD] + sum_from[i + 1][EVEN]); } cout << no_of_points; return 0; } ================================================ FILE: C Programs/C Programs 24/The Way to Home.cpp ================================================ #include #include #include using namespace std; int main() { int length, max_jump; cin >> length >> max_jump; string path; cin >> path; const int oo = 1e9; vector minimum_jumps_to_reach(length, 0); minimum_jumps_to_reach[0] = 0; for(int i = 1; i < length; i++) { minimum_jumps_to_reach[i] = oo; if(path[i] == '0') continue; for(int j = 1; j <= max_jump && i - j >= 0; j++) { minimum_jumps_to_reach[i] = min(minimum_jumps_to_reach[i], 1 + minimum_jumps_to_reach[i - j]); } } cout << (minimum_jumps_to_reach[length - 1] == oo ? -1 : minimum_jumps_to_reach[length - 1]); return 0; } ================================================ FILE: C Programs/C Programs 24/Vanya and Label.cpp ================================================ #include #include #include using namespace std; int is_bit_set(int n, int position) { return ( (n&(1 << position)) != 0); } int value(char n) { if('0' <= n && n <= '9') return n - '0'; if('A' <= n && n <= 'Z') return 10 + n - 'A'; if('a' <= n && n <= 'z') return 36 + n - 'a'; if(n == '-')return 62; if(n == '_') return 63; } int main() { string S; cin >> S; long long no_of_ways = 1; const int MOD = 1e9 + 7; for(int i = 0; i < S.size(); i++) { for(int bit = 0; bit < 6; bit++) { if(!is_bit_set(value(S[i]), bit)) { no_of_ways = (no_of_ways*3)%MOD; } } } cout << no_of_ways; return 0; } ================================================ FILE: C Programs/C Programs 24/Where_Do_I_Turn.c ================================================ #include int main() { int a_x, a_y, b_x, b_y, c_x, c_y; scanf("%d %d %d %d %d %d", &a_x, &a_y, &b_x, &b_y, &c_x, &c_y); //Cross_product if( (c_y - b_y)*1LL*(b_x - a_x) - (b_y - a_y)*1LL*(c_x - b_x) == 0 ) printf("TOWARDS\n"); else if( (c_y - b_y)*1LL*(b_x - a_x) - (b_y - a_y)*1LL*(c_x - b_x) > 0 ) printf("LEFT\n"); else printf("RIGHT\n"); return 0; } ================================================ FILE: C Programs/C Programs 24/Zero Quantity Maximisation.cpp ================================================ #include #include #include #include typedef long long LL; using namespace std; struct fraction { long long numerator, denominator; fraction(){} fraction(long long N, long long D) { long long G = __gcd(abs(N), abs(D)); numerator = N/G; denominator = D/G; if(denominator < 0) { numerator *= -1; denominator *= -1; } } const int operator <(const fraction &F) const { return (denominator*F.numerator - numerator*F.denominator < 0); } }; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> B[i]; int both_zeroes = 0; for(int i = 1; i <= no_of_elements; i++) both_zeroes += (A[i] == 0 && B[i] == 0); map frequency; for(int i = 1; i <= no_of_elements; i++) { if(A[i] == 0) continue; frequency[fraction(-B[i], A[i])]++; } int max_frequency = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { max_frequency = max(max_frequency, it->second); } int answer = max_frequency + both_zeroes; cout << answer; return 0; } ================================================ FILE: Contests/463 Div 1 + 2 ICM Technex/Explanations/Team Work Explanation.txt ================================================ We want to find sum_{i = 1}^n C(n, i) i^k We know that (1 + x)^n = sum_{i = 0}^n C(n, i) x^i If we replace x = 1, then we get 2^n. How do we get the term i^k there ? There is a well known technique in evaluating sums of this nature. We will find the derivative of this function with x, and then multiply it with x n (1 + x)^{n - 1} = x sum_{i = 0}^n C(n, i) i x^{i - 1} = sum_{i = 0}^n C(n, i) i x^i We have succeeded in getting i inside the summation ! If we repeat this step k times, we will get i^k inside and then we just need to replace x = 1 in the LHS to get the value of the sum. The question is how do we do this through programming. ------ There is a very instructive technique. Let f(k, b, c) denote the result of applying the 'differentiate-and-then-multiply' step 'k' times on the polynomial x^b (1 + x)^c In one step, it becomes x[b.x^{b - 1} (1 + x)^c + c.x^b(1 + x)^{c - 1}] = b.x^b (1 + x)^c + c x^{b + 1} (1 + x)^{c - 1} = b.f(k - 1, b, c) + c.f(k - 1, b + 1, c - 1) ------ Another small, but important thing - Although it looks like it is O(n^3) space, it is O(n^2) space because b + c is invariant. We do not need to keep track of both states in space. ------ long long f(long long differentiations, long long b, long long c) { if(no_of_ways[differentiations][b] != -1) { return no_of_ways[differentiations][b]; } //x^b(1 + x)^c becomes x[bx^{b - 1}(1 + x)^c + cx^b(1 + x)^{c - 1}] //f(a, b, c) = b.f(a - 1, b, c) + c.f(a - 1, b + 1, c - 1) if(differentiations == 0) { return no_of_ways[differentiations][b] = power_mod(2, c); } long long term_1 = b*f(differentiations - 1, b, c); long long term_2 = (c == 0 ? 0 : c*f(differentiations - 1, b + 1, c - 1)); return no_of_ways[differentiations][b] = (term_1 + term_2)%MOD; } ================================================ FILE: Contests/463 Div 1 + 2 ICM Technex/Programs/Team Work.cpp ================================================ #include #include using namespace std; const int MAX_N = 5005, MOD = 1e9 + 7; long long no_of_ways[MAX_N][MAX_N]; long long power_mod(long long x, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } long long f(long long differentiations, long long b, long long c) { if(no_of_ways[differentiations][b] != -1) { return no_of_ways[differentiations][b]; } //x^b(1 + x)^c becomes x[bx^{b - 1}(1 + x)^c + cx^b(1 + x)^{c - 1}] //f(a, b, c) = b.f(a - 1, b, c) + c.f(a - 1, b + 1, c - 1) if(differentiations == 0) { return no_of_ways[differentiations][b] = power_mod(2, c); } long long term_1 = b*f(differentiations - 1, b, c); long long term_2 = (c == 0 ? 0 : c*f(differentiations - 1, b + 1, c - 1)); return no_of_ways[differentiations][b] = (term_1 + term_2)%MOD; } int main() { long long no_of_people, k; cin >> no_of_people >> k; memset(no_of_ways, -1, sizeof(no_of_ways)); cout << f(k, 0, no_of_people) << "\n"; return 0; } ================================================ FILE: Contests/607 Div 1 + 2/Explanations/Azamon Web Services Explanation.txt ================================================ Swap a character to the minimum character in it's suffix. In case of a tie, choose the rightmost character. ----- void solve() { string word_1, word_2; cin >> word_1 >> word_2; for(int i = 0; i < word_1.size(); i++) { char minimum = word_1[i]; int position = i; for(int j = i + 1; j < word_1.size(); j++) { if(word_1[j] <= minimum) { minimum = word_1[j]; position = j; } } if(minimum < word_1[i]) { swap(word_1[i], word_1[position]); break; } } cout << (word_1 < word_2 ? word_1 : "---") << "\n"; } ================================================ FILE: Contests/607 Div 1 + 2/Explanations/Beingawesomeism Explanation.txt ================================================ The crucial insight here is that the answer is always 4. Let us see how. Impossible Case - The entire grid is P and so it can't be made A, regardless of what we do. ----- Case 1 - The answer is 0 - This is when the entire grid is A and there is nothing left for us to do. ----- Case 2 - The answer is 1 This happens if any corner row or corner column is all A. We can simply make it propagate throughout the entire grid in 1 move. ----- Case 3 - The answer is 2 This happens if any of the 4 corner squares are A Or any non-corner edge is completely full. If any square of the corner edge is full, then a. Move 1 - Make the entire edge A b. Move 2 - Reduces to Case 1 If any non-corner edge is completely full, then a. Move 1 - Propagate it towards the right/up b. Move 2 - Propagate it towards the left/down ----- Case 4 - The answer is 3 This happens if any square of the corner edge is full. a. Move 1 - Make right/up of the corner edge full b. Move 2 - Make left/down of the corner edge full c. Move 3 - We have a complete corner edge. This is Case 1 ---- Case 5 - The answer is 4 If there is at least 1 A somewhere in the grid a. Move 1 - Make right/up of the edge full b. Move 2 - Make left/down of the edge full c. Move 3 - Propagate the edge in right/up direction d. Move 4 - Propagate the edge in left/down direction ----- return true; } int all_p(int rows, int columns) { for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(grid[i][j] == 'A') { return false; } } } return true; } int all_a(int rows, int columns) { for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(grid[i][j] == 'P') { return false; } } } return true; } int corner_square(int rows, int columns) { return (grid[0][0] == 'A' || grid[0][columns - 1] == 'A' || grid[rows - 1][0] == 'A' || grid[rows - 1][columns - 1] == 'A'); } int corner_edge_square(int rows, int columns) { for(int c = 0; c < columns; c++) { if(grid[0][c] == 'A' || grid[rows - 1][c] == 'A') { return true; } } for(int r = 0; r < rows; r++) { if(grid[r][0] == 'A' || grid[r][columns - 1] == 'A') { return true; } } return false; } int full_corner_edges(int rows, int columns) { if(full_row_a(0, columns) || full_row_a(rows - 1, columns)) { return true; } if(full_column_a(rows, 0) || full_column_a(rows, columns - 1)) { return true; } return false; } int any_full_edge(int rows, int columns) { for(int i = 0; i < rows; i++) { if(full_row_a(i, columns)) { return true; } } for(int i = 0; i < columns; i++) { if(full_column_a(rows, i)) { return true; } } return false; } void solve() { int rows, columns; cin >> rows >> columns; for(int i = 0; i < rows; i++) { cin >> grid[i]; } if(all_p(rows, columns)) { cout << "MORTAL\n"; return; } else if(all_a(rows, columns)) { cout << "0\n"; return; } else if(full_corner_edges(rows, columns)) { cout << "1\n"; return; } else if(corner_square(rows, columns) || any_full_edge(rows, columns)) { cout << "2\n"; return; } else if(corner_edge_square(rows, columns)) { cout << "3\n"; return; } else { cout << "4\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/607 Div 1 + 2/Explanations/Cut and Paste Explanation.txt ================================================ We can simulate the process. We only need the first x characters so we will simulate it till the length of the string is <= x For each i, we will count how many times the suffix is added to the end of the string ----- void solve() { int no_of_steps; cin >> no_of_steps; string S; cin >> S; const int MAX = 1e6, MOD = 1e9 + 7; long long length = S.size(); for(int i = 0; i < no_of_steps; i++) { long long suffix = ((length - 1) - i + MOD)%MOD; if(S[i] == '1') { continue; } else if(S[i] == '2') { length = (length + suffix)%MOD; for(int j = 1; j <= suffix && S.size() <= min(MAX, no_of_steps); j++) { S += S[i + j]; } } else if(S[i] == '3') { length = (length + 2*suffix)%MOD; for(int k = 1; k <= 2; k++) { for(int j = 1; j <= suffix && S.size() <= min(MAX, no_of_steps); j++) { S += S[i + j]; } } } } cout << length << "\n"; } ================================================ FILE: Contests/607 Div 1 + 2/Explanations/Jeremy Bearimy Explanation.txt ================================================ We need to think about how many times a particular edge is counted. The main insight here is that each edge of a tree is a bridge between 2 Components. Minimizing Weight - When we try to minimize the weight, we will look at each edge and try to minimise the number of times it is counted. We will put pairs into 1 component. If both components are of even size, then it will be counted 0 times. If both components are odd, then this edge will be counted once. Maximizing Weight - When we try to maximize the weight, we want each edge to be counted as many times as possible. We will try to make each pair cross this edge. Suppose the component sizes are C and D, and C < D, then we will put C distinct numbers in the component and all their counterparts on the other end. Hence, the edge is counted min(C, D) times. --- How do we find out the size of the subtree on either side of an edge (u, v) ? 1. We will perform a DFS and compute the size of the subtree rooted at v. 2. For every vertex v, we will keep track of it's parent u 3. While calculating the sizes of the 2 components (u, v) One of the components will be the subtree rooted at u and the other will be all the other vertices. ----- void dfs(int v, int parent_v) { parent[v] = parent_v; subtree_size[v] = 1; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); subtree_size[v] += subtree_size[child_v]; } } ---- struct Edge { int u, v; long long weight; Edge(){}; Edge(int U, int V, long long W) { u = U; v = V; weight = W; } }; void solve() { int no_of_pairs; cin >> no_of_pairs; int no_of_vertices = 2*no_of_pairs; int no_of_edges = no_of_vertices - 1; vector E(no_of_edges + 1); tree.resize(no_of_vertices + 1); subtree_size.resize(no_of_vertices + 1); parent.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { tree[i].clear(); subtree_size[i] = 0; parent[i] = 0; } for(int i = 1; i <= no_of_edges; i++) { cin >> E[i].u >> E[i].v >> E[i].weight; tree[E[i].u].push_back(E[i].v); tree[E[i].v].push_back(E[i].u); } dfs(1, 0); long long minimum = 0, maximum = 0; for(int i = 1; i <= no_of_edges; i++) { int u_subtree, v_subtree; if(parent[E[i].v] == E[i].u) { v_subtree = subtree_size[E[i].v]; u_subtree = no_of_vertices - v_subtree; } else { u_subtree = subtree_size[E[i].u]; v_subtree = no_of_vertices - u_subtree; } int minimum_component = min(u_subtree, v_subtree); maximum += minimum_component*E[i].weight; minimum += (u_subtree%2 == 1 || v_subtree%2 == 1 ? E[i].weight : 0); } cout << minimum << " " << maximum << "\n"; } ================================================ FILE: Contests/607 Div 1 + 2/Explanations/Suffix Three Explanation.txt ================================================ We can just use a switch-case construct to answer this problem. ----- void solve() { string word; cin >> word; switch(word[word.size() - 1]) { case 'o': cout << "FILIPINO\n"; return; case 'u': cout << "JAPANESE\n"; return; case 'a': cout << "KOREAN\n"; return; } } ================================================ FILE: Contests/607 Div 1 + 2/Programs/Azamon Web Services.cpp ================================================ #include using namespace std; void solve() { string word_1, word_2; cin >> word_1 >> word_2; for(int i = 0; i < word_1.size(); i++) { char minimum = word_1[i]; int position = i; for(int j = i + 1; j < word_1.size(); j++) { if(word_1[j] <= minimum) { minimum = word_1[j]; position = j; } } if(minimum < word_1[i]) { swap(word_1[i], word_1[position]); break; } } cout << (word_1 < word_2 ? word_1 : "---") << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/607 Div 1 + 2/Programs/Beingawesomeism.cpp ================================================ #include using namespace std; const int MAX_N = 67; char grid[MAX_N][MAX_N]; int full_row_a(int r, int columns) { for(int c = 0; c < columns; c++) { if(grid[r][c] != 'A') { return false; } } return true; } int full_column_a(int rows, int c) { for(int r = 0; r < rows; r++) { if(grid[r][c] != 'A') { return false; } } return true; } int all_p(int rows, int columns) { for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(grid[i][j] == 'A') { return false; } } } return true; } int all_a(int rows, int columns) { for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { if(grid[i][j] == 'P') { return false; } } } return true; } int corner_square(int rows, int columns) { return (grid[0][0] == 'A' || grid[0][columns - 1] == 'A' || grid[rows - 1][0] == 'A' || grid[rows - 1][columns - 1] == 'A'); } int corner_edge_square(int rows, int columns) { for(int c = 0; c < columns; c++) { if(grid[0][c] == 'A' || grid[rows - 1][c] == 'A') { return true; } } for(int r = 0; r < rows; r++) { if(grid[r][0] == 'A' || grid[r][columns - 1] == 'A') { return true; } } return false; } int full_corner_edges(int rows, int columns) { if(full_row_a(0, columns) || full_row_a(rows - 1, columns)) { return true; } if(full_column_a(rows, 0) || full_column_a(rows, columns - 1)) { return true; } return false; } int any_full_edge(int rows, int columns) { for(int i = 0; i < rows; i++) { if(full_row_a(i, columns)) { return true; } } for(int i = 0; i < columns; i++) { if(full_column_a(rows, i)) { return true; } } return false; } void solve() { int rows, columns; cin >> rows >> columns; for(int i = 0; i < rows; i++) { cin >> grid[i]; } if(all_p(rows, columns)) { cout << "MORTAL\n"; return; } else if(all_a(rows, columns)) { cout << "0\n"; return; } else if(full_corner_edges(rows, columns)) { cout << "1\n"; return; } else if(corner_square(rows, columns) || any_full_edge(rows, columns)) { cout << "2\n"; return; } else if(corner_edge_square(rows, columns)) { cout << "3\n"; return; } else { cout << "4\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/607 Div 1 + 2/Programs/Cut and Paste.cpp ================================================ #include using namespace std; void solve() { int no_of_steps; cin >> no_of_steps; string S; cin >> S; const int MAX = 1e6, MOD = 1e9 + 7; long long length = S.size(); for(int i = 0; i < no_of_steps; i++) { long long suffix = ((length - 1) - i + MOD)%MOD; if(S[i] == '1') { continue; } else if(S[i] == '2') { length = (length + suffix)%MOD; for(int j = 1; j <= suffix && S.size() <= min(MAX, no_of_steps); j++) { S += S[i + j]; } } else if(S[i] == '3') { length = (length + 2*suffix)%MOD; for(int k = 1; k <= 2; k++) { for(int j = 1; j <= suffix && S.size() <= min(MAX, no_of_steps); j++) { S += S[i + j]; } } } } cout << length << "\n"; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/607 Div 1 + 2/Programs/Jeremy Bearimy.cpp ================================================ #include #include using namespace std; struct Edge { int u, v; long long weight; Edge(){}; Edge(int U, int V, long long W) { u = U; v = V; weight = W; } }; vector > tree; vector subtree_size; vector parent; void dfs(int v, int parent_v) { parent[v] = parent_v; subtree_size[v] = 1; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i]; if(child_v == parent_v) { continue; } dfs(child_v, v); subtree_size[v] += subtree_size[child_v]; } } void solve() { int no_of_pairs; cin >> no_of_pairs; int no_of_vertices = 2*no_of_pairs; int no_of_edges = no_of_vertices - 1; vector E(no_of_edges + 1); tree.resize(no_of_vertices + 1); subtree_size.resize(no_of_vertices + 1); parent.resize(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { tree[i].clear(); subtree_size[i] = 0; parent[i] = 0; } for(int i = 1; i <= no_of_edges; i++) { cin >> E[i].u >> E[i].v >> E[i].weight; tree[E[i].u].push_back(E[i].v); tree[E[i].v].push_back(E[i].u); } dfs(1, 0); long long minimum = 0, maximum = 0; for(int i = 1; i <= no_of_edges; i++) { int u_subtree, v_subtree; if(parent[E[i].v] == E[i].u) { v_subtree = subtree_size[E[i].v]; u_subtree = no_of_vertices - v_subtree; } else { u_subtree = subtree_size[E[i].u]; v_subtree = no_of_vertices - u_subtree; } int minimum_component = min(u_subtree, v_subtree); maximum += minimum_component*E[i].weight; minimum += (u_subtree%2 == 1 || v_subtree%2 == 1 ? E[i].weight : 0); } cout << minimum << " " << maximum << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/607 Div 1 + 2/Programs/Suffix Three.cpp ================================================ #include using namespace std; void solve() { string word; cin >> word; switch(word[word.size() - 1]) { case 'o': cout << "FILIPINO\n"; return; case 'u': cout << "JAPANESE\n"; return; case 'a': cout << "KOREAN\n"; return; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/609 Div 2/Explanations/Equation Explanation.txt ================================================ There are many ways to solve it but the simplest will use the observation that if n is not composite then some multiple of n will be composite. n = (X + 1).n - X.n We just need two values where we are sure X.n is composite. X = 8 does that. n = 9n - 8n ------ #include using namespace std; int main() { int n; cin >> n; cout << 9*n << " " << 8*n << "\n"; return 0; } ================================================ FILE: Contests/609 Div 2/Programs/Equation.cpp ================================================ #include using namespace std; int main() { int n; cin >> n; cout << 9*n << " " << 8*n << "\n"; return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Explanations/Antipalindrome Alternate Solution Explanation.txt ================================================ Blog Link - http://qr.ae/TUT345 The constraints are small enough to allow for an O(n^3) solution where all substrings are checked but there's an elegant O(n) solution ! Case 1: S is not a palindrome, then answer = n. Case 2: S is a palindrome. then we check S[1, ... , n - 1] and S[2, ... n] If either of these strings are not a palindrome, then the answer = n - 1 Case 3: S, S[1, ... , n - 1] and S[2, ... , n] are all palindromes. In that case, Notice S[1] = S[n], from 1 S[2] = S[n], from 3 Also, S[2] = S[n - 1], from 1 And S[1] = S[n - 1], from 2 So, this implies S[1] = S[2] = S[n - 1] = S[n - 2] Similarly, we see from 1, that S[i] = S[n - i] And S[i] = S[n - 1 - i] So, S[n - i] = S[n - 1 - i] We continually apply the above inequality to show that all characters are the same. If that's the case, then ANY substring will be a palindrome. -------------------------------- Therefore, the answer is either n, n - 1 or 0. ----------------------------------------------- int main() { string S; cin >> S; int length = S.size(); if(!is_palindrome(S, 0, length - 1)) cout << length; else if(!is_palindrome(S, 0, length - 2) || !is_palindrome(S, 1, length - 1)) cout << length - 1; else cout << "0"; return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Explanations/Antipalindrome Explanation.txt ================================================ N is very small. Check all choose(N, 2) substrings if they're palindromes, starting from the longest substrings. This is O(N^3). --------------------------------------- int is_palindrome(string S) { for(int i = 0; i < S.size(); i++) if(S[i] != S[S.size() - 1 - i]) return false; return true; } int main() { string S; cin >> S; for(int length = S.size(); length >= 1; length--) { for(int i = 0; i + length - 1 < S.size(); i++) { if(!is_palindrome(S.substr(i, length))) { cout << length; return 0; } } } cout << "0"; return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Explanations/Bookshelves Explanation.txt ================================================ Blog Link - http://qr.ae/TUTmQ6 Let us answer, a related question. If given a number x, how do we determine if it is possible to divide the numbers into K segments such that the bitwise AND of the sum of the K segments = x ? Each segment[L, R] has to obey the following property - (Sum[R] - Sum[L - 1])&x = x, i.e. all the bits that are set in x, must be set in the sum from [L, ... , R] for each of the K segments ! We can check this with dynamic programming. Let f(n, k) = true, if it is possible for the bitwise-AND of the sums of the first K segments = x, with the last segment ending on n. And f(n, k) = false, otherwise. f(R, K) = true, if there exists some L < R, such that Sum[L ... R]&x = x and f(L - 1, K - 1) = true. It takes us O(N^2 K) time to answer one such question. Now, let us be greedy and start from i = 60, and check if answer + 2^i is possible, if it is then the answer = answer + 2^i. This is always optimal. Overall Complexity = O(log(S) N^2 K) ----------------------------------------------- int is_possible(LL goal) { memset(possible, false, sizeof(possible)); possible[0][0] = true; for(int part = 1; part <= no_of_parts; part++) { for(int right = 1; right <= no_of_elements; right++) { for(int left = 0; left < right; left++) { if( possible[left][part - 1] && ( ( (sum[right] - sum[left])&goal ) == goal ) ) { possible[right][part] = true; break; } } } } return possible[no_of_elements][no_of_parts]; } int main() { scanf("%d %d", &no_of_elements, &no_of_parts); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); sum[0] = 0; for(int i = 1; i <= no_of_elements; i++) sum[i] = sum[i - 1] + A[i]; LL answer = 0; for(int bit = MAX_BIT; bit >= 0; bit--) { if(is_possible(answer|(1LL << bit))) { answer |= (1LL << bit); } } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Explanations/Businessman Problems Explanation.txt ================================================ For every item x, we add max{A_cost[x], B_cost[x]} If x does not exist in either A or B, then it is 0. We can use maps to do this ! While reading A_cost, just read in cost[x]. While reading B_cost, then cost[x] = max{cost[x], cost} ------------------------------------------------- int main() { int a_elements; scanf("%d", &a_elements); map cost; for(int i = 1; i <= a_elements; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = cost_i; } int b_elements; scanf("%d", &b_elements); for(int i = 1; i <= b_elements; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = max(cost[element_i], cost_i); } long long total_cost = 0; for(map :: iterator it = cost.begin(); it != cost.end(); it++) { total_cost += it->second; } printf("%I64d\n", total_cost); return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Explanations/Useful Decomposition Explanation.txt ================================================ We root the tree at a vertex V, and we make a path from V to each of it's leaves. We can always decompose a tree, unless V has some descendant that has more than one child. So, here's what we do 1. If the graph has more than one vertex which has 3 or more edges, then it is not possible. 2. If the graph has exactly one vertex which has 3 or more edges, then we root the tree at that vertex. If the graph has no such vertex, then it means every vertex has at most two edges (one parent and one child). We can arbitrarily root the graph at any of these vertices, then. Once we have a root, then make a path from the root the leaf vertex by going through each of the root's children. Note - You don't need to minimise the number of paths. Otherwise, the root is the vertex which has degree > 2, or the vertex with degree = 1, if all vertices have degree <= 2 Let us suppose we were asked to minimise or maximise the number of paths. Call a vertex a root if it's degree > 2. Case 1 : There is atleast one vertex with degree > 2 If there is more than one root, then the solution stays the same as a decomposition is not possible. If there was exactly one root, then we have to make it the root and the solution stays the same. Making any other vertex the root will not satisfy the given conditions. Case 2 : All vertices have degree <= 2 To minimise the number of paths, we must choose a leaf vertex since it has only one child and it will result in 1 simple path from one leaf to another. For maximising the number of paths, we will have to pick any non-leaf vertex which has a degree of 2. There will be two paths, one to each leaf. ---------------------------------------- int dfs_leaf_from(int v, int parent) { if(graph[v].size() == 1) return v; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(child == parent) continue; return dfs_leaf_from(child, v); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int i = 1; i < no_of_vertices; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } int no_of_roots = 0, root = 1; for(int i = 1; i <= no_of_vertices; i++) { if(graph[i].size() > 2) { no_of_roots++; root = i; } } if(no_of_roots > 1) { printf("No\n"); return 0; } printf("Yes\n"); int no_of_paths = graph[root].size(); printf("%d\n", no_of_paths); for(int i = 0; i < graph[root].size(); i++) { int child = graph[root][i]; int leaf = dfs_leaf_from(child, root); printf("%d %d\n", root, leaf); } return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Programs/Antipalindrome Alternate Solution.cpp ================================================ #include #include using namespace std; int is_palindrome(string S, int left, int right) { while(left <= right) { if(S[left++] != S[right--]) return false; } return true; } int main() { string S; cin >> S; int length = S.size(); if(!is_palindrome(S, 0, length - 1)) cout << length; else if(!is_palindrome(S, 0, length - 2) || !is_palindrome(S, 1, length - 1)) cout << length - 1; else cout << "0"; return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Programs/Antipalindrome.cpp ================================================ #include using namespace std; int is_palindrome(string S) { for(int i = 0; i < S.size(); i++) if(S[i] != S[S.size() - 1 - i]) return false; return true; } int main() { string S; cin >> S; for(int length = S.size(); length >= 1; length--) { for(int i = 0; i + length - 1 < S.size(); i++) { if(!is_palindrome(S.substr(i, length))) { cout << length; return 0; } } } cout << "0"; return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Programs/Bookshelves.cpp ================================================ #include #include const int MAX_BIT = 61, MAX_N = 55; typedef long long LL; int no_of_elements, no_of_parts; LL A[MAX_N], sum[MAX_N]; int possible[MAX_N][MAX_N]; int is_possible(LL goal) { memset(possible, false, sizeof(possible)); possible[0][0] = true; for(int part = 1; part <= no_of_parts; part++) { for(int right = 1; right <= no_of_elements; right++) { for(int left = 0; left < right; left++) { if( possible[left][part - 1] && ( ( (sum[right] - sum[left])&goal ) == goal ) ) { possible[right][part] = true; break; } } } } return possible[no_of_elements][no_of_parts]; } int main() { scanf("%d %d", &no_of_elements, &no_of_parts); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); sum[0] = 0; for(int i = 1; i <= no_of_elements; i++) sum[i] = sum[i - 1] + A[i]; LL answer = 0; for(int bit = MAX_BIT; bit >= 0; bit--) { if(is_possible(answer|(1LL << bit))) { answer |= (1LL << bit); } } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Programs/Businessman Problems.cpp ================================================ #include #include using namespace std; int main() { int a_element_is; scanf("%d", &a_element_is); map cost; for(int i = 1; i <= a_element_is; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = cost_i; } int b_element_is; scanf("%d", &b_element_is); for(int i = 1; i <= b_element_is; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = max(cost[element_i], cost_i); } long long total_cost = 0; for(map :: iterator it = cost.begin(); it != cost.end(); it++) { total_cost += it->second; } printf("%I64d\n", total_cost); return 0; } ================================================ FILE: Contests/Avito Code Challenge 2018/Programs/Useful Decomposition.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 15; vector graph[MAX_N]; int dfs_leaf_from(int v, int parent) { if(graph[v].size() == 1) return v; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(child == parent) continue; return dfs_leaf_from(child, v); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int i = 1; i < no_of_vertices; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } int no_of_roots = 0, root = 1; for(int i = 1; i <= no_of_vertices; i++) { if(graph[i].size() > 2) { no_of_roots++; root = i; } } if(no_of_roots > 1) { printf("No\n"); return 0; } printf("Yes\n"); int no_of_paths = graph[root].size(); printf("%d\n", no_of_paths); for(int i = 0; i < graph[root].size(); i++) { int child = graph[root][i]; int leaf = dfs_leaf_from(child, root); printf("%d %d\n", root, leaf); } return 0; } ================================================ FILE: Contests/Avito Cool Challenge 2018/Explanation/Colourful Bricks Explanation.txt ================================================ Blog Link - https://qr.ae/TUtWEt The number of ways of making the K + 1 groups is given by stars and bars - C(N - 1, K) The number of ways to colour them is M (M - 1)^K --------------- int main() { int no_of_bricks, no_of_colours, no_of_divisions; scanf("%d %d %d", &no_of_bricks, &no_of_colours, &no_of_divisions); int no_of_groups = no_of_divisions + 1; const int MOD = 998244353; long long group_size_count = choose(no_of_bricks - 1, no_of_divisions, MOD); long long colour_distribution_count = (no_of_colours* power_mod(no_of_colours - 1,no_of_groups - 1, MOD))%MOD; long long answer = (group_size_count*colour_distribution_count)%MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Avito Cool Challenge 2018/Explanation/Definite Game Explanation.txt ================================================ Whatever N is, we can subtract with N - 1 and get 1. The only exception is 2. Because it is the only integer for which N - 1 | N. ------------ int main() { int n; cin >> n; int minimum_value = (n <= 2 ? n : 1); cout << minimum_value; return 0; } ================================================ FILE: Contests/Avito Cool Challenge 2018/Programs/Colourful Bricks.cpp ================================================ #include #include using namespace std; long long power_mod(long long base, long long power, long long mod) { long long result = 1; while(power) { if(power%2 == 1) result = (result*base)%mod; base = (base*base)%mod; power = power >> 1; } return result; } long long inverse(long long n, long long mod) { return power_mod(n, mod - 2, mod); } long long choose(long long n, long long r, long long mod) { vector factorial(n + 1); factorial[0] = 1; for(int i = 1; i <= n; i++) factorial[i] = (i*factorial[i - 1])%mod; vector inverse_factorial(n + 1); // i*(i - 1)! = i! => i^(-1) (i - 1)!^(-1) = i!^(-1) inverse_factorial[n] = inverse(factorial[n], mod); for(int i = n - 1; i >= 0; i--) inverse_factorial[i] = ((i + 1)*inverse_factorial[i + 1])%mod; long long numerator = factorial[n]; long long denominator_inverse = (inverse_factorial[r]*inverse_factorial[n - r])%mod; return (numerator*denominator_inverse)%mod; } int main() { int no_of_bricks, no_of_colours, no_of_divisions; scanf("%d %d %d", &no_of_bricks, &no_of_colours, &no_of_divisions); int no_of_groups = no_of_divisions + 1; const int MOD = 998244353; long long group_size_count = choose(no_of_bricks - 1, no_of_divisions, MOD); long long colour_distribution_count = (no_of_colours* power_mod(no_of_colours - 1,no_of_groups - 1, MOD))%MOD; long long answer = (group_size_count*colour_distribution_count)%MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Avito Cool Challenge 2018/Programs/Definite Game.cpp ================================================ #include using namespace std; int main() { int n; cin >> n; int minimum_value = (n <= 2 ? n : 1); cout << minimum_value; return 0; } ================================================ FILE: Contests/Barcelona Bootcamp 2018/Explanation/Maximum Sum of Digits Explanation.txt ================================================ We try to maximise the number of 9s in the digit sum Let A = all 9s except the first digit. B = N - A ----------------------- int main() { string N; cin >> N; string A; A = N[0] - 1; for(int i = 1; i < N.size(); i++) A += '9'; long long n = to_int(N), a = to_int(A); long long b = n - a; cout << digit_sum(a) + digit_sum(b); return 0; } ================================================ FILE: Contests/Barcelona Bootcamp 2018/Explanation/Phone Numbers Explanation.txt ================================================ We can have at most N/11 strings. The number of strings can't be more than the number of 8s. If the number of 8s > N/11, then there will be N/11 strings. If N/11 > number of 8s, then there will be as many strings as there are 8s. In total number of strings = min(number of 8s, N/11) ----------------------- #include #include #define min(a, b) (a < b ? a : b) using namespace std; int main() { int length; string S; cin >> length >> S; int no_of_8 = 0; for(int i = 0; i < length; i++) no_of_8 += (S[i] == '8'); cout << min(no_of_8, length/11) << endl; return 0; } ================================================ FILE: Contests/Barcelona Bootcamp 2018/Explanation/Social Circles Explanation.txt ================================================ Let us imagine everyone is sitting at their own table at first. They will need max(l, r) + 1 chairs. Now, what happens if we want to combine first and second person to one table. We will need ... Max(l[1], r[2]) + Max(l[2], r[1]) + 2 This is equal to = Max(l[1], r[2]) + 1 + Max(l[2], r[1]) + 1 chairs. This is equal to what happens when there is a new person (l[1], r[2]) is sitting on his own table. ------------------------------------ Let Next(i) be the person sitting next to person i Now the number of chairs will be equal to N + sum[max{Left(i), Right(Next(i))}] Now we will prove that it is always optimal to match the smallest left to the smallest right. If we have matched l2 to r1 and l1 to something else - rx, Note that we cannot get more chairs by swapping and matching (l1, r1) and (l2, rx) ---------------------------- int main() { int no_of_guests; scanf("%d", &no_of_guests); vector left(no_of_guests + 1, 0), right(no_of_guests + 1, 0); for(int i = 1; i <= no_of_guests; i++) scanf("%d %d", &left[i], &right[i]); sort(all(left)); sort(all(right)); long long no_of_chairs = 0; for(int i = 1; i <= no_of_guests; i++) no_of_chairs += max(left[i], right[i]) + 1; printf("%I64d\n", no_of_chairs); return 0; } ================================================ FILE: Contests/Barcelona Bootcamp 2018/Programs/Maximum Sum of Digits.cpp ================================================ #include using namespace std; int digit_sum(long long n) { int sum = 0; while(n) { sum += n%10; n = n/10; } return sum; } long long to_int(string &S) { long long n = 0; for(int i = 0; i < S.size(); i++) n = n*10 + (S[i] - '0'); return n; } int main() { string N; cin >> N; string A; A = N[0] - 1; for(int i = 1; i < N.size(); i++) A += '9'; long long n = to_int(N), a = to_int(A); long long b = n - a; cout << digit_sum(a) + digit_sum(b); return 0; } ================================================ FILE: Contests/Barcelona Bootcamp 2018/Programs/Phone Numbers.cpp ================================================ #include #include #define min(a, b) (a < b ? a : b) using namespace std; int main() { int length; string S; cin >> length >> S; int no_of_8 = 0; for(int i = 0; i < length; i++) no_of_8 += (S[i] == '8'); cout << min(no_of_8, length/11) << endl; return 0; } ================================================ FILE: Contests/Barcelona Bootcamp 2018/Programs/Social Circles.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_guests; scanf("%d", &no_of_guests); vector left(no_of_guests + 1, 0), right(no_of_guests + 1, 0); for(int i = 1; i <= no_of_guests; i++) scanf("%d %d", &left[i], &right[i]); sort(all(left)); sort(all(right)); long long no_of_chairs = 0; for(int i = 1; i <= no_of_guests; i++) no_of_chairs += max(left[i], right[i]) + 1; printf("%I64d\n", no_of_chairs); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Explanations/Magic Stones Explanation.txt ================================================ Quora Blog Link - https://qr.ae/TUyM1P When we perform an operation, we swap adjacent elements of the difference array. If it is possible to go from A to B, then their difference arrays must be permutations of each other and the first elements must be equal. ---------- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; LL is_permutation(vector A, vector B) { sort(all(A)); sort(all(B)); int is_equal = (A.size() == B.size() ? true : false); for(int i = 0; i < A.size(); i++) { if(A[i] != B[i]) { is_equal = false; } } return is_equal; } void read(vector &A, int n) { for(int i = 0; i < n; i++) cin >> A[i]; } void get_difference(vector &A, vector &D) { for(int i = 0; i + 1 < A.size(); i++) { D.push_back(A[i + 1] - A[i]); } } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); read(A, no_of_elements); vector B(no_of_elements); read(B, no_of_elements); vector beginning_difference; get_difference(A, beginning_difference); vector ending_difference; get_difference(B, ending_difference); cout << (A[0] == B[0] && is_permutation(beginning_difference, ending_difference) ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Explanations/Meaningless Operations Explanation.txt ================================================ Blog Link - https://qr.ae/TUreZ2 If X = 2^N - 1, then precompute the answer offline for all N from 1 to 25. Else, the answer is always 2^N - 1, where N is the number of bits in X. We can get this by choosing Y as the complement of X. X xor Y = 2^N - 1 X and Y = 0 gcd(0, 2^N - 1) = 2^N - 1 This is the highest possible because the XOR and AND of two N bit number cannot have more than N bits. And gcd(a, b) <= max(a, b) ----------------- void solve() { int x; cin >> x; int max_gcd = (is_all_ones(x) ? answer[x] : all_ones(no_of_bits(x))); cout << max_gcd << "\n"; } void precompute() { answer[1] = 0; answer[3] = 1; answer[7] = 1; answer[15] = 5; answer[31] = 1; answer[63] = 21; answer[127] = 1; answer[255] = 85; answer[511] = 73; answer[1023] = 341; answer[2047] = 89; answer[4095] = 1365; answer[8191] = 1; answer[16383] = 5461; answer[32767] = 4681; answer[65535] = 21845; answer[131071] = 1; answer[262143] = 87381; answer[524287] = 1; answer[1048575] = 349525; answer[2097151] = 299593; answer[4194303] = 1398101; answer[8388607] = 178481; answer[16777215] = 5592405; answer[33554431] = 1082401; } int main() { precompute(); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Explanations/Parity Explanation.txt ================================================ N = \sum b^K a_k We merely find the parity by keeping track of each term mod 2. Take care that when k = 0, there is no term of b. It is just a_0 If b is even, then all powers of b are even and if b is odd, then all powers of b are odd. ----------------- int main() { int base, no_of_digits; cin >> base >> no_of_digits; int sum_parity = 0; for(int d = no_of_digits - 1; d >= 0; d--) { int digit; cin >> digit; int digit_parity = digit%2; int base_parity = base%2; if(d > 0) sum_parity += (digit_parity*base_parity); else sum_parity += digit_parity; } cout << (sum_parity%2 == 0 ? "Even\n" : "Odd\n"); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Explanations/Tape Explanation.txt ================================================ First, let us sort the N points given to us - A1, A2, ... , An. Next, let us take their distances - We will construct a difference array - D1, D2, ... , D(n - 1) Di = Ai - A(i - 1) ----------------- We will sort the N - 1 differences. We will then be greedy. We will start our first part from point 1, and then go right. If the distance between our current point Ai and next A(i + 1) is one of the (k - 1) greatest distances, then we will not use it. -------- Here is how we implement it - If a difference d belongs to one of the K - 1 greatest differences, then mark the ending i as 'not allowed'. Then start scanning the array A from 1 to N. Keep two pointers left and right. left points to the first point which we haven't counted yet and right points to the last point that is allowed from left. Maintain this invariant. We stop whenever right hits a point that is not allowed or reaches the end of the array. After we count the current segment [L, R], we set L = R + 1 and R to L + 1. ------------- int main() { int no_of_points, total_length, max_parts; cin >> no_of_points >> total_length >> max_parts; vector A(no_of_points); for(int i = 0; i < no_of_points; i++) cin >> A[i]; sort(all(A)); vector X; for(int i = 1; i < no_of_points; i++) X.push_back(Point(i, A[i] - A[i - 1])); sort(all(X)); vector allowed(no_of_points, true); for(int count = 1, i = X.size() - 1; i >= 0 && count < max_parts; count++, i--) { allowed[X[i].position] = false; } int left = 0, right = 1; int total_length_used = 0; while(left < no_of_points) { while(right < no_of_points && allowed[right]) { right++; } right--; total_length_used += (A[right] - A[left] + 1); left = right + 1; right = left + 1; } cout << total_length_used << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Programs/Magic Stones.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; LL is_permutation(vector A, vector B) { sort(all(A)); sort(all(B)); int is_equal = (A.size() == B.size() ? true : false); for(int i = 0; i < A.size(); i++) { if(A[i] != B[i]) { is_equal = false; } } return is_equal; } void read(vector &A, int n) { for(int i = 0; i < n; i++) cin >> A[i]; } void get_difference(vector &A, vector &D) { for(int i = 0; i + 1 < A.size(); i++) { D.push_back(A[i + 1] - A[i]); } } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); read(A, no_of_elements); vector B(no_of_elements); read(B, no_of_elements); vector beginning_difference; get_difference(A, beginning_difference); vector ending_difference; get_difference(B, ending_difference); cout << (A[0] == B[0] && is_permutation(beginning_difference, ending_difference) ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Programs/Meaningless Operations.cpp ================================================ #include #include using namespace std; map answer; int all_ones(int n) { return ( (1 << n) - 1); } int no_of_bits(int n) { int bit_count = 0; while(n) { bit_count++; n /= 2; } return bit_count; } int is_all_ones(int n) { return (all_ones(no_of_bits(n)) == n); } void solve() { int x; cin >> x; int max_gcd = (is_all_ones(x) ? answer[x] : all_ones(no_of_bits(x))); cout << max_gcd << "\n"; } void precompute() { answer[1] = 0; answer[3] = 1; answer[7] = 1; answer[15] = 5; answer[31] = 1; answer[63] = 21; answer[127] = 1; answer[255] = 85; answer[511] = 73; answer[1023] = 341; answer[2047] = 89; answer[4095] = 1365; answer[8191] = 1; answer[16383] = 5461; answer[32767] = 4681; answer[65535] = 21845; answer[131071] = 1; answer[262143] = 87381; answer[524287] = 1; answer[1048575] = 349525; answer[2097151] = 299593; answer[4194303] = 1398101; answer[8388607] = 178481; answer[16777215] = 5592405; answer[33554431] = 1082401; } int main() { precompute(); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Programs/Parity.cpp ================================================ #include using namespace std; int main() { int base, no_of_digits; cin >> base >> no_of_digits; int sum_parity = 0; for(int d = no_of_digits - 1; d >= 0; d--) { int digit; cin >> digit; int digit_parity = digit%2; int base_parity = base%2; if(d > 0) sum_parity += (digit_parity*base_parity); else sum_parity += digit_parity; } cout << (sum_parity%2 == 0 ? "Even\n" : "Odd\n"); return 0; } ================================================ FILE: Contests/CodeForces Global Round 1/Programs/Tape.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct Point { int position, difference; Point(int p, int d) { position = p, difference = d; } int operator <(const Point &P) { return (difference < P.difference); } }; int main() { int no_of_points, total_length, max_parts; cin >> no_of_points >> total_length >> max_parts; vector A(no_of_points); for(int i = 0; i < no_of_points; i++) cin >> A[i]; sort(all(A)); vector D; for(int i = 1; i < no_of_points; i++) D.push_back(Point(i, A[i] - A[i - 1])); sort(all(D)); vector allowed(no_of_points, true); for(int count = 1, i = D.size() - 1; i >= 0 && count < max_parts; count++, i--) { allowed[D[i].position] = false; } int left = 0, right = 1; int total_length_used = 0; while(left < no_of_points) { while(right < no_of_points && allowed[right]) { right++; } right--; total_length_used += (A[right] - A[left] + 1); left = right + 1; right = left + 1; } cout << total_length_used << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Explanations/Another One Bites the Dust Explanation.txt ================================================ We will match all the As with Bs and then append all the 'AB's. If we have an extra A, we will put it at the end. If we have an extra B, we will put it at the beginning. --- #include using namespace std; int main() { long long A, B, AB; cin >> A >> B >> AB; long long answer = (B != A ? 1 + 2*AB + 2*min(A, B) : 2*min(A, B) + 2*AB); cout << answer; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Explanations/Born This Way Explanation.txt ================================================ If we delete k flights in total, we will be deleting a from A and (b = k - a) from B. We will go over all possibilities and choose the best result It is always best to delete the first 'a' flights from A After that, the time we reach the airport will be A[a + 1] + T[a]. We will delete the immediate next (k - a) flights from B. We can find out the closest b, such that B[b] >= A[a + 1] + T[a] and then delete [b, b + (k - a) - 1] flights If we can delete all flights in A or all flights in B, we are done ------ int main() { int A_to_B, B_to_C, time_A_to_B, time_B_to_C, deleted; cin >> A_to_B >> B_to_C >> time_A_to_B >> time_B_to_C >> deleted; vector A(A_to_B + 1); for(int i = 1; i <= A_to_B; i++) { cin >> A[i]; } vector B(B_to_C + 1); for(int i = 1; i <= B_to_C; i++) { cin >> B[i]; } const long long oo = 1e15; long long max_time = (deleted >= A_to_B || deleted >= B_to_C ? oo : 0); A.push_back(oo); B.push_back(oo); for(int a_deletes = 0; a_deletes <= min(deleted, A_to_B - 1); a_deletes++) { long long reached_B = A[a_deletes + 1] + time_A_to_B; int first_b = upper_bound(B.begin(), B.end(), reached_B - 1) - B.begin(); int b_deletes = deleted - a_deletes + first_b - 1; if(b_deletes > B_to_C) { max_time = oo; break; } max_time = max(max_time, B[b_deletes + 1] + time_B_to_C); } cout << (max_time >= oo ? -1 : max_time) << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Explanations/Crazy Diamond Explanation.txt ================================================ For every element x, let P(x) denote the position where x currently is. We will scan the array from i = 1 to N. If (i = A[i]), we will not do anything. Otherwise, we will find out the current position of i, it is P(i). We want to swap A(i) and A(P(i)). We also want to update the array P. To make things simpler, let us abstract the complexity and create a function for swapping elements - void arrange_swaps(int start, int destination) { int original_start = A[start], original_destination = A[destination]; swap(A[start], A[destination]); position[original_start] = destination; position[original_destination] = start; swaps.push_back(make_pair(start, destination)); } --------- Now, let us see how we will swap. Let L = min{i, P(i)} and R = max{i, P(i)} We have to swap A[L] and A[R]. --- Case 1 - Both L and R are in the first half We can swap like this - swap(A[R], A[N]) swap(A[N], A[L]) => Now, A[R] has reached A[L] swap(A[N], A[R]) => Now, A[L] has reached A[R] ------ Case 2 - Both L and R are in the second half swap(A[L], A[1]) swap(A[1], A[R]) => Now, A[L] has reached A[R] swap(A[1], A[L]) => Now, A[R] has reached A[L]. Also, A[1] has reached it's correct position again. Please note that when we are at position i, A[1, ... i - 1] is sorted. So A[1] will hold 1. We need to take care that A[1] contains 1 after we are done. We do not need to worry about this in Case 1 since A[N] need not hold the correct value - N ------ Case 3 - L and R are in different halves Here, we will utilise both ends. swap(A[L], A[N]) swap(A[N], A[1]) swap(A[1], A[R]) => Now, A[L] has reached A[R] swap(A[1], A[N]) => Now, the correct value of A[1] has been put back in A[1] swap(A[N], A[L]) => Now, A[R] has reached A[L] ------ int main() { int no_of_elements; cin >> no_of_elements; for(int i =1 ; i <= no_of_elements; i++) cin >> A[i]; for(int i = 1; i <= no_of_elements; i++) position[A[i]] = i; for(int i = 1; i <= no_of_elements; i++) { if(i == A[i]) continue; int target = i; int target_position = position[target]; int left = min(target_position, i); int right = max(target_position, i); if(right - left >= no_of_elements/2) { arrange_swaps(i, target_position); continue; } if(left > no_of_elements/2) { arrange_swaps(1, left); arrange_swaps(1, right); arrange_swaps(left, 1); } else if(right <= no_of_elements/2) { arrange_swaps(right, no_of_elements); arrange_swaps(no_of_elements, left); } else { arrange_swaps(left, no_of_elements); arrange_swaps(no_of_elements, 1); arrange_swaps(1, right); arrange_swaps(1, no_of_elements); arrange_swaps(no_of_elements, left); } } cout << swaps.size() << "\n"; for(int i = 0; i < swaps.size(); i++) cout << swaps[i].first << " " << swaps[i].second << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Explanations/Dirty Deeds Done Dirt Cheap Explanation.txt ================================================ Let us notice that although the signs alternate between the numbers, the type of pairs stay the same. Either our sequence consists only of pairs (a, b) where (a < b) Or it consists only of pairs (a, b) where (a > b). ---- 1. We will store all pairs of 1 kind in a list. 2. We will sort it in such a way that we will get a valid ordering. ---- Let us consider pairs of the type (a < b) We want to order them in such a way that if pairs (P, Q) P comes before Q, then (P.a < P.b) > (Q.a < Q.b) We can sort the pairs by (P.b > Q.a). However, this is an invalid way of ordering the pairs. It is possible for (P < Q) and for (Q < P) at the same time. This causes a run time error and it is not a valid way of comparing or ordering. Instead, we can get around this by sorting in order of (P.b > Q.b) Then, (P.b > Q.b > Q.a) => P.b > Q.a --- Similarly, we will sort the other pairs in (P.a < Q.a) We want (P.a > P.b) < (Q.a < Q.b) (P.b < P.a < Q.a) => P.b < Q.a --- We can just sort by (P.a < Q.a) and we will get a valid ordering. The answer is just whichever pair occurs more times. --- struct pairs { int a, b, index; pairs() { a = 0; b = 0; }; pairs(int A, int B, int I) { a = A, b = B, index = I; } }; // (p1 < p2) > (q1 < q2) int sort_increasing_pairs(pairs &P, pairs &Q) { return (P.b > Q.b); } // (p1 > p2) < (q1 > q2) int sort_decreasing_pairs(pairs&P, pairs &Q) { return (P.a < Q.a); } int main() { int no_of_pairs; cin >> no_of_pairs; vector increasing, decreasing; for(int i = 1; i <= no_of_pairs; i++) { int x, y; cin >> x >> y; if(x < y) { increasing.push_back(pairs(x, y, i)); } else { decreasing.push_back(pairs(x, y, i)); } } sort(all(increasing), sort_increasing_pairs); sort(all(decreasing), sort_decreasing_pairs); if(increasing.size() >= decreasing.size()) { cout << increasing.size() << "\n"; for(int i = 0; i < increasing.size(); i++) { cout << increasing[i].index << " "; } } else { cout << decreasing.size() << "\n"; for(int i = 0; i < decreasing.size(); i++) { cout << decreasing[i].index << " "; } } return 0; } ---- Bonus - Suppose, we were not allowed to change the orders of the pairs. Then, we would have stored the indices of all pairs of one type in their sorted order and then look for the Longest Increasing Subsequence ================================================ FILE: Contests/CodeForces Global Round 3/Programs/Another One Bites the Dust.cpp ================================================ #include using namespace std; int main() { long long A, B, AB; cin >> A >> B >> AB; long long answer = (B != A ? 1 + 2*AB + 2*min(A, B) : 2*min(A, B) + 2*AB); cout << answer; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Programs/Born This Way.cpp ================================================ #include #include #include using namespace std; int main() { int A_to_B, B_to_C, time_A_to_B, time_B_to_C, deleted; cin >> A_to_B >> B_to_C >> time_A_to_B >> time_B_to_C >> deleted; vector A(A_to_B + 1); for(int i = 1; i <= A_to_B; i++) { cin >> A[i]; } vector B(B_to_C + 1); for(int i = 1; i <= B_to_C; i++) { cin >> B[i]; } const long long oo = 1e15; long long max_time = (deleted >= A_to_B || deleted >= B_to_C ? oo : 0); A.push_back(oo); B.push_back(oo); for(int a_deletes = 0; a_deletes <= min(deleted, A_to_B - 1); a_deletes++) { long long reached_B = A[a_deletes + 1] + time_A_to_B; int first_b = upper_bound(B.begin(), B.end(), reached_B - 1) - B.begin(); int b_deletes = deleted - a_deletes + first_b - 1; if(b_deletes > B_to_C) { max_time = oo; break; } max_time = max(max_time, B[b_deletes + 1] + time_B_to_C); } cout << (max_time >= oo ? -1 : max_time) << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Programs/Crazy Diamond.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e6 + 5; vector A(MAX_N); vector position(MAX_N); vector > swaps; void arrange_swaps(int start, int destination) { int original_start = A[start], original_destination = A[destination]; swap(A[start], A[destination]); position[original_start] = destination; position[original_destination] = start; swaps.push_back(make_pair(start, destination)); } int main() { int no_of_elements; cin >> no_of_elements; for(int i =1 ; i <= no_of_elements; i++) cin >> A[i]; for(int i = 1; i <= no_of_elements; i++) position[A[i]] = i; for(int i = 1; i <= no_of_elements; i++) { if(i == A[i]) continue; int target = i; int target_position = position[target]; int left = min(target_position, i); int right = max(target_position, i); if(right - left >= no_of_elements/2) { arrange_swaps(i, target_position); continue; } if(left > no_of_elements/2) { arrange_swaps(1, left); arrange_swaps(1, right); arrange_swaps(left, 1); } else if(right <= no_of_elements/2) { arrange_swaps(right, no_of_elements); arrange_swaps(no_of_elements, left); } else { arrange_swaps(left, no_of_elements); arrange_swaps(no_of_elements, 1); arrange_swaps(1, right); arrange_swaps(1, no_of_elements); arrange_swaps(no_of_elements, left); } } cout << swaps.size() << "\n"; for(int i = 0; i < swaps.size(); i++) cout << swaps[i].first << " " << swaps[i].second << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Programs/Dirty Deeds Done Dirt Cheap.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct pairs { int a, b, index; pairs() { a = 0; b = 0; }; pairs(int A, int B, int I) { a = A, b = B, index = I; } }; // (p1 < p2) > (q1 < q2) int sort_increasing_pairs(pairs &P, pairs &Q) { return (P.b > Q.b); } // (p1 > p2) < (q1 > q2) int sort_decreasing_pairs(pairs&P, pairs &Q) { return (P.a < Q.a); } int main() { int no_of_pairs; cin >> no_of_pairs; vector increasing, decreasing; for(int i = 1; i <= no_of_pairs; i++) { int x, y; cin >> x >> y; if(x < y) { increasing.push_back(pairs(x, y, i)); } else { decreasing.push_back(pairs(x, y, i)); } } sort(all(increasing), sort_increasing_pairs); sort(all(decreasing), sort_decreasing_pairs); if(increasing.size() >= decreasing.size()) { cout << increasing.size() << "\n"; for(int i = 0; i < increasing.size(); i++) { cout << increasing[i].index << " "; } } else { cout << decreasing.size() << "\n"; for(int i = 0; i < decreasing.size(); i++) { cout << decreasing[i].index << " "; } } return 0; } ================================================ FILE: Contests/CodeForces Global Round 3/Rough Notes Link ================================================ https://1drv.ms/b/s!AoiWcyvzkQXVhzwro8u-YeTes_kj ================================================ FILE: Contests/CodeForces Global Round 5/Explanations/Balanced Rating Changes Explanation.txt ================================================ First, we will make R[i] = R[i]/2 rounded down for all the N integers. Then, we will check the sum Case 1 = Sum S = 0 Then, there is nothing further to do. Case 2 = Sum S < 0 That means the sum is too low and we need to raise some integers. That means some of the odd integers need to be rounded up. We will increment some of the odd integers by 1 till our sum is 0. Case 3 - Sum S > 0 That means the sum is too high. Some of the odd integers need to be rounded down instead of up. However, this can't happen here. We have already rounded down all the N integers. ----- Another alternative approach is that if there are X odd numbers, we will round up X/2 odd integers and round down X/2 odd integers. ---- int main() { int no_of_students; cin >> no_of_students; vector rating(no_of_students + 1); vector was_odd(no_of_students + 1, false); int sum = 0; for(int i = 1; i <= no_of_students; i++) { cin >> rating[i]; was_odd[i] = (abs(rating[i])%2 == 1); rating[i] /= 2; sum += rating[i]; } if(sum < 0) { for(int i = 1; i <= no_of_students && sum != 0; i++) { if(was_odd[i] && rating[i] > 0) { rating[i]++; sum++; } } } else if(sum > 0) { for(int i = 1; i <= no_of_students && sum != 0; i++) { if(was_odd[i] && rating[i] < 0) { rating[i]--; sum--; } } } for(int i = 1; i <= no_of_students; i++) { cout << rating[i] << "\n"; } return 0; } ================================================ FILE: Contests/CodeForces Global Round 5/Explanations/Balanced Tunnel Explanation.txt ================================================ Let us keep track of the time in which each car enters and exits. We will sort the cars by their entry time. Then, we will go from C1 to CN, C1.Entry < C2.Entry < .... < CN.Entry Car i is fined if it's exit comes before any of the (i - 1) cars This means that Car i's exit muct come before some Exit of one of the first (i - 1) cars. If that is true, then it will definitely come before the MAXIUMUM of the first (i - 1) exits. So we will keep track of the maximum exit time we have seen so far. If Car i.Exit is smaller than the maximum of the Exit time so far, then Car i will be fined. ---- struct cars { int entry, exit; cars(){}; const int operator<(cars &C) { return (entry < C.entry); } }; int main() { int no_of_cars; cin >> no_of_cars; vector car_no(no_of_cars); for(int i = 0; i < no_of_cars; i++) { int car; cin >> car; car_no[car - 1].entry = i; } int cars_fined = 0; for(int i = 0; i < no_of_cars; i++) { int car; cin >> car; car_no[car - 1].exit = i; } sort(all(car_no)); int maximum_exit_so_far = car_no[0].exit; for(int i = 1; i < no_of_cars; i++) { if(car_no[i].exit < maximum_exit_so_far) { cars_fined++; } maximum_exit_so_far = max(maximum_exit_so_far, car_no[i].exit); } cout << cars_fined << "\n"; return 0; } ================================================ FILE: Contests/CodeForces Global Round 5/Programs/Balanced Rating Changes.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_students; cin >> no_of_students; vector rating(no_of_students + 1); vector was_odd(no_of_students + 1, false); int sum = 0; for(int i = 1; i <= no_of_students; i++) { cin >> rating[i]; was_odd[i] = (abs(rating[i])%2 == 1); rating[i] /= 2; sum += rating[i]; } if(sum < 0) { for(int i = 1; i <= no_of_students && sum != 0; i++) { if(was_odd[i] && rating[i] > 0) { rating[i]++; sum++; } } } else if(sum > 0) { for(int i = 1; i <= no_of_students && sum != 0; i++) { if(was_odd[i] && rating[i] < 0) { rating[i]--; sum--; } } } for(int i = 1; i <= no_of_students; i++) { cout << rating[i] << "\n"; } return 0; } ================================================ FILE: Contests/CodeForces Global Round 5/Programs/Balanced Tunnel.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct cars { int entry, exit; cars(){}; const int operator<(cars &C) { return (entry < C.entry); } }; int main() { int no_of_cars; cin >> no_of_cars; vector car_no(no_of_cars); for(int i = 0; i < no_of_cars; i++) { int car; cin >> car; car_no[car - 1].entry = i; } int cars_fined = 0; for(int i = 0; i < no_of_cars; i++) { int car; cin >> car; car_no[car - 1].exit = i; } sort(all(car_no)); int maximum_exit_so_far = car_no[0].exit; for(int i = 1; i < no_of_cars; i++) { if(car_no[i].exit < maximum_exit_so_far) { cars_fined++; } maximum_exit_so_far = max(maximum_exit_so_far, car_no[i].exit); } cout << cars_fined << "\n"; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Explanations/Cows and Snacks Explanation.txt ================================================ 1. Since each cow likes only 2 snacks, we can treat the cows as edges and the snacks as vertices. 2. Let us look at 1 connected component of this graph. 2 snacks can be had by the first edge. After that, each snack can only be eaten by 1 edge. 3. A connected component of size C will have at most (C - 1) happy cows. 4. We will take the sum of all the connected components and then the number of unhappy cows = Total Cows - Happy Cows 5. The reason we cannot simply write the answer as Total Cows - Number of Connected Components, assuming each component produces exactly 1 unhappy cow is that multi-edges are allowed in this graph. Only (C - 1) edges are enough to span the entire connected component but it can have many more edges and the cows correspond to edges. ----- #include #include using namespace std; const int MAX_N = 1e5 + 5; vector graph[MAX_N]; vector visited(MAX_N, false); int dfs_component_size(int v) { if(visited[v]) return 0; int component_size = 1; visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(visited[child]) { continue; } component_size += dfs_component_size(child); } return component_size; } int main() { int no_of_snacks, no_of_animals; cin >> no_of_snacks >> no_of_animals; for(int i = 1; i <= no_of_animals; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } int happy_animals = 0; for(int i = 1; i <= no_of_snacks; i++) { if(!visited[i]) { int component_size = dfs_component_size(i); happy_animals += (component_size - 1); } } int unhappy_animals = no_of_animals - happy_animals; cout << unhappy_animals; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Explanations/Koala and Lights Explanation ================================================ Just do a brute force simulation about a large enough time. (Suppose 1000). Actually the sequences are all periodic. And the maximum period is the lcm of all the individual periods - 2, 4, 6, 8, 10 We can simulate upto a large number and then find the maximum number of simultaneous lights on. --- int main() { int no_of_lights; cin >> no_of_lights; string initial; cin >> initial; vector start(no_of_lights); vector difference(no_of_lights); for(int i = 0; i < no_of_lights; i++) { cin >> difference[i] >> start[i]; } const int MAX_TIME = 1001, ON = 0, OFF = 1; vector lights_on_at(MAX_TIME, 0); for(int i = 0; i < no_of_lights; i++) { int state = (initial[i] == '0' ? OFF : ON); if(initial[i] == '1') { for(int time = 0; time < start[i]; time++) { lights_on_at[time]++; } } for(int time = start[i]; time < MAX_TIME; time++) { if((time - start[i])%difference[i] == 0) { state = (state == ON ? OFF : ON); } if(state == ON) { lights_on_at[time]++; } } } int max_lights = 0; for(int t = 0; t < MAX_TIME; t++) { max_lights = max(max_lights, lights_on_at[t]); } cout << max_lights; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Explanations/Paint The Digits Explanation ================================================ Here is what this question asks us. You are given a string S. Split it into two sequences S1 and S2. S1 and S2 are both sorted in non-decreasing order. The string (S1 S2) must also be sorted in non-decreasing oder. Now one observation to make is that the number of possible characters is small (10) even though the length is large. Let us iterate over all 10 digits. We will put all digits < d in S1 and > d in S2. The reason we are not touching the digits = d is that they can be put into either of the strings based on convenience. 1. Iterate over 10 digits. 2. For the current digit d, put all characters < d in S1 and > d in S2. 3. Check if S1 and S2 are non-decreasing Here is what this question asks us. You are given a string S. Split it into two sequences S1 and S2. S1 and S2 are both sorted in non-decreasing order. The string (S1 S2) must also be sorted in non-decreasing oder. Now one observation to make is that the number of possible characters is small (10) even though the length is large. Let us iterate over all 10 digits. We will put all digits < d in S1 and > d in S2. The reason we are not touching the digits = d is that they can be put into either of the strings based on convenience. 1. Iterate over 10 digits. 2. For the current digit d, put all characters < d in S1 and > d in S2. 3. Check if S1 and S2 are non-decreasing --- int possible_to_split(string S, int n) { string new_string_lesser_than_n, new_string_greater_than_n; for(int i = 0; i < S.size(); i++) { if(S[i] - '0' < n) { new_string_lesser_than_n += S[i]; } else if(S[i] - '0' > n) { new_string_greater_than_n += S[i]; } } return (is_non_decreasing(new_string_greater_than_n) && is_non_decreasing(new_string_lesser_than_n)); } ----- We can use a very simple function to check if a string S in non-decreasing. int is_non_decreasing(string S) { for(int i = 0; i + 1 < S.size(); i++) { if(S[i] > S[i + 1]) return false; } return true; } --- Let us now suppose that there exists some digit d such that we can make 2 non-decreasing strings S1 and S2 such that all characters in S1 < d and all characters in S2 > d. Is this sufficient ? No. We need to accomodate the digit d too. --- Let x be the leftmost occurrence of any digit > d. int second_sequence_beginning = length - 1; for(int i = length - 1; i >= 0; i--) { if(S[i] - '0' > possible_endings_1) { second_sequence_beginning = i; } } --- Let y be the rightmost occurence of any digit < d int first_sequence_ending = 0; for(int i = 0; i < length; i++) { if(S[i] - '0' < possible_endings_1) { first_sequence_ending = i; } } ---- 1. Any occurence of d that is before x can be put in the beginning of S2 2. Any occurence of d that is after y can be put at the end of S1 3.Occurences of d that are in between x and y cannot be put in either S1 or S2 If this is the case, then we will continue searching for another digit for which we can construct this ---- int colouring_possible = true; for(int i = second_sequence_beginning; i < first_sequence_ending; i++) { if(S[i] - '0' == possible_endings_1) { colouring_possible = false; } } if(!colouring_possible) continue; --------- If the colouring is possible, we will construct it according to the rules above string colouring; for(int i = 0; i < length; i++) { if( (S[i] - '0' < possible_endings_1) || (S[i] - '0' == possible_endings_1 && i >= first_sequence_ending) ) { colouring += '1'; } else if( (S[i] - '0' > possible_endings_1) || (S[i] - '0' == possible_endings_1 && i <= second_sequence_beginning)) { colouring += '2'; } } ----------- --- ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Explanations/Paint Your Numbers Explanation ================================================ The smallest number has to be painted with some colour. We will paint all the multiples of this smallest number with the same colour. This suggests a sieve-like approach. 1. Sort the elements 2. If we find an uncoloured element, paint that element with a new colour 2a. Iterate over all multiples of this element and paint it with the same colour 3. Continue scanning and look for the next uncoloured element --------- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; sort(all(A)); const int MAX = 101; int last_colour = 0; vector colour(MAX, 0); for(int i = 1; i <= no_of_elements; i++) { if(colour[A[i]] == 0) { last_colour++; for(int j = A[i]; j < MAX; j += A[i]) { colour[j] = last_colour; } } } cout << last_colour; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Programs/Cows and Snacks.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e5 + 5; vector graph[MAX_N]; vector visited(MAX_N, false); int dfs_component_size(int v) { if(visited[v]) return 0; int component_size = 1; visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(visited[child]) { continue; } component_size += dfs_component_size(child); } return component_size; } int main() { int no_of_snacks, no_of_animals; cin >> no_of_snacks >> no_of_animals; for(int i = 1; i <= no_of_animals; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } int happy_animals = 0; for(int i = 1; i <= no_of_snacks; i++) { if(!visited[i]) { int component_size = dfs_component_size(i); happy_animals += (component_size - 1); } } int unhappy_animals = no_of_animals - happy_animals; cout << unhappy_animals; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Programs/Koala and Lights.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_lights; cin >> no_of_lights; string initial; cin >> initial; vector start(no_of_lights); vector difference(no_of_lights); for(int i = 0; i < no_of_lights; i++) { cin >> difference[i] >> start[i]; } const int MAX_TIME = 1001, ON = 0, OFF = 1; vector lights_on_at(MAX_TIME, 0); for(int i = 0; i < no_of_lights; i++) { int state = (initial[i] == '0' ? OFF : ON); if(initial[i] == '1') { for(int time = 0; time < start[i]; time++) { lights_on_at[time]++; } } for(int time = start[i]; time < MAX_TIME; time++) { if((time - start[i])%difference[i] == 0) { state = (state == ON ? OFF : ON); } if(state == ON) { lights_on_at[time]++; } } } int max_lights = 0; for(int t = 0; t < MAX_TIME; t++) { max_lights = max(max_lights, lights_on_at[t]); } cout << max_lights; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Programs/Paint The Digits.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int is_non_decreasing(string S) { for(int i = 0; i + 1 < S.size(); i++) { if(S[i] > S[i + 1]) return false; } return true; } int possible_to_split(string S, int n) { string new_string_lesser_than_n, new_string_greater_than_n; for(int i = 0; i < S.size(); i++) { if(S[i] - '0' < n) { new_string_lesser_than_n += S[i]; } else if(S[i] - '0' > n) { new_string_greater_than_n += S[i]; } } return (is_non_decreasing(new_string_greater_than_n) && is_non_decreasing(new_string_lesser_than_n)); } void solve() { int length; string S; cin >> length >> S; int possible_endings_1 = 0; for(possible_endings_1 = 0; possible_endings_1 < 10; possible_endings_1++) { if(!possible_to_split(S, possible_endings_1)) { continue; } int first_sequence_ending = 0; for(int i = 0; i < length; i++) { if(S[i] - '0' < possible_endings_1) { first_sequence_ending = i; } } int second_sequence_beginning = length - 1; for(int i = length - 1; i >= 0; i--) { if(S[i] - '0' > possible_endings_1) { second_sequence_beginning = i; } } int colouring_possible = true; for(int i = second_sequence_beginning; i < first_sequence_ending; i++) { if(S[i] - '0' == possible_endings_1) { colouring_possible = false; } } if(!colouring_possible) continue; string colouring; for(int i = 0; i < length; i++) { if( (S[i] - '0' < possible_endings_1) || (S[i] - '0' == possible_endings_1 && i >= first_sequence_ending) ) { colouring += '1'; } else if( (S[i] - '0' > possible_endings_1) || (S[i] - '0' == possible_endings_1 && i <= second_sequence_beginning)) { colouring += '2'; } } cout << colouring << "\n"; return; } if(possible_endings_1 == 10) { cout << "-\n"; return; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Programs/Paint The Numbers.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; sort(all(A)); const int MAX = 101; int last_colour = 0; vector colour(MAX, 0); for(int i = 1; i <= no_of_elements; i++) { if(colour[A[i]] == 0) { last_colour++; for(int j = A[i]; j < MAX; j += A[i]) { colour[j] = last_colour; } } } cout << last_colour; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Programs/Paint Your Numbers.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; sort(all(A)); const int MAX = 101; int last_colour = 0; vector colour(MAX, 0); for(int i = 1; i <= no_of_elements; i++) { if(colour[A[i]] == 0) { last_colour++; for(int j = A[i]; j < MAX; j += A[i]) { colour[j] = last_colour; } } } cout << last_colour; return 0; } ================================================ FILE: Contests/Dasha Code Championship Elimination Round 2019/Rough Notes ================================================ https://1drv.ms/b/s!AoiWcyvzkQXViGvYtE4yyrEofu3T?e=4Nqcdt ================================================ FILE: Contests/Div 1 492/Explanations/Game 995 Explanation.txt ================================================ Blog Link - http://qr.ae/TUpe5F Expectation is just the average ! ------------------------------------- int main() { int n, no_of_changes; scanf("%d %d", &n, &no_of_changes); int no_of_elements = (1LL << n); long long sum = 0; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { scanf("%d", &A[i]); sum += A[i]; } double average = (sum*1.0)/no_of_elements; printf("%.12f\n", average); for(int i = 1; i <= no_of_changes; i++) { int position, new_value; scanf("%d %d", &position, &new_value); sum = sum - A[position] + new_value; A[position] = new_value; average = (sum*1.0)/(no_of_elements); printf("%.12f\n", average); } return 0; } ================================================ FILE: Contests/Div 1 492/Explanations/Leaving the Bar Explanation.txt ================================================ Blog link - https://mathprogrammer.quora.com/4253883-1?share=4cf393bf&srid=F7Hz Turns out randomly shuffling the vectors and being greedy is a very efficient heuristic ! ------------------------------ do { random_shuffle(all(V)); P = Point(0, 0); for(int i = 0; i < no_of_points; i++) { if(square_norm(P + V[i]) <= square_norm(P - V[i])) { P = P + V[i]; step[V[i].index] = 1; } else { P = P - V[i]; step[V[i].index] = -1; } } } while(square_norm(P) > square(oo)); ================================================ FILE: Contests/Div 1 492/Explanations/Suit and Tie Explanation.txt ================================================ We can be greedy. Go through the array. If A[i] =/= A[i + 1], Find the rightmost occurence of A[i] and keep swapping. Let us prove that this is optimal. now, if a and a are seperated All other pairs, must be of the form aa bb abab a bb a Now in the first kind, our algorithm won't touch it. In the seonc kind, we need to atleast do one swap. The greedy algorithm does one swap. In the thrid, we need to do at least two, The greedy does two. We see the greedy algorithm does no more swaps than necessary. ------------------------------------- int main() { int no_of_couples; scanf("%d", &no_of_couples); vector A(2*no_of_couples + 1); for(int i = 1; i <= 2*no_of_couples; i++) scanf("%d", &A[i]); int no_of_swaps = 0; for(int i = 1; i <= 2*no_of_couples; i += 2) { for(int j = 2*no_of_couples; j > i + 1; j--) { if(A[j] == A[i]) { swap(A[j], A[j - 1]); no_of_swaps++; } } } printf("%d\n", no_of_swaps); return 0; } ================================================ FILE: Contests/Div 1 492/Programs/Game 995D.cpp ================================================ #include #include using namespace std; int main() { int n, no_of_changes; scanf("%d %d", &n, &no_of_changes); int no_of_elements = (1LL << n); long long sum = 0; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { scanf("%d", &A[i]); sum += A[i]; } double average = (sum*1.0)/no_of_elements; printf("%.12f\n", average); for(int i = 1; i <= no_of_changes; i++) { int position, new_value; scanf("%d %d", &position, &new_value); sum = sum - A[position] + new_value; A[position] = new_value; average = (sum*1.0)/(no_of_elements); printf("%.12f\n", average); } return 0; } ================================================ FILE: Contests/Div 1 492/Programs/Leaving The Bar.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; struct Point { int index; LL x, y; Point(LL a = 0, LL b = 0, int index = 0) { x = a, y = b, index = 0; } Point operator+(const Point &P) { return Point(x + P.x, y + P.y); } Point operator-(const Point &P) { return Point(x - P.x, y - P.y); } }; LL square(LL n) { return n*n; } LL square_norm(Point P) { return (P.x*P.x + P.y*P.y); } int main() { int no_of_points; scanf("%d", &no_of_points); vector V(no_of_points); for(int i = 0; i < no_of_points; i++) { scanf("%I64d %I64d", &V[i].x, &V[i].y); V[i].index = i; } const LL oo = 1.5e6; Point P; vector step(no_of_points); do { random_shuffle(all(V)); P = Point(0, 0); for(int i = 0; i < no_of_points; i++) { if(square_norm(P + V[i]) <= square_norm(P - V[i])) { P = P + V[i]; step[V[i].index] = 1; } else { P = P - V[i]; step[V[i].index] = -1; } } } while(square_norm(P) > square(oo)); for(int i = 0; i < no_of_points; i++) printf("%d ", step[i]); return 0; } ================================================ FILE: Contests/Div 1 492/Programs/Suit and Tie.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_couples; scanf("%d", &no_of_couples); vector A(2*no_of_couples + 1); for(int i = 1; i <= 2*no_of_couples; i++) scanf("%d", &A[i]); int no_of_swaps = 0; for(int i = 1; i <= 2*no_of_couples; i += 2) { for(int j = 2*no_of_couples; j > i + 1; j--) { if(A[j] == A[i]) { swap(A[j], A[j - 1]); no_of_swaps++; } } } printf("%d\n", no_of_swaps); return 0; } ================================================ FILE: Contests/Div 2 12/Explanations/Ball Explanation.txt ================================================ Blog Link - http://qr.ae/TUpFlU You have N triplets (A, B, C). Sort the triplets by A. Maintain an array S, where the index is B and the value is C. Initially C is empty. Process triplets in descending order of A. Check if max{S[B[i] + 1, B[i] + 2, ... , N]} > C_i, If yes, then we have found a triplet j such that A_j > A_i, because it was processed first. B_j > B_i, because we have queried in the range > B_i C_j > C_i, as we have just found out ! We compress the coordinates of B and maintain a segment tree over S. Otherwise, it once again degrades to O(n^2). But, with our beautiful segment tree, it's now O(n log n). ------------------------------------------------ int main() { int no_of_ladies; scanf("%d", &no_of_ladies); vector lady(no_of_ladies + 1); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].beauty); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].richness); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].intellect); sort(all(lady), sort_by_beauty); vector intelligence(no_of_ladies + 1, 0); for(int i = 1; i <= no_of_ladies; i++) intelligence[i] = lady[i].intellect; sort(all(intelligence)); map iq_rank; for(int i = 1; i <= no_of_ladies; i++) { iq_rank[intelligence[i]] = (intelligence[i] == intelligence[i - 1] ? iq_rank[intelligence[i - 1]] : i); } memset(max_tree, 0, sizeof(max_tree)); int suicides = 0; for(int i = no_of_ladies; i >= 1; ) { int j; for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { int max_richness_with_other_2_greater = get_max_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect] + 1, no_of_ladies); if(max_richness_with_other_2_greater > lady[j].richness) suicides++; } for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { insert_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect], lady[j].richness); } i = j; } printf("%d", suicides); return 0; } ================================================ FILE: Contests/Div 2 12/Explanations/Correct Solution Explanation.txt ================================================ If you are given N, the answer is all the digits of N in ascending order. If N[0] = 0, then swap it with the first non zero number. (There's always a non zero digit, if the number of digits > 1 as there is no number consisting of multiple zeroes. However, a single 0 is a special case. Be careful. If it's only 0, then there's no non zero digit to replace it with.) Compare the answer with B. -------------------------------------------------------------- string solve(string S) { vector digits; for(int i = 0; i < S.size(); i++) digits.push_back(S[i]); sort(all(digits)); if(digits[0] == '0') { int first_nonzero = 1; while(first_nonzero < digits.size() && digits[first_nonzero] == '0') first_nonzero++; swap(digits[0], digits[first_nonzero]); } string answer; for(int i = 0; i < digits.size(); i++) answer += digits[i]; return answer; } int main() { string A, B; cin >> A >> B; string answer = solve(A); cout << ((answer == B) ? "OK\n" : "WRONG_ANSWER\n"); return 0; } ================================================ FILE: Contests/Div 2 12/Explanations/Fruits Explanation.txt ================================================ Keep track of the frequency of each fruit. To minimise prices, the most frequent fruits, get the lowest prices. To maximise prices, the most frequent fruits get the highest prices. ------------------------------ sort(all(fruit_frequency)); reverse(all(fruit_frequency)); long long min_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) min_price += price[i]*1LL*fruit_frequency[i]; reverse(all(price)); long long max_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) max_price += price[i]*1LL*fruit_frequency[i]; ================================================ FILE: Contests/Div 2 12/Explanations/Super Agent Explanation.txt ================================================ There are only 9 points and 4 pairs. Check all of them. int main() { const int N = 3; char grid[N + 2][N + 2]; for(int i = 1; i <= N; i++) scanf("%s", grid[i] + 1); int symmetric = (grid[1][1] == grid[3][3]) && (grid[1][2] == grid[3][2]) && (grid[1][3] == grid[3][1]) && (grid[2][3] == grid[2][1]); printf(symmetric ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 12/Programs/Ball.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin() + 1, (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; const int MAX_N = 5e5 + 15; int max_tree[3*MAX_N]; struct info { int beauty, richness, intellect; }; int sort_by_beauty(info &A, info &B) { return (A.beauty < B.beauty); } void insert_richness(int n, int left, int right, int index, int value) { if(index < left || right < index) return; if(left == right) { max_tree[n] = max(max_tree[n], value); return ; } int mid = (left + right) >> 1; insert_richness(LEFT(n), left, mid, index, value); insert_richness(RIGHT(n), mid + 1, right, index, value); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } int get_max_richness(int n, int left, int right, int query_left, int query_right) { if(right < query_left || query_right < left || right < left) return 0; if(query_left <= left && right <= query_right) return max_tree[n]; int mid = (left + right) >> 1; int left_max = get_max_richness(LEFT(n), left, mid, query_left, query_right); int right_max = get_max_richness(RIGHT(n), mid + 1, right, query_left, query_right); return max(left_max, right_max); } int main() { int no_of_ladies; scanf("%d", &no_of_ladies); vector lady(no_of_ladies + 1); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].beauty); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].richness); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].intellect); sort(all(lady), sort_by_beauty); vector intelligence(no_of_ladies + 1, 0); for(int i = 1; i <= no_of_ladies; i++) intelligence[i] = lady[i].intellect; sort(all(intelligence)); map iq_rank; for(int i = 1; i <= no_of_ladies; i++) { iq_rank[intelligence[i]] = (intelligence[i] == intelligence[i - 1] ? iq_rank[intelligence[i - 1]] : i); } memset(max_tree, 0, sizeof(max_tree)); int suicides = 0; for(int i = no_of_ladies; i >= 1; ) { int j; for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { int max_richness_with_other_2_greater = get_max_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect] + 1, no_of_ladies); if(max_richness_with_other_2_greater > lady[j].richness) suicides++; } for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { insert_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect], lady[j].richness); } i = j; } printf("%d", suicides); return 0; } ================================================ FILE: Contests/Div 2 12/Programs/Correct Solution.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; string solve(string S) { vector digits; for(int i = 0; i < S.size(); i++) digits.push_back(S[i]); sort(all(digits)); if(digits[0] == '0' && digits.size() > 1) { int first_nonzero = 1; while(digits[first_nonzero] == '0') first_nonzero++; swap(digits[0], digits[first_nonzero]); } string answer; for(int i = 0; i < digits.size(); i++) answer += digits[i]; return answer; } int main() { string A, B; cin >> A >> B; string answer = solve(A); cout << ((answer == B) ? "OK\n" : "WRONG_ANSWER\n"); return 0; } ================================================ FILE: Contests/Div 2 12/Programs/Fruits.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_prices, no_of_fruits; cin >> no_of_prices >> no_of_fruits; vector price(no_of_prices, 0); for(int i = 0; i < no_of_prices; i++) cin >> price[i]; sort(all(price)); map frequency; for(int i = 1; i <= no_of_fruits; i++) { string fruit; cin >> fruit; frequency[fruit]++; } vector fruit_frequency; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) fruit_frequency.push_back(it->second); sort(all(fruit_frequency)); reverse(all(fruit_frequency)); long long min_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) min_price += price[i]*1LL*fruit_frequency[i]; reverse(all(price)); long long max_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) max_price += price[i]*1LL*fruit_frequency[i]; cout << min_price << " " << max_price; return 0; } ================================================ FILE: Contests/Div 2 12/Programs/Super Agent.cpp ================================================ #include int main() { const int N = 3; char grid[N + 2][N + 2]; for(int i = 1; i <= N; i++) scanf("%s", grid[i] + 1); int symmetric = (grid[1][1] == grid[3][3]) && (grid[1][2] == grid[3][2]) && (grid[1][3] == grid[3][1]) && (grid[2][3] == grid[2][1]); printf(symmetric ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 136/Explanations/Little Elephant And Array Segment Tree Explanation.txt ================================================ Blog Link - http://qr.ae/TUpmul Very similar to DQUERY. The idea is that we set the index of the last x-th occurence of x to 1, the one before that to -1 and all others to 0 and do offline processing ! It's quite beautiful actually ! This ensures that when we're processing queries that end at i, we have all the required information. We can't answer the queries online as it's not convenient and it gets messy but solving them offline makes the problem so beautiful ! --------------------------------------------------- for(int i = 1; i <= no_of_elements; i++) { if(A[i] < MAX_N) { occurence[A[i]].push_back(i); int A_i_frequency = occurence[A[i]].size(); if(A_i_frequency >= A[i]) { int last = A_i_frequency - A[i]; int last_occurence = occurence[A[i]][last]; update(1, 1, no_of_elements, last_occurence, 1); } if(A_i_frequency >= A[i] + 1) { int second_last = A_i_frequency - (A[i] + 1); int second_last_occurence = occurence[A[i]][second_last]; update(1, 1, no_of_elements, second_last_occurence, -1); } if(A_i_frequency >= A[i] + 2) { int third_last = A_i_frequency - (A[i] + 2); int third_last_occurence = occurence[A[i]][third_last]; update(1, 1, no_of_elements, third_last_occurence, 0); } } while(Q[last_query].right == i) { answer[Q[last_query].index] = get_sum(1, 1, no_of_elements, Q[last_query].left, Q[last_query].right); last_query++; } } ================================================ FILE: Contests/Div 2 136/Explanations/Little Elephant and Arrays Explanation.txt ================================================ Blog Link - http://qr.ae/TUpmul Main insight is there can be at most 2 root(n) numbers x who's frequency in the array is > x -------------------------- vector answer(no_of_queries + 1, 0); for(int i = 1; i <= MAX_N; i++) { if(frequency[i] >= i) //There can't be more than 2 root(n) such elements { vector frequency_till(no_of_elements + 1, 0); for(int j = 1; j <= no_of_elements; j++) frequency_till[j] = frequency_till[j - 1] + (A[j] == i); for(int q = 1; q <= no_of_queries; q++) answer[q] += (frequency_till[right[q]] - frequency_till[left[q] - 1] == i); } } ================================================ FILE: Contests/Div 2 136/Explanations/Little Elephant and Function Explanation.txt ================================================ The Little Elephant enjoys recursive functions. This time he enjoys the sorting function. Let a is a permutation of an integers from 1 to n, inclusive, and ai denotes the i-th element of the permutation. The Little Elephant's recursive function f(x), that sorts the first x permutation's elements, works as follows: If x?=?1, exit the function. Otherwise, call f(x?-?1), and then make swap(ax?-?1,?ax) (swap the x-th and (x?-?1)-th elements of a). The Little Elephant's teacher believes that this function does not work correctly. But that-be do not get an F, the Little Elephant wants to show the performance of its function. Help him, find a permutation of numbers from 1 to n, such that after performing the Little Elephant's function (that is call f(n)), the permutation will be sorted in ascending order. ------------------------------------------------------- Important to have some understanding of recursive stackframes for this one. At first I thought it first swaps, ax and a(x-1) and then calls f(x - 1). In that case the answer is a sorted array, rotated one place to the left. Like, 2 3 4 1 Because every swap will - 2 3 1 4, 2 1 3 4 and finally 1 2 3 4 ... The order of elements doesn't change ... The smallest element goes to the first position. But, this is wrong. What happens is that it first calls f(x-1), f(x-2) ... and so on till it reaches f(1) and then starts swapping. So, in other words starting from position 2 till n, ai and a(i - 1) are swapped. In this case, the answer is a sorted array rotated one place to the RIGHT. the order of elements doesn't change this way ... The first element occupies the last position. 4 1 2 3, 1 4 2 3, 1 2 4 3 and finally 1 2 3 4. ----------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); printf("%d ", no_of_elements); for(int i = 1; i < no_of_elements; i++) printf("%d ", i); return 0; } ================================================ FILE: Contests/Div 2 136/Explanations/Little Elephant and Numbers Explanation.txt ================================================ Just implement it. O(root(n)) time -------------------------------------- int main() { int n; scanf("%d", &n); int answer = 0; for(int i = 1; i*i <= n; i++) { if(n%i == 0) { answer += common_digit(i, n); answer += (i*i != n && common_digit(n/i, n)); } } printf("%d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 136/Explanations/Little Elephant and Problem Explanation.txt ================================================ The Little Elephant has got a problem somebody has been touching his sorted by non-decreasing array a of length n and possibly swapped some elements of the array. The Little Elephant doesn't want to call the police until he understands if he could have accidentally changed the array himself. He thinks that he could have accidentally changed array a, only if array a can be sorted in no more than one operation of swapping elements (not necessarily adjacent). That is, the Little Elephant could have accidentally swapped some two elements. Help the Little Elephant, determine if he could have accidentally changed the array a, sorted by non-decreasing, himself. ------------------------------------------------------- Sort the array and check how many positions differ with the original array. int main() { int no_of_elements; scanf("%d", &no_of_elements); vector original_array(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original_array[i]); vector sorted_array = original_array; sort(all(sorted_array)); int differences = 0; for(int i = 0; i < no_of_elements; i++) differences += (sorted_array[i] != original_array[i]); printf(differences <= 2 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 136/Programs/Little Elephant And Array Segment Tree Solution.cpp ================================================ #include #include #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) #define all(v) (v).begin() + 1, (v).end() using namespace std; struct info { int left, right, index; int operator <(const info &A) { return (right < A.right); } }; const int MAX_N = 1e5 + 1; int sum_tree[3*MAX_N]; vector occurence[MAX_N]; void update(int n, int left, int right, int position, int value) { if(right < position || position < left) return; if(left == right) { sum_tree[n] = value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; int left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); int right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector Q(no_of_queries + 1); for(int i = 1; i <= no_of_queries; i++) { scanf("%d %d", &Q[i].left, &Q[i].right); Q[i].index = i; } sort(all(Q)); memset(sum_tree, 0, sizeof(sum_tree)); int last_query = 1; vector answer(no_of_queries + 1); for(int i = 1; i <= no_of_elements; i++) { if(A[i] < MAX_N) { occurence[A[i]].push_back(i); int A_i_frequency = occurence[A[i]].size(); if(A_i_frequency >= A[i]) { int last = A_i_frequency - A[i]; int last_occurence = occurence[A[i]][last]; update(1, 1, no_of_elements, last_occurence, 1); } if(A_i_frequency >= A[i] + 1) { int second_last = A_i_frequency - (A[i] + 1); int second_last_occurence = occurence[A[i]][second_last]; update(1, 1, no_of_elements, second_last_occurence, -1); } if(A_i_frequency >= A[i] + 2) { int third_last = A_i_frequency - (A[i] + 2); int third_last_occurence = occurence[A[i]][third_last]; update(1, 1, no_of_elements, third_last_occurence, 0); } } while(Q[last_query].right == i) { answer[Q[last_query].index] = get_sum(1, 1, no_of_elements, Q[last_query].left, Q[last_query].right); last_query++; } } for(int i = 1; i <= no_of_queries; i++) printf("%d\n", answer[i]); return 0; } ================================================ FILE: Contests/Div 2 136/Programs/Little Elephant and Array.cpp ================================================ #include #include using namespace std; int main() { const int MAX_N = 1e5 + 1; int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector A(no_of_elements + 1); vector frequency(MAX_N + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); if(A[i] < MAX_N) frequency[A[i]]++; } vector left(no_of_queries + 1); vector right(no_of_queries + 1); for(int i = 1; i <= no_of_queries; i++) scanf("%d %d", &left[i], &right[i]); vector answer(no_of_queries + 1, 0); for(int i = 1; i <= MAX_N; i++) { if(frequency[i] >= i) //There can't be more than 2 root(n) such elements { vector frequency_till(no_of_elements + 1, 0); for(int j = 1; j <= no_of_elements; j++) frequency_till[j] = frequency_till[j - 1] + (A[j] == i); for(int q = 1; q <= no_of_queries; q++) answer[q] += (frequency_till[right[q]] - frequency_till[left[q] - 1] == i); } } for(int i = 1; i <= no_of_queries; i++) printf("%d\n", answer[i]); return 0; } ================================================ FILE: Contests/Div 2 136/Programs/Little Elephant and Function.cpp ================================================ #include int main() { int no_of_elements; scanf("%d", &no_of_elements); printf("%d ", no_of_elements); for(int i = 1; i < no_of_elements; i++) printf("%d ", i); return 0; } ================================================ FILE: Contests/Div 2 136/Programs/Little Elephant and Numbers.cpp ================================================ #include #include using namespace std; void get(int n, vector &frequency) { while(n) { frequency[n%10]++; n /= 10; } } int common_digit(int a, int b) { vector a_frequency(10, 0); get(a, a_frequency); vector b_frequency(10, 0); get(b, b_frequency); for(int i = 0; i < 10; i++) if(a_frequency[i] > 0 && b_frequency[i] > 0) return true; return false; } int main() { int n; scanf("%d", &n); int answer = 0; for(int i = 1; i*i <= n; i++) { if(n%i == 0) { answer += common_digit(i, n); answer += (i*i != n && common_digit(n/i, n)); } } printf("%d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 136/Programs/Little Elephant and Problem.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector original_array(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original_array[i]); vector sorted_array = original_array; sort(all(sorted_array)); int differences = 0; for(int i = 0; i < no_of_elements; i++) differences += (sorted_array[i] != original_array[i]); printf(differences <= 2 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 197/Explanations/Helpful Maths Explanation.txt ================================================ Xenia the beginner mathematician is a third year student at elementary school. She is now learning the addition operation. The teacher has written down the sum of multiple numbers. Pupils should calculate the sum. To make the calculation easier, the sum only contains numbers 1, 2 and 3. Still, that isn't enough for Xenia. She is only beginning to count, so she can calculate a sum only if the summands follow in non-decreasing order. For example, she can't calculate sum 1+3+2+1 but she can calculate sums 1+1+2 and 3+3. You've got the sum that was written on the board. Rearrange the summans and print the sum in such a way that Xenia can calculate the sum. ----------------------------------------------- Sort the digits and print them one by one seperated by '+' signs. ------------------------------------------ int main() { string expression; cin >> expression; typedef unsigned int u_int; vector number; for(u_int i = 0; i < expression.size(); i++) { if(expression[i] != '+') number.push_back(expression[i]); } sort(all(number)); for(u_int i = 0; i < number.size() - 1; i++) { printf("%c+", number[i]); } printf("%c\n", number.back()); return 0; } ================================================ FILE: Contests/Div 2 197/Explanations/Xenia and Ringroad Explanation.txt ================================================ Simple implementation int get_travel_time(int previous, int current, int no_of_houses) { return (previous <= current ? current - previous : no_of_houses - previous + current); } int main() { int no_of_houses, no_of_tasks; scanf("%d %d", &no_of_houses, &no_of_tasks); int previous_house = 1; long long total_time = 0; while(no_of_tasks--) { int current_house; scanf("%d", ¤t_house); total_time += get_travel_time(previous_house, current_house, no_of_houses); previous_house = current_house; } printf("%I64d\n", total_time); return 0; } ================================================ FILE: Contests/Div 2 197/Explanations/Xenia and Weights Explanation.txt ================================================ Let us solve this recursively. To know if it is possible to do so in x weighings, all we need to do is keep track of the current move and check if it's possible to do so in x-1 weighings. ----------------------- Let f(n, last, difference) denote whether or not it is possible to complete the process with n weighings with the difference between left and right pans = difference. ------------------- For our next move, we make all legal moves and update the difference accordingly. int possible(int difference, int current_weigh_no, int no_of_weighs) { if(current_weigh_no > no_of_weighs) { return true; } int previous_weight = answer[current_weigh_no - 1]; for(int next_weight = difference + 1; next_weight <= MAX_WEIGHT; next_weight++) { if(available[next_weight] && next_weight != previous_weight) { answer[current_weigh_no] = next_weight; if(possible(next_weight - difference, current_weigh_no + 1, no_of_weighs)) { return true; } } } return false; } ----------------------------- ================================================ FILE: Contests/Div 2 197/Programs/Helpful Maths.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { string expression; cin >> expression; typedef unsigned int u_int; vector number; for(u_int i = 0; i < expression.size(); i++) { if(expression[i] != '+') number.push_back(expression[i]); } sort(all(number)); for(u_int i = 0; i < number.size() - 1; i++) { printf("%c+", number[i]); } printf("%c\n", number.back()); return 0; } ================================================ FILE: Contests/Div 2 197/Programs/Xenia and Bit Operations.cpp ================================================ #include const int OR = 0, XOR = 1, MAX_SIZE = 1e6; int tree[3*MAX_SIZE]; int element[MAX_SIZE]; int perform(int a, int operation, int b) { switch(operation) { case OR : return (a|b); case XOR : return (a^b); } } int other(int operation) { return (operation^1); } void build(int node, int start, int end, int operation) { if(start == end) { tree[node] = element[start]; return; } int mid = (start + end)/2; build(2*node, start, mid, other(operation)); build(2*node + 1, mid + 1, end, other(operation)); tree[node] = perform(tree[2*node], operation, tree[2*node + 1]); } void update(int node, int start, int end, int index, int value, int operation) { if(start == end) { tree[node] = element[index] = value; return; } int mid = (start + end)/2; if(index >= start && index <= mid) { update(2*node, start, mid, index, value, other(operation)); } else if(index > mid && index <= end) { update(2*node + 1, mid + 1, end, index, value, other(operation)); } tree[node] = perform(tree[2*node], operation, tree[2*node + 1]); } int main() { int n, no_of_queries; scanf("%d %d", &n, &no_of_queries); int no_of_elements = (1 << n); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); int first_operation = (n%2 == 0 ? XOR : OR); build(1, 1, no_of_elements, first_operation); while(no_of_queries--) { int index, value; scanf("%d %d", &index, &value); update(1, 1, no_of_elements, index, value, first_operation); printf("%d\n", tree[1]); } return 0; } ================================================ FILE: Contests/Div 2 197/Programs/Xenia and Ringroad.cpp ================================================ #include int get_travel_time(int previous, int current, int no_of_houses) { return (previous <= current ? current - previous : no_of_houses - previous + current); } int main() { int no_of_houses, no_of_tasks; scanf("%d %d", &no_of_houses, &no_of_tasks); int previous_house = 1; long long total_time = 0; while(no_of_tasks--) { int current_house; scanf("%d", ¤t_house); total_time += get_travel_time(previous_house, current_house, no_of_houses); previous_house = current_house; } printf("%I64d\n", total_time); return 0; } ================================================ FILE: Contests/Div 2 197/Programs/Xenia and Weights.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e5 + 5, MAX_WEIGHT = 10; int answer[MAX_N]; int available[MAX_WEIGHT + 1]; int possible(int difference, int current_weigh_no, int no_of_weighs) { if(current_weigh_no > no_of_weighs) { return true; } int previous_weight = answer[current_weigh_no - 1]; for(int next_weight = difference + 1; next_weight <= MAX_WEIGHT; next_weight++) { if(available[next_weight] && next_weight != previous_weight) { answer[current_weigh_no] = next_weight; if(possible(next_weight - difference, current_weigh_no + 1, no_of_weighs)) { return true; } } } return false; } int main() { int no_of_weighs; string weights; cin >> weights >> no_of_weighs; for(int i = 1; i <= MAX_WEIGHT; i++) available[i] = (weights[i - 1] == '1'); if(possible(0, 1, no_of_weighs)) { cout << "YES\n"; for(int i = 1; i <= no_of_weighs; i++) { cout << answer[i] << " "; } } else { cout << "NO\n"; } return 0; } ================================================ FILE: Contests/Div 2 205/Explanation/Little Elephant and Cards Explanation.txt ================================================ Keep track of the front frequency and back frequency of each colour. Now if colour c was made the majority colour, Then, front(c) + back(c) >= half How many flips do we make ? We greedily make as many flips from the back part as required This = max(0, half - front(c)) If front(c) >= half, then we don't make a flip. The tricky case is when a card has the same colour on both sides. If c is on the front and back of a card, then only update the front(c)++, don't do anything with back. This is because we will never flip this card. (Flipping will not give us a different colour, so there is no point in flipping.) I missed this tricky case of what happens when front and back are the same. ------------------------------------- int main() { int no_of_cards; scanf("%d", &no_of_cards); map present; map front_frequency; map back_frequency; for(int i = 1; i <= no_of_cards; i++) { int front, back; scanf("%d %d", &front, &back); front_frequency[front]++; if(front != back) //If front and back have the same colour, count only for front. back_frequency[back]++; present[front] = true; present[back] = true; } int half = no_of_cards/2 + no_of_cards%2; int minimum_moves = no_of_cards + 1; for(map :: iterator it = present.begin(); it != present.end(); it++) { int colour = it->first; if(front_frequency[colour] + back_frequency[colour] >= half) { int moves_for_this_colour = half - front_frequency[colour]; minimum_moves = min(minimum_moves, max(0, moves_for_this_colour)); } } printf("%d\n", minimum_moves > no_of_cards ? -1 : minimum_moves); return 0; } ================================================ FILE: Contests/Div 2 205/Programs/Little Elephant and Cards.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_cards; scanf("%d", &no_of_cards); map present; map front_frequency; map back_frequency; for(int i = 1; i <= no_of_cards; i++) { int front, back; scanf("%d %d", &front, &back); front_frequency[front]++; if(front != back) //If front and back have the same colour, count only for front. back_frequency[back]++; present[front] = true; present[back] = true; } int half = no_of_cards/2 + no_of_cards%2; int minimum_moves = no_of_cards + 1; for(map :: iterator it = present.begin(); it != present.end(); it++) { int colour = it->first; if(front_frequency[colour] + back_frequency[colour] >= half) { int moves_for_this_colour = half - front_frequency[colour]; minimum_moves = min(minimum_moves, max(0, moves_for_this_colour)); } } printf("%d\n", minimum_moves > no_of_cards ? -1 : minimum_moves); return 0; } ================================================ FILE: Contests/Div 2 205/Programs/Little Elephant and Sorting.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); long long no_of_additions = 0; for(int i = 1; i <= no_of_elements; i++) { if(A[i] < A[i - 1]) { no_of_additions += (A[i - 1] - A[i]); } } printf("%I64d\n", no_of_additions); return 0; } ================================================ FILE: Contests/Div 2 205/Programs/Little_Elephant_Rozdil.c ================================================ #include #include void read_time_taken_to_each_city(unsigned int,unsigned long *); void find_which_city_elephant_goes_to(unsigned int,unsigned long *, unsigned int *,unsigned int *); int main() { unsigned int no_of_cities, no_of_minima, city_with_minimum_time; scanf("%u",&no_of_cities); unsigned long *time_taken_to_city = malloc(no_of_cities*(sizeof(unsigned long))); read_time_taken_to_each_city(no_of_cities, time_taken_to_city); find_which_city_elephant_goes_to(no_of_cities, time_taken_to_city, &city_with_minimum_time, &no_of_minima); //Pass by reference if(no_of_minima > 1) //If there is more than one city with the same minimum time, stay in Rozdil { printf("Still Rozdil\n"); } else //Otherwise, tell the number of the city { printf("%u\n", city_with_minimum_time); } free(time_taken_to_city); return 0; } void read_time_taken_to_each_city(unsigned int no_of_cities,unsigned long *time_taken_to_city) { unsigned int i; for(i = 0; i < no_of_cities; i++) { scanf("%lu",(time_taken_to_city + i)); } } void find_which_city_elephant_goes_to(unsigned int no_of_cities,unsigned long *time_taken_to_city, unsigned int *city_with_minimum_time,unsigned int *no_of_minima) { unsigned int i; //First element is marked as minima initially *city_with_minimum_time = 0; *no_of_minima = 1; for(i = 1; i < no_of_cities; i++) { if( *(time_taken_to_city + i) < *(time_taken_to_city + *(city_with_minimum_time)))//If it is less than minima, change the minima { *city_with_minimum_time = i; *no_of_minima = 1; //Reseting the count of minima } else if( *(time_taken_to_city + i) == *(time_taken_to_city + *(city_with_minimum_time))) { *no_of_minima = *no_of_minima + 1; } } if(*no_of_minima == 1)//If there is only one minima, increment the value of city because we have started counting from 0 rather than 1 { *(city_with_minimum_time) = *(city_with_minimum_time) + 1; } } ================================================ FILE: Contests/Div 2 261/Explanation/Pashmak and Buses Explanation.txt ================================================ Let us represent the activities of each student as a d-tuple. (b1, b2, ... bd), where bi represents the bus taken on day i. Each day you can take k buses. Overall, there are k^d distinct d-tuples. If two tuples are the same, then it means two students take the same bus everyday. If k^d < N, then by the pigeonhole principle there will be two d-tuples that are the same at every spot. So, if k^d < N, then it is not possible. int possible(int people, int buses, int days) { //Check if k^d > n for(int power = 1, d = 0; d <= days; power *= buses, d++) { if(power >= people) return true; } return false; } ------------------------------------------------- Otherwise, let us generate the first N numbers of length d in base k. (In other words, we're visiting the d-tuples in lexicographic order.) for(int p = 0; p < no_of_people; p++) { for(int d = 0; d < no_of_days; d++) { arrangement[p][d] = (p == 0 ? 0 : arrangement[p - 1][d]); } for(int d = no_of_days - 1; d >= 0; d--) { arrangement[p][d]++; arrangement[p][d] %= no_of_buses; if(arrangement[p][d] != 0) break; } } ----------------------------------------- It's easy to generate this with respect to d-tuples, but the output must be in n-tuples for(int d = 0; d < no_of_days; d++) { for(int p = 0; p < no_of_people; p++) { printf("%d ", arrangement[p][d] + 1); } printf("\\n"); } ================================================ FILE: Contests/Div 2 261/Explanation/Pashmak and Buses.cpp ================================================ #include const int MAX_N = 1015; int arrangement[MAX_N][MAX_N]; int possible(int people, int buses, int days) { //Check if k^d > n for(int power = 1, d = 0; d <= days; power *= buses, d++) { if(power >= people) return true; } return false; } int main() { int no_of_people, no_of_buses, no_of_days; scanf("%d %d %d", &no_of_people, &no_of_buses, &no_of_days); if(!possible(no_of_people, no_of_buses, no_of_days)) { printf("-1\n"); return 0; } for(int p = 0; p < no_of_people; p++) { for(int d = 0; d < no_of_days; d++) { arrangement[p][d] = (p == 0 ? 0 : arrangement[p - 1][d]); } for(int d = no_of_days - 1; d >= 0; d--) { arrangement[p][d]++; arrangement[p][d] %= no_of_buses; if(arrangement[p][d] != 0) break; } } for(int d = 0; d < no_of_days; d++) { for(int p = 0; p < no_of_people; p++) { printf("%d ", arrangement[p][d] + 1); } printf("\n"); } return 0; } ================================================ FILE: Contests/Div 2 261/Explanation/Pashmak and Flowers - Explanation.txt ================================================ Pashmak decided to give Parmida a pair of flowers from the garden. There are n flowers in the garden and the i-th of them has a beauty number bi. Parmida is a very strange girl so she doesn't want to have the two most beautiful flowers necessarily. She wants to have those pairs of flowers that their beauty difference is maximal possible! Your task is to write a program which calculates two things: The maximum beauty difference of flowers that Pashmak can give to Parmida. The number of ways that Pashmak can pick the flowers. Two ways are considered different if and only if there is at least one flower that is chosen in the first way and not chosen in the second way. --------------------------------------------------------------------------------------------- We need to count the number of maxima and the number of minima and multiply them. I had overlooked overflow at first in multiplication and the case where the maxima and minima are equal. In that case, the answer is n(n-1)/2, where n is the number of flowers because all flowers are equally beautiful. Multiplying number of minima and maxima will not be correct in that case since it will be overcounting pairs. for(i = 1; i <= no_of_flowers; i++) { scanf("%d",¤t_beauty); if(current_beauty == most_beautiful) no_of_maxima++; if(current_beauty == least_beautiful) no_of_minima++; if(current_beauty < least_beautiful) least_beautiful = current_beauty, no_of_minima = 1; if(current_beauty > most_beautiful) most_beautiful = current_beauty, no_of_maxima = 1; } //If all flowers are equally beautiful, then choices = n(n-1)/2 no_of_choices = ( most_beautiful == least_beautiful ? (no_of_flowers*1LL*(no_of_flowers - 1) )/2 : no_of_minima*1LL*no_of_maxima ); printf("%d %I64d\n",(most_beautiful - least_beautiful), no_of_choices); -------------------------------------------------------------------------------------------------- Note - type casting by multiplying by 1LL is necessary to avoid overflow, otherwise 32 bit multiplication will be performed. ================================================ FILE: Contests/Div 2 261/Explanation/Pashmak and Garden Explanation.txt ================================================ Okay, if the x1 = x2, then it means we have a side parallel to y-axis. x3 = x1 + d, y3 = y1 x4 = x2 + 3, y4 = y2 Similar reasoning if y1 = y2, now, what happens if we have two diagonally opposite points ? Then, |x1 - x2| = |y1 - y2| This quantity is the same in squares. We are taking absolute values because it might be anti-diagonal as well. int main() { int x_1, x_2, y_1, y_2; scanf("%d %d %d %d", &x_1, &y_1, &x_2, &y_2); int x_3, y_3, x_4, y_4; if(x_1 == x_2) { int distance = abs(y_1 - y_2); x_3 = x_1 + distance; y_3 = y_1; x_4 = x_2 + distance; y_4 = y_2; } else if(y_1 == y_2) { int distance = abs(x_1 - x_2); y_3 = y_1 + distance; x_3 = x_1; y_4 = y_2 + distance; x_4 = x_2; } else if(abs(x_1 - x_2) == abs(y_1 - y_2)) { x_3 = x_1; y_3 = y_2; x_4 = x_2; y_4 = y_1; } else { printf("-1\n"); return 0; } printf("%d %d %d %d\n", x_3, y_3, x_4, y_4); return 0; } ================================================ FILE: Contests/Div 2 261/Explanation/Pashmak and Graph Explanation.txt ================================================ 1. We will keep an empty graph and add the edges one by one in ascending order of weight 2. When we add an edge (u, v) then we will update path[v] = max(1 + path[u], path[v]) 3. We have to be careful on handling edges of the same weight Suppose we have multiple edges ending at u and then at v, we can't use both u and v So, we will process all edges of the same weigh together ----- struct Edge { int source, destination, weight; int operator <(const Edge &A) { return (weight < A.weight); } }; int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); vector edge(no_of_edges + 1); for(int i = 1; i <= no_of_edges; i++) { scanf("%d %d %d", &edge[i].source, &edge[i].destination, &edge[i].weight); } sort(all(edge)); vector maximum_ending_at(no_of_vertices + 1, 0); vector maximum_with_this_weight(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_edges; ) { int j = i; for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = 0; } //Process all edges having this weight. Have a different vector so you don't interact with equal weights. for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = max(maximum_with_this_weight[edge[j].destination], 1 + maximum_ending_at[edge[j].source]); } for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_ending_at[edge[j].destination] = max(maximum_ending_at[edge[j].destination], maximum_with_this_weight[edge[j].destination]); } i = j; } int maximum_path = 0; for(int i = 1; i <= no_of_vertices; i++) maximum_path = max(maximum_path, maximum_ending_at[i]); printf("%d\n", maximum_path); return 0; } ================================================ FILE: Contests/Div 2 261/Explanation/Pashmak and Parmida's Problem Explanation.txt ================================================ Blog Link - http://qr.ae/TUpUkU Let L[i] be frequeny of i in prefix. R[i] be frequency of i in suffix. Maintain an array S, where the index is R[i] and value if frequency of R[i]. Process the indices from i = N to 1 For each i, take the sum of [1, L[i] - 1], and then increment S[R[i]] by 1. This ensures that whatever we have summed has R < L[i] because we have only taken the range L[i] - 1 And j > i, because we are inserting in descending order. If R[j] is already in S, then it means j > i So both conditions i < j and L[i] > R[j] are satisfied ! Beautiful Problem ! ---------------------------------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); map left_frequency; vector left(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { left_frequency[A[i]]++; left[i] = left_frequency[A[i]]; } map right_frequency; vector right(no_of_elements + 1, 0); for(int i = no_of_elements; i >= 1; i--) { right_frequency[A[i]]++; right[i] = right_frequency[A[i]]; } LL answer = 0; for(int i = no_of_elements; i >= 1; i--) { answer += get_sum(1, 1, no_of_elements, 1, left[i] - 1); //Adding all rights that are smaller than left update(1, 1, no_of_elements, right[i], 1); } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 261/Programs/Pashmak and Buses.cpp ================================================ #include const int MAX_N = 1015; int arrangement[MAX_N][MAX_N]; int possible(int people, int buses, int days) { //Check if k^d > n for(int power = 1, d = 0; d <= days; power *= buses, d++) { if(power >= people) return true; } return false; } int main() { int no_of_people, no_of_buses, no_of_days; scanf("%d %d %d", &no_of_people, &no_of_buses, &no_of_days); if(!possible(no_of_people, no_of_buses, no_of_days)) { printf("-1\n"); return 0; } for(int p = 0; p < no_of_people; p++) { for(int d = 0; d < no_of_days; d++) { arrangement[p][d] = (p == 0 ? 0 : arrangement[p - 1][d]); } for(int d = no_of_days - 1; d >= 0; d--) { arrangement[p][d]++; arrangement[p][d] %= no_of_buses; if(arrangement[p][d] != 0) break; } } for(int d = 0; d < no_of_days; d++) { for(int p = 0; p < no_of_people; p++) { printf("%d ", arrangement[p][d] + 1); } printf("\n"); } return 0; } ================================================ FILE: Contests/Div 2 261/Programs/Pashmak and Garden.cpp ================================================ #include #define abs(x) ( (x) > 0 ? (x) : -(x) ) int main() { int x_1, x_2, y_1, y_2; scanf("%d %d %d %d", &x_1, &y_1, &x_2, &y_2); int x_3, y_3, x_4, y_4; if(x_1 == x_2) { int distance = abs(y_1 - y_2); x_3 = x_1 + distance; y_3 = y_1; x_4 = x_2 + distance; y_4 = y_2; } else if(y_1 == y_2) { int distance = abs(x_1 - x_2); y_3 = y_1 + distance; x_3 = x_1; y_4 = y_2 + distance; x_4 = x_2; } else if(abs(x_1 - x_2) == abs(y_1 - y_2)) { x_3 = x_1; y_3 = y_2; x_4 = x_2; y_4 = y_1; } else { printf("-1\n"); return 0; } printf("%d %d %d %d\n", x_3, y_3, x_4, y_4); return 0; } ================================================ FILE: Contests/Div 2 261/Programs/Pashmak and Graph.cpp ================================================ #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; struct Edge { int source, destination, weight; int operator <(const Edge &A) { return (weight < A.weight); } }; int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); vector edge(no_of_edges + 1); for(int i = 1; i <= no_of_edges; i++) { scanf("%d %d %d", &edge[i].source, &edge[i].destination, &edge[i].weight); } sort(all(edge)); vector maximum_ending_at(no_of_vertices + 1, 0); vector maximum_with_this_weight(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_edges; ) { int j = i; for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = 0; } //Process all edges having this weight. Have a different vector so you don't interact with equal weights. for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_with_this_weight[edge[j].destination] = max(maximum_with_this_weight[edge[j].destination], 1 + maximum_ending_at[edge[j].source]); } for(j = i; j <= no_of_edges && edge[j].weight == edge[i].weight; j++) { maximum_ending_at[edge[j].destination] = max(maximum_ending_at[edge[j].destination], maximum_with_this_weight[edge[j].destination]); } i = j; } int maximum_path = 0; for(int i = 1; i <= no_of_vertices; i++) maximum_path = max(maximum_path, maximum_ending_at[i]); printf("%d\n", maximum_path); return 0; } ================================================ FILE: Contests/Div 2 261/Programs/Pashmak and Parmida's Problem.cpp ================================================ #include #include #include using namespace std; typedef long long LL; #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 1e6; LL sum_tree[3*MAX_N]; void update(int n, int left, int right, int position, int value) { if(right < position || position < left) return; if(left == right) { sum_tree[n] += value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, position, value); update(RIGHT(n), mid + 1, right, position, value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } LL get_sum(int n, int left, int right, int query_left, int query_right) { if(right < query_left || query_right < left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; LL left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); LL right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); map left_frequency; vector left(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { left_frequency[A[i]]++; left[i] = left_frequency[A[i]]; } map right_frequency; vector right(no_of_elements + 1, 0); for(int i = no_of_elements; i >= 1; i--) { right_frequency[A[i]]++; right[i] = right_frequency[A[i]]; } LL answer = 0; for(int i = no_of_elements; i >= 1; i--) { answer += get_sum(1, 1, no_of_elements, 1, left[i] - 1); //Adding all rights that are smaller than left update(1, 1, no_of_elements, right[i], 1); } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 261/Programs/Pashmak_and_Flowers.c ================================================ #include int main() { int no_of_minima = 0, no_of_maxima = 0, most_beautiful = 0, least_beautiful = 1e9 + 1, no_of_flowers, current_beauty, i; long long no_of_choices; scanf("%d", &no_of_flowers); for(i = 1; i <= no_of_flowers; i++) { scanf("%d",¤t_beauty); if(current_beauty == most_beautiful) no_of_maxima++; if(current_beauty == least_beautiful) no_of_minima++; if(current_beauty < least_beautiful) least_beautiful = current_beauty, no_of_minima = 1; if(current_beauty > most_beautiful) most_beautiful = current_beauty, no_of_maxima = 1; } //If all flowers are equally beautiful, then choices = n(n-1)/2 no_of_choices = ( most_beautiful == least_beautiful ? (no_of_flowers*1LL*(no_of_flowers - 1) )/2 : no_of_minima*1LL*no_of_maxima ); printf("%d %I64d\n",(most_beautiful - least_beautiful), no_of_choices); return 0; } ================================================ FILE: Contests/Div 2 276/Explanations/Little Girl and Maximum XOR Explanation.txt ================================================ Blog Link - http://qr.ae/TUTCDS Let L = 000110011 R = 0001101111 Notice that there must be some position p, where R[p] = 1, and L[p] = 0 and for all i < p, R[p] = L[p] The key observation here is that all numbers in between [L, R] will all have the same value for all those bits before p. The XOR of any two numbers will give 0. It doesn’t contribute anything. Now, the largest possible XOR we can get is a number with p 1’s since all the bits before that will always be 0 in any pair we choose. Now, I’ll prove it’s always possible to get a number with p 1’s. Let A match the common prefix of L and R. A[p] = 0, and let all positions after this = 1 A is smaller than R for sure since R[p] = 1. It is >= L. It can’t be smaller than L because it matches L till position P and from then has all 1’s. Let B match the common prefix of L and R till p. B[p] = 1, and then all positions after that have 0. B is greater than L because B[p] = 1 > L[p] B is <= R because it matches R till position P and from there has all 0s. (A xor B) = a string of 1’s. We don’t even need to find out what the numbers are ! ---------------------------------------------------------------------------------- int main() { long long left, right; scanf("%I64d %I64d", &left, &right); if(left == right) { printf("0\n"); return 0; } int largest_unequal_bit_position; for(int i = 0; left > 0 || right > 0; i++) { if(left%2 != right%2) largest_unequal_bit_position = i; left >>= 1; right >>= 1; } long long answer = all_ones(largest_unequal_bit_position); //This gives a number consisting of n 1's in binary printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 276/Programs/Little Girl and Maximum Sum.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector element(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector no_of_queries_starting_here(no_of_elements + 1, 0); vector no_of_queries_ending_here(no_of_elements + 1, 0); for(int i = 1; i <= no_of_queries; i++) { int left_i, right_i; scanf("%d %d", &left_i, &right_i); no_of_queries_starting_here[left_i]++; if(right_i + 1 <= no_of_elements) no_of_queries_ending_here[right_i + 1]++; } int no_of_queries_on_this_index = 0; vector no_of_times_index_queried(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { no_of_queries_on_this_index += (no_of_queries_starting_here[i] - no_of_queries_ending_here[i]); no_of_times_index_queried[i] = no_of_queries_on_this_index; } sort(all(element)); sort(all(no_of_times_index_queried)); long long maximum_sum = 0; for(int i = 1; i <= no_of_elements; i++) maximum_sum += no_of_times_index_queried[i]*1LL*element[i]; printf("%I64d\n", maximum_sum); return 0; } ================================================ FILE: Contests/Div 2 276/Programs/Little Girl and Maximum XOR.cpp ================================================ #include long long all_ones(int n) { return (1LL << (n + 1)) - 1; } int main() { long long left, right; scanf("%I64d %I64d", &left, &right); if(left == right) { printf("0\n"); return 0; } int largest_unequal_bit_position; for(int i = 0; left > 0 || right > 0; i++) { if(left%2 != right%2) largest_unequal_bit_position = i; left >>= 1; right >>= 1; } long long answer = all_ones(largest_unequal_bit_position); //This gives a number consisting of n 1's in binary printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 276/Programs/Lunch Rush.cpp ================================================ #include #define max(a, b) (a > b ? a : b) int main() { int no_of_restaurants, time_limit; scanf("%d %d", &no_of_restaurants, &time_limit); const int NEGATIVE_INFINITY = -1e9; int maximum_joy = NEGATIVE_INFINITY; for(int i = 1; i <= no_of_restaurants; i++) { int time_i, joy_i; scanf("%d %d", &joy_i, &time_i); if(time_i <= time_limit) { maximum_joy = max(maximum_joy, joy_i); } else { maximum_joy = max(maximum_joy, joy_i - (time_i - time_limit)); } } printf("%d\n", maximum_joy); return 0; } ================================================ FILE: Contests/Div 2 321/Programs/Kefa and Company.cpp ================================================ #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; struct info { int money, friendship; }; int sort_by_money(const info &A, const info &B) { return (A.money < B.money); } int main() { int no_of_friends, difference; scanf("%d %d", &no_of_friends, &difference); vector friends(no_of_friends + 1); for(int i = 1; i <= no_of_friends; i++) scanf("%d %d", &friends[i].money, &friends[i].friendship); sort(all(friends), sort_by_money); long long maximum_friendship = 0, current_friendship = 0; int left = 1, right = 1; while(right <= no_of_friends) { if(friends[right].money - friends[left].money < difference) { current_friendship += friends[right].friendship; right++; } else { current_friendship -= friends[left].friendship; left++; } maximum_friendship = max(maximum_friendship, current_friendship); } printf("%I64d\n", maximum_friendship); return 0; } ================================================ FILE: Contests/Div 2 321/Programs/Kefa and Park.cpp ================================================ #include #include using namespace std; const int MAX_VERTICES = 2e5 + 1; int visited[MAX_VERTICES] = {false}; int has_cat[MAX_VERTICES] = {false}; int no_of_consecutive_cats_till[MAX_VERTICES] = {0}; vector tree[MAX_VERTICES]; int max_cats; void dfs(int current_park, int &no_of_paths) { if(tree[current_park].size() == 1 && visited[tree[current_park][0]]) no_of_paths++; for(int i = 0; i < tree[current_park].size(); i++) { int next_park = tree[current_park][i]; if(!visited[next_park]) { visited[next_park] = true; no_of_consecutive_cats_till[next_park] = (has_cat[next_park] ? no_of_consecutive_cats_till[current_park] + 1 : 0); if(no_of_consecutive_cats_till[next_park] <= max_cats) dfs(next_park, no_of_paths); } } } int main() { int no_of_vertices; scanf("%d %d", &no_of_vertices, &max_cats); for(int i = 1; i <= no_of_vertices; i++) scanf("%d", &has_cat[i]); for(int i = 1; i <= no_of_vertices - 1; i++) { int x, y; scanf("%d %d", &x, &y); tree[x].push_back(y); tree[y].push_back(x); } no_of_consecutive_cats_till[1] = has_cat[1]; visited[1] = true; int no_of_paths = 0; dfs(1, no_of_paths); printf("%d\n", no_of_paths); return 0; } ================================================ FILE: Contests/Div 2 321/Programs/Kefa_and_First_Step.c ================================================ #include #include void read(unsigned long *, unsigned int); unsigned int find_length_longest_non_decreasing_streak(unsigned long *, unsigned int); unsigned long max(unsigned long, unsigned long); int main() { unsigned int no_of_days, longest_non_decreasing_streak; scanf("%u",&no_of_days); unsigned long *money_made = malloc(no_of_days*sizeof(unsigned long)); read(money_made, no_of_days); longest_non_decreasing_streak = find_length_longest_non_decreasing_streak(money_made, no_of_days); printf("%u\n",longest_non_decreasing_streak); free(money_made); return 0; } unsigned int find_length_longest_non_decreasing_streak(unsigned long *money_made, unsigned int no_of_days) { unsigned int i, longest_non_decreasing_streak = 1, current_non_decreasing_streak = 1 ; for(i = 1; i < no_of_days; i++) { //If A[i] >= A[i-1], current streak increases, else a new streak begins. current_non_decreasing_streak = ( ( *(money_made + i) >= *(money_made + i -1) ) ? current_non_decreasing_streak+1 : 1 ); longest_non_decreasing_streak = max(longest_non_decreasing_streak, current_non_decreasing_streak); } return longest_non_decreasing_streak; } void read(unsigned long *money_made, unsigned int no_of_days) { unsigned int i; for(i = 0; i < no_of_days; i++) { scanf("%lu",(money_made + i)); } } unsigned long max(unsigned long a, unsigned long b) { return ( (a > b) ? a : b); } ================================================ FILE: Contests/Div 2 367/Explanation/Hard Problem Explanation.txt ================================================ Blog Link - http://qr.ae/TUT2km ----------------------------------------- Here's the main idea. Assume the first i elements of the list are already sorted. How can you place string (i + 1) at the end of this list ? There are two options - Either you place it reversed, or un-reversed. f(i, R) = Minimum cost for the first i strings with last string reversed. f(i, U) = Minimum cost for the first i strings with last string unreversed. if(s[i] >= s[i - 1]) f(i, U) = f(i - 1, U) if(s[i] >= R(s[i - 1]) f(i, U) = min{f(i, U), f(i - 1, R)} if(R(s[i]) >= s[i - 1]) f(i, R) = c[i] + f(i - 1, U) if(R(s[i]) >= R(s[i - 1])) f(i, R) = min{f(i, R), c[i] + f(i - 1, R)} Answer = min{f(N, R), f(N, U)} Check if answer >= oo, in which case it's not possible. ------------------------------------------------------------------------------ string rev(string s) { reverse(all(s)); return s; } int main() { int no_of_strings; scanf("%d", &no_of_strings); vector cost(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) scanf("%d", &cost[i]); vector s(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) cin >> s[i]; const long long oo = 1e16; const int WITHOUT_REVERSING = 0, REVERSING = 1; long long minimum_till[no_of_strings + 1][2]; minimum_till[0][REVERSING] = minimum_till[0][WITHOUT_REVERSING] = 0; for(int i = 1; i <= no_of_strings; i++) { minimum_till[i][REVERSING] = minimum_till[i][WITHOUT_REVERSING] = oo; if(s[i] >= s[i - 1]) minimum_till[i][WITHOUT_REVERSING] = minimum_till[i - 1][WITHOUT_REVERSING]; if(s[i] >= rev(s[i - 1])) minimum_till[i][WITHOUT_REVERSING] = min(minimum_till[i][WITHOUT_REVERSING], minimum_till[i - 1][REVERSING]); if(rev(s[i]) >= s[i - 1]) minimum_till[i][REVERSING] = cost[i] + minimum_till[i - 1][WITHOUT_REVERSING]; if(rev(s[i]) >= rev(s[i - 1])) minimum_till[i][REVERSING] = min(minimum_till[i][REVERSING], cost[i] + minimum_till[i - 1][REVERSING]); } long long answer = min(minimum_till[no_of_strings][REVERSING], minimum_till[no_of_strings][WITHOUT_REVERSING]); printf("%I64d\n", answer >= oo ? -1 : answer); return 0; } ================================================ FILE: Contests/Div 2 367/Explanation/Interesting Drink Explanation.txt ================================================ Vasiliy likes to rest after a hard work, so you may often meet him in some bar nearby. As all programmers do, he loves the famous drink "Beecola", which can be bought in n different shops in the city. It's known that the price of one bottle in the shop i is equal to xi coins. Vasiliy plans to buy his favorite drink for q consecutive days. He knows, that on the i-th day he will be able to spent mi coins. Now, for each of the days he want to know in how many different shops he can buy a bottle of "Beecola". ------------------------------------------------- Sort all the drinks in ascending order of price and then use upper bound. upper bound returns the rightmost index that is <= key. It is already one indexed so no need to decrease by 1. If all the prices are greater, than it will return 0. If all are smaller it will return n. ------------------------------------------------------------ int main() { int no_of_shops; scanf("%d", &no_of_shops); vector price_in_shop(no_of_shops); for(int i = 0; i < no_of_shops; i++) scanf("%d", &price_in_shop[i]); sort(all(price_in_shop)); int no_of_days, budget_day_i; scanf("%d", &no_of_days); for(int i = 1; i <= no_of_days; i++) { scanf("%d", &budget_day_i); int no_of_eligible_shops = upper_bound(all(price_in_shop), budget_day_i) - price_in_shop.begin(); printf("%d\n",no_of_eligible_shops); //0 indexed vector so no need to subtract 1. } return 0; } ================================================ FILE: Contests/Div 2 367/Programs/Hard Problem.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; string rev(string s) { reverse(all(s)); return s; } int main() { int no_of_strings; scanf("%d", &no_of_strings); vector cost(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) scanf("%d", &cost[i]); vector s(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) cin >> s[i]; const long long oo = 1e16; const int WITHOUT_REVERSING = 0, REVERSING = 1; long long minimum_till[no_of_strings + 1][2]; minimum_till[0][REVERSING] = minimum_till[0][WITHOUT_REVERSING] = 0; for(int i = 1; i <= no_of_strings; i++) { minimum_till[i][REVERSING] = minimum_till[i][WITHOUT_REVERSING] = oo; if(s[i] >= s[i - 1]) minimum_till[i][WITHOUT_REVERSING] = minimum_till[i - 1][WITHOUT_REVERSING]; if(s[i] >= rev(s[i - 1])) minimum_till[i][WITHOUT_REVERSING] = min(minimum_till[i][WITHOUT_REVERSING], minimum_till[i - 1][REVERSING]); if(rev(s[i]) >= s[i - 1]) minimum_till[i][REVERSING] = cost[i] + minimum_till[i - 1][WITHOUT_REVERSING]; if(rev(s[i]) >= rev(s[i - 1])) minimum_till[i][REVERSING] = min(minimum_till[i][REVERSING], cost[i] + minimum_till[i - 1][REVERSING]); } long long answer = min(minimum_till[no_of_strings][REVERSING], minimum_till[no_of_strings][WITHOUT_REVERSING]); printf("%I64d\n", answer >= oo ? -1 : answer); return 0; } ================================================ FILE: Contests/Div 2 367/Programs/Interesting Drink.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_shops; scanf("%d", &no_of_shops); vector price_in_shop(no_of_shops); for(int i = 0; i < no_of_shops; i++) scanf("%d", &price_in_shop[i]); sort(all(price_in_shop)); int no_of_days, budget_day_i; scanf("%d", &no_of_days); for(int i = 1; i <= no_of_days; i++) { scanf("%d", &budget_day_i); int no_of_eligible_shops = upper_bound(all(price_in_shop), budget_day_i) - price_in_shop.begin(); printf("%d\n",no_of_eligible_shops); //0 indexed vector so no need to subtract 1. } return 0; } ================================================ FILE: Contests/Div 2 371/Explanations/Sonya and Queries Explanation.txt ================================================ I was thinking of a very complicated solution involving tries, but there's actually a very simple, elegant and beautiful solution to this problem ! Maintain a frequency array. Rather than storing the numbers, store the mask of the number ! We only have about 2^{18} masks ! Here's how you get the mask of an integer - int get_mask(long long n) { int mask = 0; for(int bit = 0; n > 0; bit++) { int digit = n%10; if(digit%2 == 1) mask |= (1LL << bit); n /= 10; } return mask; } Set the bit at all the odd digits. ----------------------------------------------------- For each query, give the frequency of the mask ! We're done ! while(no_of_queries--) { const char INSERTION = '+', DELETION = '-', QUERY = '?'; char query_type; cin >> query_type; if(query_type == INSERTION) { long long n; cin >> n; frequency[get_mask(n)]++; } else if(query_type == DELETION) { long long n; cin >> n; frequency[get_mask(n)]--; } else if(query_type == QUERY) { string mask; cin >> mask; cout << frequency[to_integer(mask)] << "\n"; } } ================================================ FILE: Contests/Div 2 371/Programs/Filya_and_Homework.c ================================================ #include #include #include #define true 1 #define false 0 short count_no_of_distinct_elements(unsigned long *,unsigned long, unsigned long[]); short check_if_set_is_in_AP(unsigned long[], short); void get_answer(char[], short); int main() { short is_possible = false, distinct_count; unsigned long no_of_elements, i, distinct_element[3]; unsigned long *list_of_numbers = NULL; char answer[4]; scanf("%lu",&no_of_elements); list_of_numbers = malloc(no_of_elements*sizeof(unsigned long)); for(i = 0; i < no_of_elements; i++) { scanf("%lu",(list_of_numbers + i)); } distinct_count = count_no_of_distinct_elements(list_of_numbers, no_of_elements, distinct_element); if(distinct_count > 3) { is_possible = false; } else { is_possible = check_if_set_is_in_AP(distinct_element, distinct_count); } get_answer(answer, is_possible); printf("%s\n",answer); free(list_of_numbers); return 0; } short count_no_of_distinct_elements(unsigned long *list_of_numbers,unsigned long no_of_elements, unsigned long distinct_element[]) { short distinct_count = 0, already_counted; int i, j; for(i = 0; i < no_of_elements; i++) { already_counted = false; //For the i=th element, for(j = 0; j < distinct_count ; j++) { if(*(list_of_numbers + i) == distinct_element[j]) { already_counted = true; break; } } if(already_counted == false) { distinct_element[distinct_count] = *(list_of_numbers + i); distinct_count++; if(distinct_count > 3) //If it exceeds three, just stop. Because it isn't possible for more than three distinct elements. { break; } } } return distinct_count ; } short check_if_set_is_in_AP(unsigned long distinct_element[], short distinct_count) { short set_is_in_AP = false; if(distinct_count < 3) //Set of 2 or 1 element will always be in AP { set_is_in_AP = true; return set_is_in_AP; } unsigned long a = distinct_element[0], b = distinct_element[1], c = distinct_element[2]; if( (a + c == 2*b) || (b + c == 2*a) || (b + a == 2*c) ) { set_is_in_AP = true; } return set_is_in_AP; } void get_answer(char answer[], short is_possible) { if(is_possible == true) { strcpy(answer, "YES"); } else { strcpy(answer, "NO"); } } ================================================ FILE: Contests/Div 2 371/Programs/Meeting_of_Old_Friends.c ================================================ #include #define max(a,b) (a > b ? a : b) #define min(a,b) (a < b ? a : b) int main() { long long sonya_start, sonya_end, filya_start, filya_end, no_of_minutes, prinking_minute, meeting_start, meeting_end; scanf("%I64d %I64d %I64d %I64d %I64d",&sonya_start, &sonya_end, &filya_start, &filya_end, &prinking_minute); meeting_start = max(sonya_start, filya_start); meeting_end = min(sonya_end, filya_end); no_of_minutes = (meeting_end >= meeting_start) ? (meeting_end - meeting_start + 1) : 0; //Inclusive of starting and ending time no_of_minutes -= (prinking_minute >= meeting_start) && (prinking_minute <= meeting_end)? 1 : 0; //Decrement 1 if k is in the meeting time printf("%I64d\n",no_of_minutes); return 0; } ================================================ FILE: Contests/Div 2 371/Programs/Sonya and Queries.cpp ================================================ #include #include #include using namespace std; int to_integer(string S) { int mask = 0; for(int i = S.size() - 1, bit = 0; i >= 0; i--, bit++) { if(S[i] == '1') mask |= (1LL << bit); } return mask; } int get_mask(long long n) { int mask = 0; for(int bit = 0; n > 0; bit++) { int digit = n%10; if(digit%2 == 1) mask |= (1LL << bit); n /= 10; } return mask; } int main() { int no_of_queries; cin >> no_of_queries; map frequency; while(no_of_queries--) { const char INSERTION = '+', DELETION = '-', QUERY = '?'; char query_type; cin >> query_type; if(query_type == INSERTION) { long long n; cin >> n; frequency[get_mask(n)]++; } else if(query_type == DELETION) { long long n; cin >> n; frequency[get_mask(n)]--; } else if(query_type == QUERY) { string mask; cin >> mask; cout << frequency[to_integer(mask)] << "\n"; } } return 0; } ================================================ FILE: Contests/Div 2 461/Explanations/Cave Paintings Explanation.txt ================================================ Let us try to examine the properties of n, if it had a different remainder with every number from 1 to k. n = 0 (mod 1) This means n = 1 (mod 2) No other option. Similarly, n = 2 (mod 3) n = 3 (mod 4) And so on. At every stage, n = -1 (mod i) This means, (n + 1) = 0 (mod i) This means that (n + 1) must be divisible by every number from 1 to i. I made the mistake of thinking that it means (n + 1) should be i!, and then a multiple of i!, but that's incorrect. It's a common mistake. If you mark multiples of A and B, multiples of LCM(A, B) will be marked twice, not AB. LCM(A, B) = AB, when they are coprime. So, actually (n + 1) should be a multiple of all numbers from 1 to i, means it should be divisibly by LCM(1, ... , i) I checked how fast the sequence grows and when i = 43, it is > 10^18. So in the contest, I precomputed all LCM's from 1 to 42, and then if k < 43 and (n + 1)%lcm(43) == 0, Answer is yes ------------------------------------------------------------------------------ #include int main() { long long n, k; scanf("%I64d %I64d", &n, &k); long long lcm_1_till[45]; lcm_1_till[1] = 1; for(int i = 2; i < 43; i++) { int ii = i; long long extra = 1, lcm_i_minus_1 = lcm_1_till[i - 1]; for(int j = 2; j <= ii; j++) { while(ii%j == 0) { ii /= j; if(lcm_i_minus_1%j == 0) lcm_i_minus_1 /= j; else extra *= j; } } lcm_1_till[i] = lcm_1_till[i - 1]*extra; } printf( k < 43 && (n + 1)%lcm_1_till[k] == 0 ? "Yes\n" : "No\n"); return 0; } ------------------------------------------------------------------------------- After the contest, and reading the editorial, I made it cleaner by realising that no need of precomputing, k < 43, so you can check every number from 1 to 42, provided k < 43 int main() { long long n, k; scanf("%I64d %I64d", &n, &k); const int LIMIT = 43; int divisible_by_lcm = true; if(k < LIMIT) { for(int i = 1; i <= k; i++) { if( (n + 1)%i != 0) { divisible_by_lcm = false; break; } } } printf(k < LIMIT && divisible_by_lcm ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/Div 2 461/Programs/Cave Paintings.cpp ================================================ #include int main() { long long n, k; scanf("%I64d %I64d", &n, &k); const int LIMIT = 43; int divisible_by_lcm_1_till_k = true; if(k < LIMIT) { for(int i = 1; i <= k; i++) { if( (n + 1)%i != 0) { divisible_by_lcm_1_till_k = false; break; } } } printf(k < LIMIT && divisible_by_lcm_1_till_k ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/Div 2 464/Programs/Love Triangle.cpp ================================================ #include #include using namespace std; int main() { int no_of_planes; scanf("%d", &no_of_planes); vector liked_by(no_of_planes + 1); for(int i = 1; i <= no_of_planes; i++) scanf("%d", &liked_by[i]); int love_triangle_exists = false; for(int i = 1; i <= no_of_planes; i++) { int a = i; int b = liked_by[a]; int c = liked_by[b]; if(a == liked_by[c]) { love_triangle_exists = true; } } printf(love_triangle_exists ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 473/Explanation/Mahmoud and Ehab and Another Array Construction Task Explanation.txt ================================================ Blog Link - http://qr.ae/TUTAnY If all the elements are pairwise coprime, then it means that no prime number occurs in the prime factorisation of two numbers. Let us keep an array Used[] Used[x] = true, if prime factor x occurs in the factorisation of some A[i]. Used[x] = false, otherwise. Now, we go through each A[i], If all of A[i]'s prime factors are unused, then mark all of them and add A[i] to the solution. If we get an A[i], which has at least one used prime factor, Then, x = A[i], while(all_prime_factors_unused(x)) x++ And then insert x to the solution. Now, we have lexicographically larger B. From here, onwards, we must print the smallest numbers that are not used. These numbers must be prime. Let us suppose we have a composite numbe C. We can get a smaller number by replacing C with any of it's prime factors. So, here's the overall algorithm. 1. Push as many A[i] as possible. 2. If an A[i] is not possible, x = A[i] + 1, keep incrementing till x is possible. 3. After x, print the smallest unused primes. ----------------------------------------------------------------------------------------------- void sieve(vector &is_prime, int LIMIT) { is_prime[0] = is_prime[1] = false; for(long long i = 2; i*i <= LIMIT; i++) { if(is_prime[i]) { for(long long multiple = i*i; multiple <= LIMIT; multiple += i) { is_prime[multiple] = false; } } } } int all_prime_factors_available(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { if(used[p] == true) return false; n /= p; } } if(n > 1 && used[n]) return false; return true; } void mark_prime_factors(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { used[p] = true; n /= p; } } if(n > 1) used[n] = true; } int main() { const int LIMIT = 2e6; vector is_prime(LIMIT, true); sieve(is_prime, LIMIT); int no_of_elements; scanf("%d", &no_of_elements); vector original(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original[i]); vector solution; vector used(LIMIT, false); for(int i = 0; i < no_of_elements; i++) { if(all_prime_factors_available(original[i], used)) { solution.push_back(original[i]); mark_prime_factors(original[i], used); } else { int x = original[i] + 1; while(!all_prime_factors_available(x, used)) x++; mark_prime_factors(x, used); solution.push_back(x); break; } } for(int i = 2; i < LIMIT && solution.size() < no_of_elements; i++) { if(!used[i] && is_prime[i]) solution.push_back(i); } for(int i = 0; i < no_of_elements; i++) printf("%d ", solution[i]); return 0; } ================================================ FILE: Contests/Div 2 473/Explanation/Mahmoud and Ehab and Even Odd Game Explanation.txt ================================================ If n is even, then Mahmoud takes n and wins. If n is odd, no matter what even number takes, he leaves an odd number for Ehab. Ehab then takes it and wins. ----------------------------------------------------- int main() { int n; scanf("%d", &n); printf(n%2 == 0 ? "Mahmoud\n" : "Ehab\n"); return 0; } ================================================ FILE: Contests/Div 2 473/Programs/Mahmoud and Ehab and Another Array Construction Task.cpp ================================================ #include #include using namespace std; void sieve(vector &is_prime, int LIMIT) { is_prime[0] = is_prime[1] = false; for(long long i = 2; i*i <= LIMIT; i++) { if(is_prime[i]) { for(long long multiple = i*i; multiple <= LIMIT; multiple += i) { is_prime[multiple] = false; } } } } int all_prime_factors_available(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { if(used[p] == true) return false; n /= p; } } if(n > 1 && used[n]) return false; return true; } void mark_prime_factors(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { used[p] = true; n /= p; } } if(n > 1) used[n] = true; } int main() { const int LIMIT = 2e6; vector is_prime(LIMIT, true); sieve(is_prime, LIMIT); int no_of_elements; scanf("%d", &no_of_elements); vector original(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original[i]); vector solution; vector used(LIMIT, false); for(int i = 0; i < no_of_elements; i++) { if(all_prime_factors_available(original[i], used)) { solution.push_back(original[i]); mark_prime_factors(original[i], used); } else { int x = original[i] + 1; while(!all_prime_factors_available(x, used)) x++; mark_prime_factors(x, used); solution.push_back(x); break; } } for(int i = 2; i < LIMIT && solution.size() < no_of_elements; i++) { //printf("i = %d, u %d, p %d\n", i, used[i], is_prime[i]); if(!used[i] && is_prime[i]) solution.push_back(i); } for(int i = 0; i < no_of_elements; i++) printf("%d ", solution[i]); return 0; } ================================================ FILE: Contests/Div 2 473/Programs/Mahmoud and Ehab and Even Odd Game.cpp ================================================ #include int main() { int n; scanf("%d", &n); printf(n%2 == 0 ? "Mahmoud\n" : "Ehab\n"); return 0; } ================================================ FILE: Contests/Div 2 478/Explanations/Aramic Script Bitmask Solution.txt ================================================ Maintain a binary string of length 26. Construct a binary string with each given string as follows : The i-th bit is set if the i-th alphabet is present in the string and 0 otherwise. Strings which have the same 'root' have the same mask. Count the number of distinct masks. ------------------------------------------------ int main() { int no_of_words; cin >> no_of_words; set mask; while(no_of_words--) { string word; cin >> word; int current_mask = 0; for(int i = 0; i < word.size(); i++) current_mask |= (1 << (word[i] - 'a')); mask.insert(current_mask); } cout << mask.size(); return 0; } ================================================ FILE: Contests/Div 2 478/Explanations/Aramic Script Explanation.txt ================================================ For each string, keep track of which alphabets were used. And then make another string X, consisting of exactly one occurence of each of it's alphabets in alphabetical order. This ensures strings which have the same root are mapped to the same X. Count the number of distinct X. ---------------------------------------------------------- int main() { int no_of_words; cin >> no_of_words; set distinct_words; while(no_of_words--) { string word; cin >> word; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < word.size(); i++) present[word[i] - 'a'] = true; string root; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(present[i]) root += (char)('a' + i); distinct_words.insert(root); } cout << distinct_words.size(); return 0; } ================================================ FILE: Contests/Div 2 478/Explanations/Ghosts Explanation.txt ================================================ Unlike most problems, this problems specifically asks us to overcount rather than avoid it. Each collision must be counted two times - once for each ghost. Now, the equation for the motion of a ghost = P + VT, where V is velocity, T is time and P is position. We have two dimensions and the equations need to be applied seperately on both. Now the trick is in noticing that two ghosts will intersect if the time for their x coordinates to be equal is the same as the Y. X1 + Vx1T = X2 + Vx2T X1 - X2 = T(Vx2 - Vx1) T = (X1 - X2)/(Vx2 - Vx1) And Y1 + Vy1T = Y2 + Vy2T Y1 - Y2 = T(Vy2 - Vy1) T = (Y1 - Y2)/(Vy2 - Vy1) (X1 - X2)/(Vx2 - Vx1) = (Y1 - Y2)/(Vy2 - Vy1) (X1 - X2)/(Vx2 - Vx1) = (aX1 + b - aX2 - b)/(Vy2 - Vy1) (X1 - X2)/(Vx2 - Vx1) = a(X1 - X2)/(Vy2 - Vy1) 1/(Vx2 - Vx1) = a/(Vy2 - Vy1) Vy2 - Vy1 = aVx2 - aVx1 ------------------------------- aVx1 - Vy1 = aVx2 - Vy2 This shows that ghosts which have the same aVx - Vy intersect at some point. However, we need to notice that if two ghosts are parallel (V1 = V2) then they never meet. --------------------------------- Take each ghost. That ghost intersects with all ghosts who have aVx - Vy value, but not with those that have the same V. (Parallel) A very elegant way to keep track of slopes is to maintain a map of pairs. {Vx, Vy}. Maintain another map for {aVx - Vy} ------------------------------------------ Multiply the number of collisions by 2 at the end. ------------------------------------------------------ int main() { int no_of_points, a, b; scanf("%d %d %d", &no_of_points, &a, &b); long long total_collisions = 0; map < pair, int > slope_count; map intersections; for(int i = 1; i <= no_of_points; i++) { int x, vx, vy; scanf("%d %d %d", &x, &vx, &vy); total_collisions += intersections[a*1LL*vx - vy] - slope_count[make_pair(vx, vy)]; //Parallel points don't meet. slope_count[make_pair(vx, vy)]++; intersections[a*1LL*vx - vy]++; } total_collisions *= 2; printf("%I64d\n", total_collisions); return 0; } ================================================ FILE: Contests/Div 2 478/Explanations/Mancala Explanation.txt ================================================ There are only 14 hold. The problem is small enough to simulate. Take each hole. Calculate the answer if this hole was redistributed. And keep track of the best hole. How to calculate the answer if a particular hole is distributed ? Well, let's say hole[i] has S stones. And let S = 14q + r, q is the quotient, r is the remainder, 0 <= r < 14 Now, first of all set hole[i] = 0. Then all 14 holes will get an additional q stones. Then simulate the process of distributing the left out r stones. (Start from (i + 1) and give one stone to all holes till you run out of stones.) After this do an O(n) scan to find out the hole with the maximum number of stones. This requires 3 O(n) scans. We do this for all 14 holes. So 42 O(n) scans. ------------------------------------------------------------ long long score_by_distributing(int chosen, vector stone, int no_of_holes) { int quotient = stone[chosen]/no_of_holes, remainder = stone[chosen]%no_of_holes; stone[chosen] = 0; int current = chosen; do { stone[current] += quotient; current = (current + 1)%no_of_holes; } while(current != chosen); current = (chosen + 1)%no_of_holes; while(remainder > 0) { stone[current]++; remainder--; current = (current + 1)%no_of_holes; } long long score = 0; for(int i = 0; i < stone.size(); i++) if(stone[i]%2 == 0) score += stone[i]; return score; } int main() { const int NO_OF_HOLES = 14; vector stone(NO_OF_HOLES); for(int i = 0; i < NO_OF_HOLES; i++) cin >> stone[i]; long long maximum_score = 0; for(int i = 0; i < NO_OF_HOLES; i++) maximum_score = max(maximum_score, score_by_distributing(i, stone, NO_OF_HOLES)); cout << maximum_score; return 0; } ================================================ FILE: Contests/Div 2 478/Explanations/Valhalla Siege Explanation.txt ================================================ To kill i soldiers, we need to shoot S[1] + S[2] + ... + S[i] arrows. Maintain a prefix sum array. Keep track of the total number of arrows shot so far. If total_arrows >= S[n], then total_arrows = 0 After that use binary search and find the smallest position i, such that total_arrows < S[i]. (i - 1) soldiers would have been dead at that time and the remaining N - i are alive. ----------------------------------------------------------- int main() { int no_of_soldiers, no_of_queries; scanf("%d %d", &no_of_soldiers, &no_of_queries); vector strength(no_of_soldiers + 1); for(int i = 1; i <= no_of_soldiers; i++) scanf("%I64d", &strength[i]); vector sum(no_of_soldiers + 1, 0); for(int i = 1; i <= no_of_soldiers; i++) sum[i] = sum[i - 1] + strength[i]; long long total_arrows = 0; while(no_of_queries--) { long long arrows; scanf("%I64d", &arrows); total_arrows += arrows; if(total_arrows >= sum[no_of_soldiers]) total_arrows = 0; int no_of_dead_soldiers = upper_bound(all(sum), total_arrows) - sum.begin() - 1; int no_of_alive_soldiers = no_of_soldiers - no_of_dead_soldiers; printf("%d\n", no_of_alive_soldiers); } return 0; } ================================================ FILE: Contests/Div 2 478/Programs/Aramic Script Bitmask Solution.cpp ================================================ #include #include using namespace std; int main() { int no_of_words; cin >> no_of_words; set mask; while(no_of_words--) { string word; cin >> word; int current_mask = 0; for(int i = 0; i < word.size(); i++) current_mask |= (1 << (word[i] - 'a')); mask.insert(current_mask); } cout << mask.size(); return 0; } ================================================ FILE: Contests/Div 2 478/Programs/Aramic Script.cpp ================================================ #include #include #include #include #include #define all (v) (v).begin(), (v).end() using namespace std; int main() { int no_of_words; cin >> no_of_words; set distinct_words; while(no_of_words--) { string word; cin >> word; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < word.size(); i++) present[word[i] - 'a'] = true; string root; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(present[i]) root += (char)('a' + i); distinct_words.insert(root); } cout << distinct_words.size(); return 0; } ================================================ FILE: Contests/Div 2 478/Programs/Ghosts.cpp ================================================ #include #include using namespace std; int main() { int no_of_points, a, b; scanf("%d %d %d", &no_of_points, &a, &b); long long total_collisions = 0; map < pair, int > slope_count; map intersections; for(int i = 1; i <= no_of_points; i++) { int x, vx, vy; scanf("%d %d %d", &x, &vx, &vy); total_collisions += intersections[a*1LL*vx - vy] - slope_count[make_pair(vx, vy)]; //Parallel points don't meet. slope_count[make_pair(vx, vy)]++; intersections[a*1LL*vx - vy]++; } total_collisions *= 2; printf("%I64d\n", total_collisions); return 0; } ================================================ FILE: Contests/Div 2 478/Programs/Mancala.cpp ================================================ #include #include using namespace std; long long score_by_distributing(int chosen, vector stone, int no_of_holes) { int quotient = stone[chosen]/no_of_holes, remainder = stone[chosen]%no_of_holes; stone[chosen] = 0; int current = chosen; do { stone[current] += quotient; current = (current + 1)%no_of_holes; } while(current != chosen); current = (chosen + 1)%no_of_holes; while(remainder > 0) { stone[current]++; remainder--; current = (current + 1)%no_of_holes; } long long score = 0; for(int i = 0; i < stone.size(); i++) if(stone[i]%2 == 0) score += stone[i]; return score; } int main() { const int NO_OF_HOLES = 14; vector stone(NO_OF_HOLES); for(int i = 0; i < NO_OF_HOLES; i++) cin >> stone[i]; long long maximum_score = 0; for(int i = 0; i < NO_OF_HOLES; i++) maximum_score = max(maximum_score, score_by_distributing(i, stone, NO_OF_HOLES)); cout << maximum_score; return 0; } ================================================ FILE: Contests/Div 2 478/Programs/Valhalla Siege.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_soldiers, no_of_queries; scanf("%d %d", &no_of_soldiers, &no_of_queries); vector strength(no_of_soldiers + 1); for(int i = 1; i <= no_of_soldiers; i++) scanf("%I64d", &strength[i]); vector sum(no_of_soldiers + 1, 0); for(int i = 1; i <= no_of_soldiers; i++) sum[i] = sum[i - 1] + strength[i]; long long total_arrows = 0; while(no_of_queries--) { long long arrows; scanf("%I64d", &arrows); total_arrows += arrows; if(total_arrows >= sum[no_of_soldiers]) total_arrows = 0; int no_of_dead_soldiers = upper_bound(all(sum), total_arrows) - sum.begin() - 1; int no_of_alive_soldiers = no_of_soldiers - no_of_dead_soldiers; printf("%d\n", no_of_alive_soldiers); } return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/AND Graph Explanation.txt ================================================ Blog Link - http://qr.ae/TUT6oy Basically,X&Y = 0, if Y is any submask of X's complement. So perform DFS. Start from X From X visit all of the submasks of the complement of Y. Mark N visited if you have visited all of it's submasks. If any of the submasks are also present in the array, then visit all the submasks of it's complement as well ! Do this recursively till all integers which can be reached starting from X (in the same component). ------------------------------------------ void dfs(int mask, int no_of_bits) { if(visited[mask]) return; visited[mask] = true; for(int bit = 0; bit < no_of_bits; bit++) { if(mask&(1LL << bit)) { int submask = mask - (1LL << bit); dfs(submask, no_of_bits); } } if(is_present[mask]) dfs(complement(mask, no_of_bits), no_of_bits); } int main() { int no_of_bits, no_of_vertices; scanf("%d %d", &no_of_bits, &no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { int x; scanf("%d", &x); is_present[x] = true; } int no_of_components = 0; for(int i = 0; i < (1LL << no_of_bits); i++) { if(is_present[i] && !visited[i]) { dfs(complement(i, no_of_bits), no_of_bits); no_of_components++; } } printf("%d\n", no_of_components); return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/Fair Explanation.txt ================================================ The number of colours k is quite small (at most 100). For each colour, remember which vertices have that colour. Then push all those vertices into a queue, and perform BFS and calculate the minimum distance of that colour for all vertices. (You can't necessarily perform DFS as it is a general graph and not always a tree.) Then for each vertex you will have the minimum distance to each of the k colours. Sort them and find the sum of the smallest s of them. Complexity = O(k(m + n) + k log k) ----------------------------------------------- int main() { int n; scanf("%d", &n); vector permutation(n + 1); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); int no_of_swaps = 0; vector visited(n + 1, false); for(int i = 1; i <= n; i++) { if(!visited[i]) { int cycle_size = 0; for(int current = i; !visited[current]; current = permutation[current]) { visited[current] = true; cycle_size++; } no_of_swaps += cycle_size - 1; } } printf(no_of_swaps%2 == (3*n)%2 ? "Petr" : "Um_nik"); return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/High Schooll Become Human Explanation.txt ================================================ Blog Link - http://qr.ae/TUTQHH You can either compare the logarithms. Or, if x^y > y^x, then y log x > x log y (log x)/x > (log y)/y Now, (log x)/x has a derivative of (1 - log x)/x^2 The derivative = 0, at x = e Derivative < 0, x > e, which means it is a monotonically decreasing function when x > e If x, y > e And x < y Then, (log x)/x > (log y)/y x^y > y^x ---------------------- Also, x^y = y^x, whenever x = y, and x = 2, y = 4 The remaining cases can be handled by hand. ------------------------------------------------------ int main() { long long x, y; scanf("%I64d %I64d", &x, &y); if(x == y || (min(x, y) == 2 && max(x, y) == 4)) { printf("="); } else if(min(x, y) == 1) { printf(x == 1 ? "<" : ">"); } else if(min(x, y) == 2) { if(x == 2) { printf(y < 4 ? "<" : ">"); } else if(y == 2) { printf(x < 4? ">" : "<"); } } else if(min(x, y) >= 3) //Both greater than e { printf(x < y ? ">" : "<"); } return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/Infinity Gauntlet Explanation.txt ================================================ Have a map of all the colours and their powers. And then have a map of which colours have been used. If a colour has not been used, then display it. ------------------------------------- int main() { map power; power["red"] = "Reality"; power["purple"] = "Power"; power["green"] = "Time"; power["yellow"] = "Mind"; power["orange"] = "Soul"; power["blue"] = "Space"; map present; int no_of_names; cin >> no_of_names; while(no_of_names--) { string colour; cin >> colour; present[colour] = true; } vector answer; for(map :: iterator it = power.begin(); it != power.end(); it++) { if(!present[it->first]) answer.push_back(it->second); } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) cout << answer[i] << "\n"; return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/Petr and Permutations Explanation.txt ================================================ Blog Link - http://qr.ae/TUTLha Basically, notice that 3n and 7n + 1 have different parities ! Find the parity of the number of inversions of the permutation and match it with whichever number of operations has the same parity. ------------------------------------- int main() { int n; scanf("%d", &n); vector permutation(n + 1); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); int no_of_swaps = 0; vector visited(n + 1, false); for(int i = 1; i <= n; i++) { if(!visited[i]) { int cycle_size = 0; for(int current = i; !visited[current]; current = permutation[current]) { visited[current] = true; cycle_size++; } no_of_swaps += cycle_size - 1; } } printf(no_of_swaps%2 == (3*n)%2 ? "Petr" : "Um_nik"); return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/Three Displays Explanation.txt ================================================ This is the O(n^2) solution. Iterate over all possible middle elements. If A[i] is the middle element, then go from (i + 1) to N. Check if S[r] > A[i], if yes then best right[i] = min{best right[i], C[r]} Do the same thing towards the left as well. Best cost = min{Best cost, best left[i] + A[i] + best right[i]} We perform an O(n) scan for every possible mid element. Hence, O(n^2) ---------------------------------------------------- int main() { int no_of_displays; scanf("%d", &no_of_displays); vector text_size(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &text_size[i]); vector cost(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &cost[i]); const long long oo = 1e10; vector best_left(no_of_displays + 1, oo); vector best_right(no_of_displays + 1, oo); long long best_cost = oo; for(int mid = 1; mid <= no_of_displays; mid++) { for(int right = mid + 1; right <= no_of_displays; right++) { if(text_size[mid] < text_size[right]) best_right[mid] = min(best_right[mid], cost[right]); } for(int left = 1; left < mid; left++) { if(text_size[left] < text_size[mid]) best_left[mid] = min(best_left[mid], cost[left]); } best_cost = min(best_cost, best_right[mid] + cost[mid] + best_left[mid]); } printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: Contests/Div 2 485/Explanations/Three Displays Segment Tree Solution Explanation.txt ================================================ This is actually a beautiful technique. There are plenty of problems where segment trees can make O(n^2) to O(n log n). Here's what we do. While processing element i, ensure that we have already processed all elements which have a smaller font size. Now find the minimum cost in the range [1, Position(i) - 1]. (To avoid a clash, ensure that you have not processed elements which have equal font size but who's positions lie to the left of Position(i) because we should not be considering their cost.) So, we sort by font size, If font size is equal, then the rightmost element comes first. One by one, we insert the costs into segment tree at Position(i). And then query the minimum in [1, Position(i) - 1]. As we have ensured rightmost element comes first for equal font sizes, elements with equal font size to the left of an element will not effect it's query as it's not been inserted yet. While finding the best right, we do the opposite. We insert elements in the reverse order that we did for the left and then find the minimum in the range [Position(i) + 1, N]. --------------------------------------------- int main() { int no_of_displays; scanf("%d", &no_of_displays); vector A(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) A[i].position = i; for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].font_size); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].cost); sort(A.begin() + 1, A.end(), compare_by_size); build_min_tree(1, 1, no_of_displays); vector best_left(no_of_displays + 1, oo); for(int i = 1; i <= no_of_displays; i++) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_left[i] = get_min(1, 1, no_of_displays, 1, A[i].position - 1); } build_min_tree(1, 1, no_of_displays); vector best_right(no_of_displays + 1, oo); for(int i = no_of_displays; i >= 1; i--) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_right[i] = get_min(1, 1, no_of_displays, A[i].position + 1, no_of_displays); } long long best_cost = oo; for(int i = 1; i <= no_of_displays; i++) best_cost = min(best_cost, best_left[i] + A[i].cost + best_right[i]); printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: Contests/Div 2 485/Programs/AND Graph.cpp ================================================ #include #include using namespace std; const int MAX_N = (1LL << 22); vector visited(MAX_N, false); vector is_present(MAX_N, false); int complement(int x, int no_of_bits) { return ( ( (1LL << no_of_bits) - 1) - x); } void dfs(int mask, int no_of_bits) { if(visited[mask]) return; visited[mask] = true; for(int bit = 0; bit < no_of_bits; bit++) { if(mask&(1LL << bit)) { int submask = mask - (1LL << bit); dfs(submask, no_of_bits); } } if(is_present[mask]) dfs(complement(mask, no_of_bits), no_of_bits); } int main() { int no_of_bits, no_of_vertices; scanf("%d %d", &no_of_bits, &no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { int x; scanf("%d", &x); is_present[x] = true; } int no_of_components = 0; for(int i = 0; i < (1LL << no_of_bits); i++) { if(is_present[i] && !visited[i]) { dfs(complement(i, no_of_bits), no_of_bits); no_of_components++; } } printf("%d\n", no_of_components); return 0; } ================================================ FILE: Contests/Div 2 485/Programs/Fair.cpp ================================================ #include #include #include #include #define all(v) (v).begin(). (v).end() using namespace std; const int MAX_N = 1e5 + 15, MAX_COLOURS = 105, oo = 1e9; vector graph[MAX_N]; vector has_colour[MAX_COLOURS]; int answer[MAX_N][MAX_COLOURS]; int main() { int no_of_vertices, no_of_edges, no_of_colours, required_colours; scanf("%d %d %d %d", &no_of_vertices, &no_of_edges, &no_of_colours, &required_colours); vector colour(no_of_vertices + 1); for(int i = 1; i <= no_of_vertices; i++) { scanf("%d", &colour[i]); has_colour[colour[i]].push_back(i); } for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } for(int c = 1; c <= no_of_colours; c++) { queue Q; vector distance(no_of_vertices + 1, oo); for(int i = 0; i < has_colour[c].size(); i++) { int v = has_colour[c][i]; distance[v] = 0; Q.push(v); } while(!Q.empty()) { int v = Q.front(); Q.pop(); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(distance[child] > distance[v] + 1) { distance[child] = distance[v] + 1; Q.push(child); } } } for(int v = 1; v <= no_of_vertices; v++) { answer[v][c] = distance[v]; } } for(int v = 1; v <= no_of_vertices; v++) { sort(answer[v] + 1, answer[v] + no_of_colours + 1); long long cost = 0; for(int c = 1; c <= required_colours; c++) cost += answer[v][c]; printf("%I64d ", cost); } return 0; } ================================================ FILE: Contests/Div 2 485/Programs/High School Become Human.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) int main() { long long x, y; scanf("%I64d %I64d", &x, &y); if(x == y || (min(x, y) == 2 && max(x, y) == 4)) { printf("="); } else if(min(x, y) == 1) { printf(x == 1 ? "<" : ">"); } else if(min(x, y) == 2) { if(x == 2) { printf(y < 4 ? "<" : ">"); } else if(y == 2) { printf(x < 4? ">" : "<"); } } else if(min(x, y) >= 3) //Both greater than e { printf(x < y ? ">" : "<"); } return 0; } ================================================ FILE: Contests/Div 2 485/Programs/Infinity Gauntlet.cpp ================================================ #include #include #include using namespace std; int main() { map power; power["red"] = "Reality"; power["purple"] = "Power"; power["green"] = "Time"; power["yellow"] = "Mind"; power["orange"] = "Soul"; power["blue"] = "Space"; map present; int no_of_names; cin >> no_of_names; while(no_of_names--) { string colour; cin >> colour; present[colour] = true; } vector answer; for(map :: iterator it = power.begin(); it != power.end(); it++) { if(!present[it->first]) answer.push_back(it->second); } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) cout << answer[i] << "\n"; return 0; } ================================================ FILE: Contests/Div 2 485/Programs/Petr and Permutations.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); vector permutation(n + 1); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); int no_of_swaps = 0; vector visited(n + 1, false); for(int i = 1; i <= n; i++) { if(!visited[i]) { int cycle_size = 0; for(int current = i; !visited[current]; current = permutation[current]) { visited[current] = true; cycle_size++; } no_of_swaps += cycle_size - 1; } } printf(no_of_swaps%2 == (3*n)%2 ? "Petr" : "Um_nik"); return 0; } ================================================ FILE: Contests/Div 2 485/Programs/Three Displays Segment Tree Solution.cpp ================================================ #include #include #include using namespace std; #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) const int MAX_N = 3015; const long long oo = 1e10; struct info { int font_size, cost, position; }; long long min_tree[4*MAX_N]; long long max_tree[4*MAX_N]; int compare_by_size(const info &A, const info &B) { if(A.font_size == B.font_size) return (A.position > B.position); else return (A.font_size < B.font_size); } void build_min_tree(int n, int left, int right) { if(left == right) { min_tree[n] = oo; return; } int mid = (left + right) >> 1; build_min_tree(LEFT(n), left, mid); build_min_tree(RIGHT(n), mid + 1, right); min_tree[n] = min(min_tree[LEFT(n)], min_tree[RIGHT(n)]); } void update_min(int n, int left, int right, int position, int value) { if(position < left || right < position) return; if(left == right) { min_tree[n] = value; return; } int mid = (left + right) >> 1; update_min(LEFT(n), left, mid, position, value); update_min(RIGHT(n), mid + 1, right, position, value); min_tree[n] = min(min_tree[LEFT(n)], min_tree[RIGHT(n)]); } long long get_min(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || query_right < query_left) return oo; if(query_left <= left && right <= query_right) return min_tree[n]; int mid = (left + right) >> 1; long long left_min = get_min(LEFT(n), left, mid, query_left, query_right); long long right_min = get_min(RIGHT(n), mid + 1, right, query_left, query_right); return min(left_min, right_min); } int main() { int no_of_displays; scanf("%d", &no_of_displays); vector A(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) A[i].position = i; for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].font_size); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].cost); sort(A.begin() + 1, A.end(), compare_by_size); build_min_tree(1, 1, no_of_displays); vector best_left(no_of_displays + 1, oo); for(int i = 1; i <= no_of_displays; i++) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_left[i] = get_min(1, 1, no_of_displays, 1, A[i].position - 1); } build_min_tree(1, 1, no_of_displays); vector best_right(no_of_displays + 1, oo); for(int i = no_of_displays; i >= 1; i--) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_right[i] = get_min(1, 1, no_of_displays, A[i].position + 1, no_of_displays); } long long best_cost = oo; for(int i = 1; i <= no_of_displays; i++) best_cost = min(best_cost, best_left[i] + A[i].cost + best_right[i]); printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: Contests/Div 2 485/Programs/Three Displays.cpp ================================================ #include #include #define min(a, b) (a < b ? a : b) using namespace std; int main() { int no_of_displays; scanf("%d", &no_of_displays); vector text_size(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &text_size[i]); vector cost(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &cost[i]); const long long oo = 1e10; vector best_left(no_of_displays + 1, oo); vector best_right(no_of_displays + 1, oo); long long best_cost = oo; for(int mid = 1; mid <= no_of_displays; mid++) { for(int right = mid + 1; right <= no_of_displays; right++) { if(text_size[mid] < text_size[right]) best_right[mid] = min(best_right[mid], cost[right]); } for(int left = 1; left < mid; left++) { if(text_size[left] < text_size[mid]) best_left[mid] = min(best_left[mid], cost[left]); } best_cost = min(best_cost, best_right[mid] + cost[mid] + best_left[mid]); } printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: Contests/Div 2 489/Explanations/Nastya Studies Informatics Explanation.txt ================================================ Let A = pg and B = qg g = gcd(A, B) This means gcd(p, q) = 1. Otherwise, gcd(A, B) > g. Now, AB = gL, where L = lcm(A, B) AB = g (pq)g So, this means that x = g, y = (pq) g Divide LCM by GCD ... This gives us pq. Find all factors of pq, and then check if gcd(p, q) = 1, and pg and qg lie inside [L, R]. One thing to watch out for is that y may not be divisible by x, in which case we have gotten an invalid pair. ------------------------------------------------ int good_pairs = 0; long long reduced_lcm = lcm/gcd; for(int i = 1; i*i <= reduced_lcm; i++) { if(reduced_lcm%i == 0) { long long p = i, q = reduced_lcm/i; if(left <= p*gcd && p*gcd <= right && left <= q*gcd && q*gcd <= right && gcd_(p, q) == 1) { if(p == q) good_pairs++; else good_pairs += 2; } } } ================================================ FILE: Contests/Div 2 489/Explanations/Nastya and Game Explanation.txt ================================================ Blog Link - http://qr.ae/TUpezI If there were no ones then it would be easy to have an O(n log max P) solution with two loops. Handle the ones well. ------------- int good_segments = 0; for(int left = 1; left <= no_of_elements; left++) { LL product = 1; for(int right = left; right <= no_of_elements && !overflow(product, A[right]); right = next_non_1[right]) { LL sum_here = sum[right] - sum[left - 1]; product *= A[right]; LL required_sum = 0; if(product%k == 0) required_sum = product/k; LL ones_in_middle = next_non_1[right] - (right + 1); if(sum_here <= required_sum && required_sum <= sum_here + ones_in_middle) good_segments++; } } ================================================ FILE: Contests/Div 2 489/Explanations/Nastya and King Shamans Alternate Solution Explanation.txt ================================================ Blog Link - http://qr.ae/TUpilr Place integers which have the same number of bits in the same bucket. Sort the bucket by index. Only the first two integers of the bucket can have A[i] = S{i - 1] This is because every other integer from the third onwards will have both the first two integers in it's prefix. And when you add two numbers of b bits, the sum has more than b bits. Therefore the number will necessarily be < S[i - 1], if there are more than 2 or more numbers of the same number of bits in it's prefix. Maintain a priority queue to sort numbers by index for each bit position and a segment tree to get the sums after every update. ------------------------------------------ int get_answer() { for(int bit = 0; bit < MAX_BITS; bit++) //Iterating over the priority queue for each no of bits { int i = 1; for(multiset :: iterator it = S[bit].begin(); it != S[bit].end() && i <= 2; i++, it++)//The first two elements, by index { int index = it->position; if(get_sum(1, 1, no_of_elements, 1, index - 1) == A[index]) return index; } } return NOT_FOUND; } void solve() { int index, new_value; scanf("%d %d", &index, &new_value); info element(A[index], index); remove_from_multiset(element, no_of_bits(A[index])); S[no_of_bits(new_value)].insert(info(new_value, index)); update(1, 1, no_of_elements, index, new_value); int answer = get_answer(); printf("%d\n", answer); } ================================================ FILE: Contests/Div 2 489/Explanations/Nastya and King Shamans Explanation.txt ================================================ Blog Link - http://qr.ae/TUp5G8 The basic idea is that if A[i] = S[i - 1], we are done. Else look for the first index i' > i, such that A[i] >= S[i]. All j, in between, A[j] < S[i] So A[j] < S[j - 1]. The sum doubles at every step. S[i'] >= A[i'] + S[i] >= S[i] + S[i] >= 2S[i]. So, in the given range you will perform at most 32 steps. --------------------------------------- int first_index(int n, int left, int right, int query_left, int query_right, LL minimum) { if(right < query_left || query_right < left || max_tree[n] < minimum) return NOT_FOUND; if(left == right) return left; int mid = (left + right) >> 1; int left_answer = first_index(LEFT(n), left, mid, query_left, query_right, minimum); if(left_answer != NOT_FOUND) return left_answer; int right_answer = first_index(RIGHT(n), mid + 1, right, query_left, query_right, minimum); return right_answer; } You'll perform O(log max A) such iterations. ---------------------------------------------------------- How do you find the smallest index j in [i + 1, N] with minimum value S ? Maintain a maximum segment tree, reject an interval if it is outside [i + 1, N] or the max < S. int first_index(int n, int left, int right, int query_left, int query_right, LL minimum) { if(right < query_left || query_right < left || max_tree[n] < minimum) return NOT_FOUND; if(left == right) return left; int mid = (left + right) >> 1; int left_answer = first_index(LEFT(n), left, mid, query_left, query_right, minimum); if(left_answer != NOT_FOUND) return left_answer; int right_answer = first_index(RIGHT(n), mid + 1, right, query_left, query_right, minimum); return right_answer; } ----------------------------------------------- ================================================ FILE: Contests/Div 2 489/Explanations/Nastya and a Wardrobe Explanation.txt ================================================ Claim - After two months the expected value will be 2^k x - (2^k - 1)/2 Let us see why. After one month, we will get 2X or 2X - 1. Average = 2x - 1/2 Similarly, when this gets doubled we'll have 4x - 1, One may be eaten so 4x - 2 Average = 4x - 3/2 Let us assume it's true for k months and prove it by induction. If after k months we have 2^k X - (2^K - 1)/2 What happens in the (k + 1)th month 2^{k + 1) X - (2^k - 1) If one gets eaten then 2^{k + 1} X - (2^k) So average = 2^{k + 1} X - (2^k + 2^k)/2 = 2^{k + 1} X - (2^{k + 1} - 1)/2 So no eating happens in the last month. So we can get rid of the denominator. Note - x = 0 is a special case. I missed this. This is because nothing gets eaten. So, it will be 0 only. Not negative ! ----------------------------------------------------- int main() { long long initial, months; scanf("%I64d %I64d", &initial, &months); if(initial == 0) { printf("0\n"); return 0; } const int MOD = 1e9 + 7; initial %= MOD; long long answer = (initial*power_mod(2, months + 1, MOD))%MOD - power_mod(2, months, MOD) + 1; answer = (answer + MOD)%MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 489/Explanations/Nastya and an Array Explanation.txt ================================================ Count the number of distinct non zero elements. #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; set S; while(no_of_elements--) { int element; cin >> element; if(element != 0) S.insert(element); } cout << S.size(); return 0; } ================================================ FILE: Contests/Div 2 489/Programs/Nastya Studies Informatics.cpp ================================================ #include #include #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; long long gcd_(long long p, long long q) { if(min(p, q) == 0) return max(p, q); else return gcd_(min(p, q), max(p, q)%min(p, q)); } int main() { long long left, right, gcd, lcm; scanf("%I64d %I64d %I64d %I64d", &left, &right, &gcd, &lcm); //search for pg, qg, where pq = l/g int good_pairs = 0; long long reduced_lcm = lcm/gcd; for(int i = 1; i*i <= reduced_lcm; i++) { if(reduced_lcm%i == 0) { long long p = i, q = reduced_lcm/i; if(left <= p*gcd && p*gcd <= right && left <= q*gcd && q*gcd <= right && gcd_(p, q) == 1) { //printf("p = %d, q = %d\n", p, q); if(p == q) good_pairs++; else good_pairs += 2; } } } printf("%d\n", good_pairs); return 0; } ================================================ FILE: Contests/Div 2 489/Programs/Nastya and Game.cpp ================================================ #include #include #include using namespace std; typedef long long LL; int overflow(LL a, LL b) { return ( ((a*b)/b) != a); } int main() { int no_of_elements, k; scanf("%d %d", &no_of_elements, &k); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); vector sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) sum[i] = sum[i - 1] + A[i]; vector next_non_1(no_of_elements + 1); next_non_1[no_of_elements] = no_of_elements + 1; for(int i = no_of_elements - 1; i >= 1; i--) next_non_1[i] = (A[i + 1] != 1 ? i + 1 : next_non_1[i + 1]); int good_segments = 0; for(int left = 1; left <= no_of_elements; left++) { LL product = 1; for(int right = left; right <= no_of_elements && !overflow(product, A[right]); right = next_non_1[right]) { LL sum_here = sum[right] - sum[left - 1]; product *= A[right]; LL required_sum = 0; if(product%k == 0) required_sum = product/k; LL ones_in_middle = next_non_1[right] - (right + 1); if(sum_here <= required_sum && required_sum <= sum_here + ones_in_middle) good_segments++; } } printf("%d\n", good_segments); return 0; } ================================================ FILE: Contests/Div 2 489/Programs/Nastya and King-Shamans Alternate Solution.cpp ================================================ #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) struct info { int value, position; info(int v = 0, int p = 0) { value = v; position = p; } int operator<(const info &A) const { return (position < A.position); } }; using namespace std; typedef long long LL; const int MAX_N = 2e5 + 5, NOT_FOUND = -1, MAX_BITS = 32; LL sum_tree[3*MAX_N], A[MAX_N]; multiset S[MAX_BITS]; int no_of_elements; void build(int n, int left, int right) { if(left == right) { sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } void update(int n, int left, int right, int index, int new_value) { if(right < index || index < left) return; if(left == right) { A[index] = new_value; sum_tree[n] = new_value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, index, new_value); update(RIGHT(n), mid + 1, right, index, new_value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } LL get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; LL left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); LL right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } int no_of_bits(int n) { int bits = 0; while(n > 0) { n = n >> 1; bits++; } return bits; } int get_answer() { for(int bit = 0; bit < MAX_BITS; bit++) //Iterating over the priority queue for each no of bits { int i = 1; for(multiset :: iterator it = S[bit].begin(); it != S[bit].end() && i <= 2; i++, it++)//The first two elements, by index { int index = it->position; if(get_sum(1, 1, no_of_elements, 1, index - 1) == A[index]) return index; } } return NOT_FOUND; } void remove_from_multiset(info element, int multiset_no) { multiset :: iterator it = S[multiset_no].find(element); if(it != S[multiset_no].end()) S[multiset_no].erase(it); } void solve() { int index, new_value; scanf("%d %d", &index, &new_value); info element(A[index], index); remove_from_multiset(element, no_of_bits(A[index])); S[no_of_bits(new_value)].insert(info(new_value, index)); update(1, 1, no_of_elements, index, new_value); int answer = get_answer(); printf("%d\n", answer); } int main() { int no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); S[no_of_bits(A[i])].insert(info(A[i], i)); } build(1, 1, no_of_elements); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 2 489/Programs/Nastya and King-Shamans.cpp ================================================ #include #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; typedef long long LL; const int MAX_N = 2e5 + 5, NOT_FOUND = -1; LL max_tree[4*MAX_N], sum_tree[4*MAX_N], A[MAX_N]; int no_of_elements; void build(int n, int left, int right) { if(left == right) { max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } void update(int n, int left, int right, int index, int new_value) { if(right < index || index < left) return; if(left == right) { A[index] = new_value; sum_tree[n] = max_tree[n] = new_value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, index, new_value); update(RIGHT(n), mid + 1, right, index, new_value); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } LL get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; LL left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); LL right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } int first_index(int n, int left, int right, int query_left, int query_right, LL minimum) { if(right < query_left || query_right < left || max_tree[n] < minimum) return NOT_FOUND; if(left == right) return left; int mid = (left + right) >> 1; int left_answer = first_index(LEFT(n), left, mid, query_left, query_right, minimum); if(left_answer != NOT_FOUND) return left_answer; int right_answer = first_index(RIGHT(n), mid + 1, right, query_left, query_right, minimum); return right_answer; } int get_answer() { LL prefix_sum; int index = 1; while(index != NOT_FOUND) { prefix_sum = get_sum(1, 1, no_of_elements, 1, index - 1); if(prefix_sum == A[index]) return index; prefix_sum += A[index]; index = first_index(1, 1, no_of_elements, index + 1, no_of_elements, prefix_sum); } return index; } void solve() { int index, new_value; scanf("%d %d", &index, &new_value); update(1, 1, no_of_elements, index, new_value); int answer = get_answer(); printf("%d\n", answer); } int main() { int no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); build(1, 1, no_of_elements); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 2 489/Programs/Nastya and a Wardrobe.cpp ================================================ #include typedef long long LL; LL power_mod(LL x, LL power, LL MOD) { LL result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } int main() { long long initial, months; scanf("%I64d %I64d", &initial, &months); if(initial == 0) { printf("0\n"); return 0; } const int MOD = 1e9 + 7; initial %= MOD; long long answer = (initial*power_mod(2, months + 1, MOD))%MOD - power_mod(2, months, MOD) + 1; answer = (answer + MOD)%MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 489/Programs/Nastya and an Array.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; set S; while(no_of_elements--) { int element; cin >> element; if(element != 0) S.insert(element); } cout << S.size(); return 0; } ================================================ FILE: Contests/Div 2 491/Explanations/Bishwock Explanation.txt ================================================ We can be greedy. It is never optimal to leave a column blank if a biscwok fits. --------------------------------- int main() { const int NO_OF_ROWS = 2; vector S(NO_OF_ROWS); for(int i = 0; i < NO_OF_ROWS; i++) cin >> S[i]; int no_of_columns = S[0].size(); int free_spaces = 0, placed_pieces = 0; for(int i = 0; i < no_of_columns; i++) { int column_spaces = (S[0][i] == '0') + (S[1][i] == '0'); free_spaces += column_spaces; if(free_spaces >= 3) { free_spaces -=3; placed_pieces++; } else { free_spaces = column_spaces; } } cout << placed_pieces; return 0; } ================================================ FILE: Contests/Div 2 491/Explanations/Bus Number Explanation.txt ================================================ If there are 3 different objects of frequency r1 r2 and r3 respectively. Then the number of arrangements of all of them is (r1 + r2 + r3)!/r1!r2!r3! ----------------------------------- One possible way is to have 10 for loops, and then make sure the frequency of each alphabet in S is at least one ... ------------------------------------- Another way is 1. Extract every possible subset of N. Suppose it's 2820.... This part we'll take all subsets out - {2, 8, 0, 280, 80, 220, etc} for(int mask = 0; mask < (1LL << n.size()); mask++) { string subset_n; for(int i = 0; i < n.size(); i++) { if(is_bit_set(mask, i)) { subset_n += n[i]; } } answer += solve(subset_n); } ------------------------------------------------- 2. For every subset, check if every element that occurs once in the set, also occurs at least once in this subset. For example {80} is not a legal subset because it doesn't have a 2. for(int i = 0; i < 10; i++) if(original_frequency[i] > 0 && frequency[i] == 0) return 0; ------------------------------------- 3. Check if we've processed a subset before. For instace, 450 and 054 are the same subset. So sort the elements of a subset. Check if it's already been processed. (Suppose we have counted permutations of 280, we don't need to count permutations 820. As we'd be overcounting. So map both 280 and 820 to 028) string sorted_S; for(int i = 0; i < 10; i++) for(int j = 1; j <= frequency[i]; j++) sorted_S += (char)(i + '0'); if(processed.count(sorted_S) == 1)//Already counted return 0; processed.insert(sorted_S); ------------------------------------------------- 4. Count the number of permutations of this string. Then, count the number of permutations with the first character 0. This means put a 0 in the beginning and then leave the others as it is. (Put a 0 at the first character and count the permutations of the remaining n - 1 elements) long long no_of_permutations = get_count(frequency); long long leading_zero_permutations = 0; if(frequency[0] > 0) { frequency[0]--; leading_zero_permutations = get_count(frequency); } return (no_of_permutations - leading_zero_permutations); --------------------------------------------- 5. Only frequency array is needed to calculate the permutations. (This is how we get the (r1 + r2 + r3)!/r1!r2!r3! long long get_count(vector &frequency) { int sum = 0; long long denominator = 1; for(int i = 0; i < 10; i++) { sum += frequency[i]; denominator *= factorial[frequency[i]]; } long long numerator = factorial[sum]; return (numerator/denominator); } ================================================ FILE: Contests/Div 2 491/Explanations/Candies Explanation.txt ================================================ Blog Link - http://qr.ae/TUpOLx It's a binary search problem ! --------------------------------------- #include #include #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; LL taken_candies(LL total_candies, LL k) { LL self_candies = 0; while(total_candies > 0) { self_candies += min(k, total_candies); total_candies = total_candies - k; LL lost_candies = total_candies/10; total_candies -= lost_candies; } return self_candies; } int main() { LL no_of_candies; scanf("%I64d", &no_of_candies); LL target_candies = no_of_candies/2 + no_of_candies%2; LL left = 1, right = no_of_candies, answer = 1; while(left <= right) { LL mid = (left + right) >> 1; if(taken_candies(no_of_candies, mid) >= target_candies) { if(mid == 1 || taken_candies(no_of_candies, mid - 1) < target_candies) { answer = mid; break; } else { right = mid - 1; } } else { left = mid + 1; } } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 491/Explanations/Getting an A Explanation.txt ================================================ Avoid floating point operations. Rather than make the average 4.5 Make the 10*sum >= 45*n Rather than deal with [2, 5], deal with [20, 50]. Multiply everything by 10 ! This is a very handy trick to get rid of floating point operations ! Now, notice that we want the sum to increase as much as possible each time, so we start from the lowest score and greedily make them 50 at each step. ----------------------------------- int main() { int no_of_exams; scanf("%d", &no_of_exams); vector grade(no_of_exams); for(int i = 0; i < no_of_exams; i++) scanf("%d", &grade[i]); sort(all(grade)); int sum = 0; for(int i = 0; i < no_of_exams; i++) { grade[i] *= 10; sum += grade[i]; } int no_of_changes = 0, target = 45; //Rather than 4.5, we aim for 45. for(int i = 0; sum < target*no_of_exams && i < no_of_exams; i++) { sum += (50 - grade[i]); //Make grade[i] = 50 no_of_changes++; } printf("%d\n", no_of_changes); return 0; } ================================================ FILE: Contests/Div 2 491/Explanations/If At First You Don't Succeed Explanation.txt ================================================ OKay, so the conditions that contradict the data is if C > min(A, B). The number of students who go to both A and B cannot be less than the students who go to both. I missed this. and if failed < 1. No need of explicitly checking if A + B - C > 0, because that would cause failed to become < 1 anyway. (If there are a negative number of students, there are a negative number of failed students too.) ----------------------------------------------- int main() { int A, B, C, total_students; cin >> A >> B >> C >> total_students; int passed = (A + B - C); int failed = total_students - passed; cout << (failed < 1 || C > min(A, B) ? -1 : failed); return 0; } ================================================ FILE: Contests/Div 2 491/Programs/Bishwock.cpp ================================================ #include #include #include using namespace std; int main() { const int NO_OF_ROWS = 2; vector S(NO_OF_ROWS); for(int i = 0; i < NO_OF_ROWS; i++) cin >> S[i]; int no_of_columns = S[0].size(); int free_spaces = 0, placed_pieces = 0; for(int i = 0; i < no_of_columns; i++) { int column_spaces = (S[0][i] == '0') + (S[1][i] == '0'); free_spaces += column_spaces; if(free_spaces >= 3) { free_spaces -=3; placed_pieces++; } else { free_spaces = column_spaces; } } cout << placed_pieces; return 0; } ================================================ FILE: Contests/Div 2 491/Programs/Bus Number.cpp ================================================ #include #include #include #include using namespace std; vector original_frequency(10, 0); vector factorial(20, 1); set processed; int is_bit_set(int n, int position) { return ( (n&(1LL << position)) != 0); } void precompute() { factorial[0] = 1; for(int i = 1; i < 20; i++) factorial[i] = i*factorial[i - 1]; } void get(string S, vector &frequency) { for(int i = 0; i < S.size(); i++) { frequency[S[i] - '0']++; } } long long get_count(vector &frequency) { int sum = 0; long long denominator = 1; for(int i = 0; i < 10; i++) { sum += frequency[i]; denominator *= factorial[frequency[i]]; } long long numerator = factorial[sum]; return (numerator/denominator); } long long solve(string S) { vector frequency(10, 0); get(S, frequency); //Not a good string. for(int i = 0; i < 10; i++) if(original_frequency[i] > 0 && frequency[i] == 0) return 0; string sorted_S; for(int i = 0; i < 10; i++) for(int j = 1; j <= frequency[i]; j++) sorted_S += (char)(i + '0'); if(processed.count(sorted_S) == 1)//Already counted return 0; processed.insert(sorted_S); long long no_of_permutations = get_count(frequency); long long leading_zero_permutations = 0; if(frequency[0] > 0) { frequency[0]--; leading_zero_permutations = get_count(frequency); } return (no_of_permutations - leading_zero_permutations); } int main() { precompute(); string n; cin >> n; get(n, original_frequency); long long answer = 0; for(int mask = 0; mask < (1LL << n.size()); mask++) { string subset_n; for(int i = 0; i < n.size(); i++) { if(is_bit_set(mask, i)) { subset_n += n[i]; } } answer += solve(subset_n); } cout << answer; return 0; } ================================================ FILE: Contests/Div 2 491/Programs/Candies.cpp ================================================ #include #include #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; LL taken_candies(LL total_candies, LL k) { LL self_candies = 0; while(total_candies > 0) { self_candies += min(k, total_candies); total_candies = total_candies - k; LL lost_candies = total_candies/10; total_candies -= lost_candies; } return self_candies; } int main() { LL no_of_candies; scanf("%I64d", &no_of_candies); LL target_candies = no_of_candies/2 + no_of_candies%2; LL left = 1, right = no_of_candies, answer = 1; while(left <= right) { LL mid = (left + right) >> 1; if(taken_candies(no_of_candies, mid) >= target_candies) { if(mid == 1 || taken_candies(no_of_candies, mid - 1) < target_candies) { answer = mid; break; } else { right = mid - 1; } } else { left = mid + 1; } } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 491/Programs/Getting an A.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_exams; scanf("%d", &no_of_exams); vector grade(no_of_exams); for(int i = 0; i < no_of_exams; i++) scanf("%d", &grade[i]); sort(all(grade)); int sum = 0; for(int i = 0; i < no_of_exams; i++) { grade[i] *= 10; sum += grade[i]; } int no_of_changes = 0, target = 45; //Rather than 4.5, we aim for 45. for(int i = 0; sum < target*no_of_exams && i < no_of_exams; i++) { sum += (50 - grade[i]); //Make grade[i] = 50 no_of_changes++; } printf("%d\n", no_of_changes); return 0; } ================================================ FILE: Contests/Div 2 491/Programs/If At First You Don't Succeed.cpp ================================================ #include #include #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int A, B, C, total_students; cin >> A >> B >> C >> total_students; int passed = (A + B - C); int failed = total_students - passed; cout << (failed < 1 || C > min(A, B) ? -1 : failed); return 0; } ================================================ FILE: Contests/Div 2 492/Explanation/Game 995 Explanation.txt ================================================ Blog Link - http://qr.ae/TUpe5F Expectation is just the average ! ------------------------------------- int main() { int n, no_of_changes; scanf("%d %d", &n, &no_of_changes); int no_of_elements = (1LL << n); long long sum = 0; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { scanf("%d", &A[i]); sum += A[i]; } double average = (sum*1.0)/no_of_elements; printf("%.12f\n", average); for(int i = 1; i <= no_of_changes; i++) { int position, new_value; scanf("%d %d", &position, &new_value); sum = sum - A[position] + new_value; A[position] = new_value; average = (sum*1.0)/(no_of_elements); printf("%.12f\n", average); } return 0; } ================================================ FILE: Contests/Div 2 492/Explanation/Hit the Lottery Explanation.txt ================================================ Each of 1, 5, 10, 20, 100 is a multiple of the last. So it's always optimal to use a larger denomination when we can. If we don't use a note of value y and use x where y < x, we will k notes where yk = x So it's best to be greedy and use as many high value denominations as possible. --------------------------------- int main() { const int NO_OF_NOTES = 5; int denominations[NO_OF_NOTES + 1] = {100, 20, 10, 5, 1}; int amount; scanf("%d", &amount); int no_of_notes = 0; for(int i = 0; i < NO_OF_NOTES; i++) { if(denominations[i] <= amount) no_of_notes += amount/denominations[i]; amount %= denominations[i]; } printf("%d\n", no_of_notes); return 0; } ================================================ FILE: Contests/Div 2 492/Explanation/Leaving the Bar Explanation.txt ================================================ Blog link - https://mathprogrammer.quora.com/4253883-1?share=4cf393bf&srid=F7Hz Turns out randomly shuffling the vectors and being greedy is a very efficient heuristic ! ------------------------------ do { random_shuffle(all(V)); P = Point(0, 0); for(int i = 0; i < no_of_points; i++) { if(square_norm(P + V[i]) <= square_norm(P - V[i])) { P = P + V[i]; step[V[i].index] = 1; } else { P = P - V[i]; step[V[i].index] = -1; } } } while(square_norm(P) > square(oo)); ================================================ FILE: Contests/Div 2 492/Explanation/Suit and Tie Explanation.txt ================================================ We can be greedy. Go through the array. If A[i] =/= A[i + 1], Find the rightmost occurence of A[i] and keep swapping. Let us prove that this is optimal. now, if a and a are seperated All other pairs, must be of the form aa bb abab a bb a Now in the first kind, our algorithm won't touch it. In the second kind, we need to atleast do one swap. The greedy algorithm does one swap. In the thrid, we need to do at least two, The greedy does two. We see the greedy algorithm does no more swaps than necessary. ------------------------------------- int main() { int no_of_couples; scanf("%d", &no_of_couples); vector A(2*no_of_couples + 1); for(int i = 1; i <= 2*no_of_couples; i++) scanf("%d", &A[i]); int no_of_swaps = 0; for(int i = 1; i <= 2*no_of_couples; i += 2) { for(int j = 2*no_of_couples; j > i + 1; j--) { if(A[j] == A[i]) { swap(A[j], A[j - 1]); no_of_swaps++; } } } printf("%d\n", no_of_swaps); return 0; } ================================================ FILE: Contests/Div 2 492/Explanation/Tesla Explanation.txt ================================================ We will place all cars that we can park in 1 move. Then, we will rotate all the cars 1 step. This problem is solved by brute force. We will try to park all the cars we can which are one move away from their designated spots. Then, we will rotate all the cars by one step and try again. We will perform $2n$ rotations and each rotation costs $2n$ moves. So the total number of moves will be $4n^2 + k \approx 10^5 + 10^2$ We will perform 2n rotations because after that, they will come back to the same place. While rotating the cars, we will begin at some point where we have a free space to move a car. ----- struct Move { int index, row, column; Move(){}; Move(int I, int R, int C) { index = I; row = R; column = C; } }; void park(vector &Moves, int no_of_columns) { for(int column = 1; column <= no_of_columns; column++) { if(parking_lot[2][column] != 0 && parking_lot[2][column] == parking_lot[1][column]) { Moves.push_back(Move(parking_lot[2][column], 1, column)); parking_lot[2][column] = 0; } if(parking_lot[3][column] != 0 && parking_lot[3][column] == parking_lot[4][column]) { Moves.push_back(Move(parking_lot[3][column], 4, column)); parking_lot[3][column] = 0; } } } void rotate(vector &Moves, int no_of_columns) { int start_row = -1, start_column = -1; for(int r = 2; r <= 3 && start_row == -1; r++) { for(int c = 1; c <= no_of_columns; c++) { if(parking_lot[r][c] == 0) { int next_r = r, next_c = c; if(r == 2) { if(c == no_of_columns) { next_c = no_of_columns; next_r = r + 1; } else { next_c = c + 1; } } else if(r == 3) { if(c == 1) { next_c = 1; next_r = r - 1; } else { next_c = c - 1; } } if(parking_lot[next_r][next_c] != 0) { start_row = r; start_column = c; break; } } } } if(start_row == -1 || start_column == -1) { return; } int r = start_row, c = start_column; while(true) { int next_r = r, next_c = c; if(r == 2) { if(c == no_of_columns) { next_c = no_of_columns; next_r = r + 1; } else { next_c = c + 1; } } else if(r == 3) { if(c == 1) { next_c = 1; next_r = r - 1; } else { next_c = c - 1; } } if(next_r == start_row && next_c == start_column) { break; } if(parking_lot[next_r][next_c] != 0) { Moves.push_back(Move(parking_lot[next_r][next_c], r, c)); parking_lot[r][c] = parking_lot[next_r][next_c]; parking_lot[next_r][next_c] = 0; } r = next_r; c = next_c; } } int check_empty(int no_of_columns) { for(int r = 2; r <= 3; r++) { for(int c = 1; c <= no_of_columns; c++) { if(parking_lot[r][c] != 0) { return false; } } } return true; } void print() { cout << "Parking Lot = \n"; for(int i = 1; i <= MAX_ROWS; i++) { for(int j = 1; j <= 4; j++) { cout << parking_lot[i][j] << " "; } cout << "\n"; } } int main() { int no_of_columns, no_of_cars; cin >> no_of_columns >> no_of_cars; for(int i = 1; i <= MAX_ROWS; i++) { for(int j = 1; j <= no_of_columns; j++) { cin >> parking_lot[i][j]; } } vector Moves; for(int rotations = 1; rotations <= 2*no_of_columns; rotations++) { park(Moves, no_of_columns); //print(); rotate(Moves, no_of_columns); //print(); } if(!check_empty(no_of_columns)) { cout << "-1\n"; return 0; } cout << Moves.size() << "\n"; for(int i = 0; i < Moves.size(); i++) { cout << Moves[i].index << " " << Moves[i].row << " " << Moves[i].column << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 492/Explanation/World Cup Explanation.txt ================================================ Blog Link - http://qr.ae/TUGAjY Suppose you have the numbers A(1), A(2), A(3), ..., A(n) What is the length when you visit them in round 1 ? A(1) — 0, A(2) — 1, A(3) — 2, A(4) - 3, ..., A(n) — (n - 1) You visit queue i when it's size = A(i) — (i - 1) in round 1 After that notice if you visit a queue at size t, you also visit it at sizes t - n, t - 2n, t - 3n, ..., 0. Now, how many visits do you make at a queue when it is 0 ? The answer is t / n = (A(i) — (i - 1)) / n So, for each queue calculate the time it will take to reach it and keep track of the minimum. Now, a small trick here is settign every A[i] to max{A[i] - (i - 1), 0}. It should not be negative. Made that mistake the first time. The program will then think it takes 1 round to reach when it actually hits it in the first round itself. ---------------------------------------------------------------------- vector length(no_of_queues + 1); for(int i = 0; i < no_of_queues; i++) scanf("%d", &length[i]); for(int i = 0; i < no_of_queues; i++) length[i] = max(length[i] - i, 0); vector rounds_to_arrive_at(no_of_queues); for(int i = 0; i < no_of_queues; i++) rounds_to_arrive_at[i] = ceil(length[i], no_of_queues); const int oo = 1e9; int best_queue, minimum_rounds = oo; for(int i = 0; i < no_of_queues; i++) if(rounds_to_arrive_at[i] < minimum_rounds) minimum_rounds = rounds_to_arrive_at[i], best_queue = i + 1; printf("%d\n", best_queue); ================================================ FILE: Contests/Div 2 492/Programs/Game 995D.cpp ================================================ #include #include using namespace std; int main() { int n, no_of_changes; scanf("%d %d", &n, &no_of_changes); int no_of_elements = (1LL << n); long long sum = 0; vector A(no_of_elements + 1); for(int i = 0; i < no_of_elements; i++) { scanf("%d", &A[i]); sum += A[i]; } double average = (sum*1.0)/no_of_elements; printf("%.12f\n", average); for(int i = 1; i <= no_of_changes; i++) { int position, new_value; scanf("%d %d", &position, &new_value); sum = sum - A[position] + new_value; A[position] = new_value; average = (sum*1.0)/(no_of_elements); printf("%.12f\n", average); } return 0; } ================================================ FILE: Contests/Div 2 492/Programs/Hit the Lottery.cpp ================================================ #include int main() { const int NO_OF_NOTES = 5; int denominations[NO_OF_NOTES + 1] = {100, 20, 10, 5, 1}; int amount; scanf("%d", &amount); int no_of_notes = 0; for(int i = 0; i < NO_OF_NOTES; i++) { if(denominations[i] <= amount) no_of_notes += amount/denominations[i]; amount %= denominations[i]; } printf("%d\n", no_of_notes); return 0; } ================================================ FILE: Contests/Div 2 492/Programs/Leaving The Bar.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; struct Point { int index; LL x, y; Point(LL a = 0, LL b = 0, int index = 0) { x = a, y = b, index = 0; } Point operator+(const Point &P) { return Point(x + P.x, y + P.y); } Point operator-(const Point &P) { return Point(x - P.x, y - P.y); } }; LL square(LL n) { return n*n; } LL square_norm(Point P) { return (P.x*P.x + P.y*P.y); } int main() { int no_of_points; scanf("%d", &no_of_points); vector V(no_of_points); for(int i = 0; i < no_of_points; i++) { scanf("%I64d %I64d", &V[i].x, &V[i].y); V[i].index = i; } const LL oo = 1.5e6; Point P; vector step(no_of_points); do { random_shuffle(all(V)); P = Point(0, 0); for(int i = 0; i < no_of_points; i++) { if(square_norm(P + V[i]) <= square_norm(P - V[i])) { P = P + V[i]; step[V[i].index] = 1; } else { P = P - V[i]; step[V[i].index] = -1; } } } while(square_norm(P) > square(oo)); for(int i = 0; i < no_of_points; i++) printf("%d ", step[i]); return 0; } ================================================ FILE: Contests/Div 2 492/Programs/Suit and Tie.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_couples; scanf("%d", &no_of_couples); vector A(2*no_of_couples + 1); for(int i = 1; i <= 2*no_of_couples; i++) scanf("%d", &A[i]); int no_of_swaps = 0; for(int i = 1; i <= 2*no_of_couples; i += 2) { for(int j = 2*no_of_couples; j > i + 1; j--) { if(A[j] == A[i]) { swap(A[j], A[j - 1]); no_of_swaps++; } } } printf("%d\n", no_of_swaps); return 0; } ================================================ FILE: Contests/Div 2 492/Programs/Tesla.cpp ================================================ #include #include using namespace std; const int MAX_ROWS = 4, MAX_COLUMNS = 55, MAX_CARS = 101; int parking_lot[MAX_ROWS + 1][MAX_COLUMNS]; struct Move { int index, row, column; Move(){}; Move(int I, int R, int C) { index = I; row = R; column = C; } }; void park(vector &Moves, int no_of_columns) { for(int column = 1; column <= no_of_columns; column++) { if(parking_lot[2][column] != 0 && parking_lot[2][column] == parking_lot[1][column]) { Moves.push_back(Move(parking_lot[2][column], 1, column)); parking_lot[2][column] = 0; } if(parking_lot[3][column] != 0 && parking_lot[3][column] == parking_lot[4][column]) { Moves.push_back(Move(parking_lot[3][column], 4, column)); parking_lot[3][column] = 0; } } } void rotate(vector &Moves, int no_of_columns) { int start_row = -1, start_column = -1; for(int r = 2; r <= 3 && start_row == -1; r++) { for(int c = 1; c <= no_of_columns; c++) { if(parking_lot[r][c] == 0) { int next_r = r, next_c = c; if(r == 2) { if(c == no_of_columns) { next_c = no_of_columns; next_r = r + 1; } else { next_c = c + 1; } } else if(r == 3) { if(c == 1) { next_c = 1; next_r = r - 1; } else { next_c = c - 1; } } if(parking_lot[next_r][next_c] != 0) { start_row = r; start_column = c; break; } } } } if(start_row == -1 || start_column == -1) { return; } int r = start_row, c = start_column; while(true) { int next_r = r, next_c = c; if(r == 2) { if(c == no_of_columns) { next_c = no_of_columns; next_r = r + 1; } else { next_c = c + 1; } } else if(r == 3) { if(c == 1) { next_c = 1; next_r = r - 1; } else { next_c = c - 1; } } if(next_r == start_row && next_c == start_column) { break; } if(parking_lot[next_r][next_c] != 0) { Moves.push_back(Move(parking_lot[next_r][next_c], r, c)); parking_lot[r][c] = parking_lot[next_r][next_c]; parking_lot[next_r][next_c] = 0; } r = next_r; c = next_c; } } int check_empty(int no_of_columns) { for(int r = 2; r <= 3; r++) { for(int c = 1; c <= no_of_columns; c++) { if(parking_lot[r][c] != 0) { return false; } } } return true; } void print() { cout << "Parking Lot = \n"; for(int i = 1; i <= MAX_ROWS; i++) { for(int j = 1; j <= 4; j++) { cout << parking_lot[i][j] << " "; } cout << "\n"; } } int main() { int no_of_columns, no_of_cars; cin >> no_of_columns >> no_of_cars; for(int i = 1; i <= MAX_ROWS; i++) { for(int j = 1; j <= no_of_columns; j++) { cin >> parking_lot[i][j]; } } vector Moves; for(int rotations = 1; rotations <= 2*no_of_columns; rotations++) { park(Moves, no_of_columns); //print(); rotate(Moves, no_of_columns); //print(); } if(!check_empty(no_of_columns)) { cout << "-1\n"; return 0; } cout << Moves.size() << "\n"; for(int i = 0; i < Moves.size(); i++) { cout << Moves[i].index << " " << Moves[i].row << " " << Moves[i].column << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 492/Programs/World Cup.cpp ================================================ #include #include using namespace std; int ceil(int numerator, int denominator) { int quotient = numerator/denominator; int remainder = numerator%denominator; return (quotient + (remainder != 0)); } int main() { int no_of_queues; scanf("%d", &no_of_queues); vector length(no_of_queues + 1); for(int i = 0; i < no_of_queues; i++) scanf("%d", &length[i]); for(int i = 0; i < no_of_queues; i++) length[i] = max(length[i] - i, 0); vector rounds_to_arrive_at(no_of_queues); for(int i = 0; i < no_of_queues; i++) rounds_to_arrive_at[i] = ceil(length[i], no_of_queues); const int oo = 1e9; int best_queue, minimum_rounds = oo; for(int i = 0; i < no_of_queues; i++) if(rounds_to_arrive_at[i] < minimum_rounds) minimum_rounds = rounds_to_arrive_at[i], best_queue = i + 1; printf("%d\n", best_queue); return 0; } ================================================ FILE: Contests/Div 2 497/Explanation/Reorder the Array Explanation.txt ================================================ Let us be greedy. For each element x, map it to the smallest element greater than it. It is solved by maintaining two pointers. :) -------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); sort(all(A)); int no_of_positions = 0; int available = no_of_elements; for(int i = no_of_elements; i >= 1; i--) { while(A[available] >= A[i]) available--; if(available > 0) available--, no_of_positions++; } printf("%d\n", no_of_positions); return 0; } ================================================ FILE: Contests/Div 2 497/Explanation/Romaji Explanation.txt ================================================ Ensure there are no consecutive vowels and that the last character is not a vowel. ----------- #include #include #include #include #include using namespace std; int is_vowel(char ch) { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': return true; } return false; } int main() { string S; cin >> S; char last_ch = S[S.size() - 1]; int good_string = (!is_vowel(last_ch) && last_ch != 'n' ? false : true); for(int i = 0; i + 1 < S.size(); i++) { if(S[i] == 'n') continue; if(!is_vowel(S[i]) && !is_vowel(S[i + 1])) { good_string = false; } } cout << (good_string ? "YES" : "NO"); return 0; } ================================================ FILE: Contests/Div 2 497/Explanation/Turn The Rectangle Explanation.txt ================================================ Just go through the array and ensure every rectangle has either minimum or maximum height so far. --------- int main() { int no_of_rectangles; scanf("%d", &no_of_rectangles); int possible = true; int last_height = 1e9; while(no_of_rectangles--) { int height, width; scanf("%d %d", &height, &width); int min_height = min(height, width); int max_height = max(height, width); if(max_height <= last_height) last_height = max_height; else if(min_height <= last_height) last_height = min_height; else possible = false; } printf(possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 497/Programs/Reorder the Array.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); sort(all(A)); int no_of_positions = 0; int available = no_of_elements; for(int i = no_of_elements; i >= 1; i--) { while(A[available] >= A[i]) available--; if(available > 0) available--, no_of_positions++; } printf("%d\n", no_of_positions); return 0; } ================================================ FILE: Contests/Div 2 497/Programs/Romaji.cpp ================================================ #include #include #include #include #include using namespace std; int is_vowel(char ch) { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': return true; } return false; } int main() { string S; cin >> S; char last_ch = S[S.size() - 1]; int good_string = (!is_vowel(last_ch) && last_ch != 'n' ? false : true); for(int i = 0; i + 1 < S.size(); i++) { if(S[i] == 'n') continue; if(!is_vowel(S[i]) && !is_vowel(S[i + 1])) { good_string = false; } } cout << (good_string ? "YES" : "NO"); return 0; } ================================================ FILE: Contests/Div 2 497/Programs/Turn the Rectangle.cpp ================================================ #include #define min(a, b) (a < b ? a : b) #define max(a, b) (a > b ? a : b) int main() { int no_of_rectangles; scanf("%d", &no_of_rectangles); int possible = true; int last_height = 1e9; while(no_of_rectangles--) { int height, width; scanf("%d %d", &height, &width); int min_height = min(height, width); int max_height = max(height, width); if(max_height <= last_height) last_height = max_height; else if(min_height <= last_height) last_height = min_height; else possible = false; } printf(possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 508/Explanation/Equality Explanation.txt ================================================ We want the minimum frequency. ----------------- #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int length, no_of_letters; string S; cin >> length >> no_of_letters >> S; vector frequency(no_of_letters, 0); for(int i = 0; i < S.size(); i++) frequency[S[i] - 'A']++; int minimum_frequency = length + 1; for(int i = 0; i < no_of_letters; i++) minimum_frequency = min(minimum_frequency, frequency[i]); int answer = minimum_frequency*no_of_letters; cout << answer; return 0; } ================================================ FILE: Contests/Div 2 508/Explanation/Gambling Explanation.txt ================================================ Greedy strategy works. If the largest element in your list, take it. Else, block it. -------------------------------------------- sort(all(A)); vector B(n); for(int i = 0; i < n; i++) cin >> B[i]; sort(all(B)); long long answer = 0; int a_ptr = n - 1, b_ptr = n - 1; for(int i = 1; i <= 2*n; i++) { if(i%2 == 1) //A's turn { if(b_ptr < 0 || (a_ptr >= 0 && A[a_ptr] >= B[b_ptr])) { answer += A[a_ptr--]; } else { b_ptr--; } } else if(i%2 == 0) //B's turn { if(a_ptr < 0 || (b_ptr >= 0 && B[b_ptr] >= A[a_ptr]) ) { answer -= B[b_ptr--]; } else { a_ptr--; } } } cout << answer; ================================================ FILE: Contests/Div 2 508/Explanation/Non Coprime Partition Explanation.txt ================================================ If n = 2, there is no solution. Else if n is even. Then (n + 1) divides the remaining sum Else n divides the remaining sum. ----------------------- if(n <= 2) { cout << "No"; } else { cout << "Yes\n"; if(n%2 == 0) { cout << "2 1 " << n; cout << "\n"; cout << n - 2 << " " ; for(int i = 2; i < n; i++) cout << i << " "; // This is (n + 1)(n - 2)/2. n is even. So it is divisible by n + 1 } else if(n%2 == 1) { cout << "1 " << n; cout << "\n"; cout << n - 1 << " "; for(int i = 1; i < n; i++) cout << i << " "; // This is n(n - 1)/2. n - 1 is even. So divisible by n. } } ================================================ FILE: Contests/Div 2 508/Programs/Equality.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int length, no_of_letters; string S; cin >> length >> no_of_letters >> S; vector frequency(no_of_letters, 0); for(int i = 0; i < S.size(); i++) frequency[S[i] - 'A']++; int minimum_frequency = length + 1; for(int i = 0; i < no_of_letters; i++) minimum_frequency = min(minimum_frequency, frequency[i]); int answer = minimum_frequency*no_of_letters; cout << answer; return 0; } ================================================ FILE: Contests/Div 2 508/Programs/Gambling.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int n; cin >> n; vector A(n); for(int i = 0; i < n; i++) cin >> A[i]; sort(all(A)); vector B(n); for(int i = 0; i < n; i++) cin >> B[i]; sort(all(B)); long long answer = 0; int a_ptr = n - 1, b_ptr = n - 1; for(int i = 1; i <= 2*n; i++) { if(i%2 == 1) //A's turn { if(b_ptr < 0 || (a_ptr >= 0 && A[a_ptr] >= B[b_ptr])) { answer += A[a_ptr--]; } else { b_ptr--; } } else if(i%2 == 0) //B's turn { if(a_ptr < 0 || (b_ptr >= 0 && B[b_ptr] >= A[a_ptr]) ) { answer -= B[b_ptr--]; } else { a_ptr--; } } } cout << answer; return 0; } ================================================ FILE: Contests/Div 2 508/Programs/Non Coprime Partition.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int n; cin >> n; if(n <= 2) { cout << "No"; } else { cout << "Yes\n"; if(n%2 == 0) { cout << "2"; cout << " 1 " << n; cout << "\n"; cout << n - 2 << " " ; for(int i = 2; i < n; i++) cout << i << " "; // This is (n + 1)(n - 2)/2. n is even. So it is divisible by n + 1 } else if(n%2 == 1) { cout << "1 " << n; cout << "\n"; cout << n - 1 << " "; for(int i = 1; i < n; i++) cout << i << " "; // This is n(n - 1)/2. n - 1 is even. So divisible by n. } } return 0; } ================================================ FILE: Contests/Div 2 511/Explanation/Enlarge GCD Explanation.txt ================================================ Every integer is divisible by the gcd - g. We want to look for the largest set of integers which have an additional common factor. Suppose it is x. Then all numbers are divisible by g and by x. If all numbers are divisible by some common factor x, then they all must have some common prime factor p. We look for the largest set of integers which are divisible by (gp), for some prime p. Now, we can't just look for a prime p which has the largest number of multiples as it is ... Because p might be a factor of g. -------------- Step 1 - Divide all integers by their gcd g. int array_gcd = 0; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); array_gcd = gcd(array_gcd, A[i]); } ------------------ Step 2 - Now you have N coprime numbers. Look for the largest set of integers which have some common prime factor - p. We can't factorise every integer. Go through every prime, and find out the number of multiples it has. The prime which has the largest number of multiples in the set is the one we want. int max_set_with_same_gcd = 0; vector is_prime(MAX_NUM + 1, true); for(int i = 2; i <= MAX_NUM; i++) { if(!is_prime[i]) continue; int no_of_i_multiples = 0; for(int multiple = i; multiple <= MAX_NUM; multiple += i) { no_of_i_multiples += frequency[multiple]; is_prime[multiple] = false; } max_set_with_same_gcd = max(max_set_with_same_gcd, no_of_i_multiples); } ================================================ FILE: Contests/Div 2 511/Explanation/Little C Loves 3 I Explanation.txt ================================================ (1, 1, n - 2) satisfies the given condition unless n = 2 (mod 3) So if n = 2 (mod 3) We will give (1, 2, n - 3) ---------------------- int main() { int n; scanf("%d", &n); if(n%3 == 2) { printf("%d %d %d\n", 1, 2, n - 3); } else { printf("%d %d %d\n", 1, 1, n - 2); } return 0; } ================================================ FILE: Contests/Div 2 511/Programs/Little C Loves 3 I.cpp ================================================ #include int main() { int n; scanf("%d", &n); if(n%3 == 2) { printf("%d %d %d\n", 1, 2, n - 3); } else { printf("%d %d %d\n", 1, 1, n - 2); } return 0; } ================================================ FILE: Contests/Div 2 533/Explanations/Ayoub and Lost Array Explanation.txt ================================================ Let f(i, r) be the number of ways of filling first i elements such that they sum upto r. Then the last element l can be either 0, 1, or 2. Let F(r) denote the frequency of r = {0, 1, 2} Now, we can fix the last element. Suppose last element is 0. Then f(i + 1, (0 + 0)) += F(0)f(i, 0) f(i + 1, (0 + 1)) += F(0)f(i, 1) f(i + 1, (0 + 2)) += F(0)f(i, 2) ----- These would be the transitions. The last can be l. The previous can be p = {0, 1, 2} --- int get_count(int limit, int remainder) { if(remainder == 0) return limit/3; else return (limit/3 + (limit%3 >= remainder)); } -------- Accordingly, we update the DP like this - A total_remainder is made by combination of {last, previous}. So, f(i, total) += F(last)f(i - 1, previous) For example, f(i, 0) = F(0)f(i - 1, 0) + F(1)f(i - 1, 2) + F(2)f(i - 1, 1) --- no_of_ways[0][0] = 1; no_of_ways[0][1] = no_of_ways[0][2] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int last = 0; last < 3; last++) { for(int previous = 0; previous < 3; previous++) { int total_remainder = (previous + last)%3; no_of_ways[i][total_remainder] += (frequency[last]*no_of_ways[i - 1][previous])%MOD; no_of_ways[i][total_remainder] %= MOD; } } } ================================================ FILE: Contests/Div 2 533/Explanations/Ayoub and Lost Array Matrix Exponentiation Explanation.txt ================================================ This one uses the approach of the previous solution but uses matrix exponentiation. Let us write down the recurrence - f(i, 0) = F[0]f(i - 1, 0) + F[2]f(i - 1, 1) + F[1]f(i - 1, 2); f(i, 1) = F[1]f(i - 1, 0) + F[0]f(i - 1, 1) + F[2]f(i - 1, 2); f(i, 2) = F[2]f(i - 1, 0) + F[1]f(i - 1, 1) + F[0]f(i - 1, 2); Let A = [f(i, 0) f(i, 1) f(i 2)] Let F = | F[0] F[1] F[2] | | F[2] F[0] F[1] | | F[1] F[2] F[0] | Then A^N = A^{N - 1} F = A^0 F^N ------------ int main() { int no_of_elements, left, right; scanf("%d %d %d", &no_of_elements, &left, &right); vector frequency(3, 0); for(int i = 0; i < 3; i++) { frequency[i] = get_count(right, i) - get_count(left - 1, i); } int no_of_ways_sum_0_from_0_elements = 1, no_of_ways_sum_1_from_0_elements = 0, no_of_ways_sum_2_from_0_elements = 0; /*f(i, 0) = F[0]f(i - 1, 0) + F[2]f(i - 1, 1) + F[1]f(i - 1, 2); f(i, 1) = F[1]f(i - 1, 0) + F[0]f(i - 1, 1) + F[2]f(i - 1, 2); f(i, 2) = F[2]f(i - 1, 0) + F[1]f(i - 1, 1) + F[0]f(i - 1, 2);*/ long long A[SIZE][SIZE] = {{no_of_ways_sum_0_from_0_elements, no_of_ways_sum_1_from_0_elements, no_of_ways_sum_2_from_0_elements}}; long long F[SIZE][SIZE] = { {frequency[0], frequency[1], frequency[2]}, {frequency[2], frequency[0], frequency[1]}, {frequency[1], frequency[2], frequency[0]} }; //A^n = A^{n - 1}F = A^1 F^{n-1} power(F, no_of_elements); multiply(A, F); printf("%I64d\n", A[0][0]); return 0; } ================================================ FILE: Contests/Div 2 533/Explanations/Salem and Sticks Explanation.txt ================================================ It is a unimodal function. (Not monotonic). So we can apply ternary search instead of binary search ! ------------ int calculate_cost(vector &A, int t) { int cost = 0; for(int i = 1; i < A.size(); i++) { if(A[i] < t) cost += ((t - 1) - A[i]); if(A[i] > t) cost += (A[i] - (t + 1)); } return cost; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; const int MAX = 100; int left = 1, right = MAX; while(left < right) { int mid_1 = (2*left + right)/3; int mid_2 = (left + 2*right)/3; if(calculate_cost(A, mid_1) <= calculate_cost(A, mid_2)) { right = mid_2; } else { left = mid_1 + 1; } } int answer = (calculate_cost(A, left) < calculate_cost(A, right) ? left : right); cout << answer << " " << calculate_cost(A, answer); return 0; } ================================================ FILE: Contests/Div 2 533/Explanations/Zuhair and Strings Explanation.txt ================================================ Let us call a substring of same characters a 'block'. Let us call a substring of same characters a 'chunk' if it is of size = k If we have a block of size >= k, we will divide it into chunks of size k. The 'level' of a string is the number of chunks we can make with any one alphabet. So, we will calculate the number of 'chunks' we can make with each alphabet and then find which alphabet has the highest number of 'chunks'. ---- Let f(i) denote the length of the 'block' size ending at i. If position i is the end of a 'block', Then we can have [f(i)/k] 'chunks' from this 'block'. We will keep track of the number of 'chunks' we can have of each alphabet and then find the maximum. ---- Suppose we have aaabaaaa Then f(i) would be {1 2 3 1 1 2 3 4} If k = 2, Then the first block aaa, can be divided into one substring of length 2. So, we get one chunk from the first block. The second block aaaa, can be divided into two substrings of length 2. So, we get two chunks from the second block. We get 3 chunks of a We do not have any chunks of b as there is only one block of b, who's size is 1 so we cannot divide it into chunks of a. ---- We calculate f(i) with a simple DP. vector longest_block_till(length, 0); longest_block_till[0] = 1; for(int i = 1; i < length; i++) { longest_block_till[i] = (S[i] == S[i - 1] ? longest_block_till[i - 1] + 1 : 1); } --- And then we use f(i). We know a block ends if it is either the end of the string or a position such that S[i] != S[i + 1]. At this position we will find the number of new blocks of the letter S[i] that are possible const int NO_OF_ALPHABETS = 26; vector no_of_k_sequences(NO_OF_ALPHABETS, 0); for(int i = 0; i < length; i++) { if(i == length - 1 || S[i] != S[i + 1])//Reached the end of a block { no_of_k_sequences[S[i] - 'a'] += longest_block_till[i]/k; } } --- After this, we will find out which alphabet has the highest number of blocks. int answer = 0; for(int i = 0; i < NO_OF_ALPHABETS; i++) answer = max(answer, no_of_k_sequences[i]); ================================================ FILE: Contests/Div 2 533/Programs/Ayoub and Lost Array Matrix Exponentiation.cpp ================================================ #include #include using namespace std; const int MOD = 1e9 + 7, SIZE = 3; void load_identity(long long I[][SIZE]) { for(int i = 0; i < SIZE; i++) for(int j = 0; j < SIZE; j++) I[i][j] = (i == j ? 1 : 0); } void copy(long long source[][SIZE], long long target[][SIZE]) { for(int i = 0; i < SIZE; i++) for(int j = 0; j < SIZE; j++) target[i][j] = source[i][j]; } void multiply(long long A[][SIZE], long long B[][SIZE]) { long long product[SIZE][SIZE]; for(int i = 0; i < SIZE; i++) { for(int j = 0; j < SIZE; j++) { product[i][j] = 0; for(int k = 0; k < SIZE; k++) { product[i][j] += (A[i][k]*B[k][j])%MOD; } product[i][j] %= MOD; } } copy(product, A); } void power(long long X[][SIZE], long long power) { long long result[SIZE][SIZE]; load_identity(result); while(power) { if(power%2 == 1) multiply(result, X); multiply(X, X); power = power >> 1; } copy(result, X); } int get_count(int limit, int remainder) { if(remainder == 0) return limit/3; else return (limit/3 + (limit%3 >= remainder)); } int main() { int no_of_elements, left, right; scanf("%d %d %d", &no_of_elements, &left, &right); vector frequency(3, 0); for(int i = 0; i < 3; i++) { frequency[i] = get_count(right, i) - get_count(left - 1, i); } int no_of_ways_sum_0_from_0_elements = 1, no_of_ways_sum_1_from_0_elements = 0, no_of_ways_sum_2_from_0_elements = 0; /*f(i, 0) = F[0]f(i - 1, 0) + F[2]f(i - 1, 1) + F[1]f(i - 1, 2); f(i, 1) = F[1]f(i - 1, 0) + F[0]f(i - 1, 1) + F[2]f(i - 1, 2); f(i, 2) = F[2]f(i - 1, 0) + F[1]f(i - 1, 1) + F[0]f(i - 1, 2);*/ long long A[SIZE][SIZE] = {{no_of_ways_sum_0_from_0_elements, no_of_ways_sum_1_from_0_elements, no_of_ways_sum_2_from_0_elements}}; long long F[SIZE][SIZE] = { {frequency[0], frequency[1], frequency[2]}, {frequency[2], frequency[0], frequency[1]}, {frequency[1], frequency[2], frequency[0]} }; //A^n = A^{n - 1}F = A^0 F^n power(F, no_of_elements); multiply(A, F); printf("%I64d\n", A[0][0]); return 0; } ================================================ FILE: Contests/Div 2 533/Programs/Ayoub and Lost Array.cpp ================================================ #include #include using namespace std; const int MOD = 1e9 + 7, MAX_N = 2e5 + 5; long long no_of_ways[MAX_N][3]; int get_count(int limit, int remainder) { if(remainder == 0) return limit/3; else return (limit/3 + (limit%3 >= remainder)); } int main() { int no_of_elements, left, right; scanf("%d %d %d", &no_of_elements, &left, &right); vector frequency(3, 0); for(int i = 0; i < 3; i++) { frequency[i] = get_count(right, i) - get_count(left - 1, i); } no_of_ways[0][0] = 1; no_of_ways[0][1] = no_of_ways[0][2] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int last = 0; last < 3; last++) { for(int previous = 0; previous < 3; previous++) { int total_remainder = (previous + last)%3; no_of_ways[i][total_remainder] += (frequency[last]*no_of_ways[i - 1][previous])%MOD; no_of_ways[i][total_remainder] %= MOD; } } } printf("%I64d\n", no_of_ways[no_of_elements][0]); return 0; } ================================================ FILE: Contests/Div 2 533/Programs/Salem and Sticks.cpp ================================================ #include #include #include using namespace std; int calculate_cost(vector &A, int t) { int cost = 0; for(int i = 1; i < A.size(); i++) { if(A[i] < t) cost += ((t - 1) - A[i]); if(A[i] > t) cost += (A[i] - (t + 1)); } return cost; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; const int MAX = 100; int left = 1, right = MAX; while(left < right) { int mid_1 = (2*left + right)/3; int mid_2 = (left + 2*right)/3; if(calculate_cost(A, mid_1) <= calculate_cost(A, mid_2)) { right = mid_2; } else { left = mid_1 + 1; } } int answer = (calculate_cost(A, left) < calculate_cost(A, right) ? left : right); cout << answer << " " << calculate_cost(A, answer); return 0; } ================================================ FILE: Contests/Div 2 533/Programs/Zuhair and Strings.cpp ================================================ #include #include #include using namespace std; int main() { int length, k; cin >> length >> k; string S; cin >> S; vector longest_block_till(length, 0); longest_block_till[0] = 1; for(int i = 1; i < length; i++) { longest_block_till[i] = (S[i] == S[i - 1] ? longest_block_till[i - 1] + 1 : 1); } const int NO_OF_ALPHABETS = 26; vector no_of_k_sequences(NO_OF_ALPHABETS, 0); for(int i = 0; i < length; i++) { if(i == length - 1 || S[i] != S[i + 1])//Reached the end of a block { no_of_k_sequences[S[i] - 'a'] += longest_block_till[i]/k; } } int answer = 0; for(int i = 0; i < NO_OF_ALPHABETS; i++) answer = max(answer, no_of_k_sequences[i]); cout << answer; return 0; } ================================================ FILE: Contests/Div 2 538/Explanations/Arithmetic Progression Explanation.txt.txt ================================================ - Use queries of the first kind to find the maximum element using binary search. - Find random indices and get the values and sort them - The difference between any two consecutive elements will be a multiple of $g$ - If we choose them randomly enough, there will two that are coprime, for example $3g$ and $5g$ so their GCD will give us $g$ The probability of failing to find 2 coprime differences among a sequence of n elements among k is of the order 10^{-9} ------ mt19937 rng(time(NULL)); int find_maximum(int &queries) { int left = 0, right = 1e9 + 5; //Always L < Max <= R while(right - left > 1) { int has_higher; int mid = (left + right)/2; queries--; cout << "> " << mid << "\n"; cout.flush(); cin >> has_higher; if(has_higher) left = mid; else right = mid; } return right; } int find_difference(int &queries, int greatest, int no_of_elements) { int remaining_range = no_of_elements - 1; vector A; vector asked(no_of_elements + 1, false); while(queries > 0 && remaining_range > 0) { int question_index = uniform_int_distribution(1, no_of_elements)(rng); if(asked[question_index]) { continue; } cout << "? " << question_index << "\n"; cout.flush(); asked[question_index] = true; int answer; cin >> answer; A.push_back(answer); queries--; remaining_range--; } sort(all(A)); if(A[A.size() - 1] != greatest) A.push_back(greatest); int difference = A[1] - A[0]; for(int i = 1; i < A.size(); i++) difference = __gcd(difference, A[i] - A[i - 1]); return difference; } int main() { int no_of_elements; cin >> no_of_elements; const int MAX_QUERIES = 60; int queries = MAX_QUERIES; int maximum = find_maximum(queries); int difference = find_difference(queries, maximum, no_of_elements); int minimum = maximum - difference*(no_of_elements - 1); cout << "! " << minimum << " " << difference << "\n"; cout.flush(); return 0; } ================================================ FILE: Contests/Div 2 538/Explanations/Flood Fill Explanation.txt ================================================ Fact - If a segment [L, R] is of one colour, then it is either A[L] or A[R] regardless of the starting square. Proof - In the last move of making the segment the same colour, we must absorb one of the ends - L or R (or both). When we absorb an end we must cover the entire segment with one colour. --------------- Let f(L, R, 0) represent the minimum number of moves to make the segment [L, R] in one colour if the colour is A[L]. Let f(L, R, 1) represent the minimum number of moves to make the segment [L, R] in one colour if the color is A[R]. How do we build [L, R] from smaller states ? Suppose we want to find out f(L, R, 0) ... Then it means we are using the colour of A[L]. So we need to know the minimum number of moves to make [L + 1, R] the same colour. ----- There are 2 cases - Case 1 - Either [L - 1, R] is the same colour as A[L]. Then the number of moves is given by f(L - 1, R, 0) and the colour is A[L]. Case 2 - [L - 1, R] is the same colour as A[R]. The the number of moves is given by f(L - 1, R, 1) and the colour is A[R]. ------- ================================================ FILE: Contests/Div 2 538/Explanations/Got Any Grapes Explanation.txt ================================================ We will see if there are enough grapes of the first kind and give the excess to the second. Then, we will see if there are enough grapes of the second kind and give the excess to the third. ------------ int main() { int green_want, black_want, purple_want; cin >> green_want >> black_want >> purple_want; int green_have, black_have, purple_have; cin >> green_have >> black_have >> purple_have; if(green_have > green_want) { int excess = green_have - green_want; green_have -= excess; black_have += excess; } if(black_have > black_want) { int excess = black_have - black_want; black_have -= excess; purple_have += excess; } cout << (green_want <= green_have && black_want <= black_have && purple_want <= purple_have ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 538/Explanations/Please Another Queries on Array Explanation.txt ================================================ Let N = p1^k1 p2^k2 ... pm^k phi(N) = p1^(k1 - 1)(p1 - 1) p2^(k2 - 1)(p2 - 1) ... pm^(km - 1)(pm - 1) = p1^K1 p2^k2 ... pm^km {(p1 - 1)(p2 - 1) ... (pm - 1)}/(p1 p2 ... pm) The reason this form of phi(N) is important is because it is independent of exponents of primes. ----------- To answer a range query, we need two informations - 1. The product of the range 2. The list of all primes having factors in the range. We can get the product of a range very easily by maintaining a segment tree. -------------- How do we keep the list of all primes having factors ? Note that Ai < 300. There are less than 64 (62 to be exact) primes from [2, 300]. We will represent each integer x, by a bitmask where the i-th bit will be set if the i-th prime divides x For example, if x = 24, then bitmask will have 00000 ... 0011 The first two bits set since it is divisible by 2 and 3. Here is how we precompute the masks - void precompute_mask() { for(int i = 1; i < MAX_N; i++) { mask[i] = 0; for(int bit = 0; bit < primes.size(); bit++) { if(i%primes[bit] == 0) { set_bit(mask[i], bit); } } } } --------------- Now, how do we find out the mask of a range of numbers ? It is simple. We want the i-th bit set, if the i-th prime divides any of the integers in the range. In other words, if any of the masks in the range have the i-th bit set, then the mask of the range should have the i-th bit set. All we need to do is find the OR of the masks of the segment ! When we are multiplying a number x with every integer in the range, we need to perform OR(x, ) with every integer in the range. It will be too slow to perform each update in O(n) time so we will maintain a segment tree that performs the OR operation ! ---------------- Here is how we answer each query - void solve() { string query; int left, right; cin >> query >> left >> right; if(query == "MULTIPLY") { int x; cin >> x; product_tree.update(1, 1, no_of_elements, left, right, x); OR_tree.update(1, 1, no_of_elements, left, right, mask[x]); } else if(query == "TOTIENT") { LL totient = product_tree.get_product(1, 1, no_of_elements, left, right); LL segment_mask = OR_tree.get_mask(1, 1, no_of_elements, left, right); for(int bit = 0; bit < primes.size(); bit++) { if(!is_bit_set(segment_mask, bit)) continue; totient = (totient*(primes[bit] - 1))%MOD; totient = (totient*prime_inverse[bit])%MOD; } cout << totient << "\n"; } } --------- We cannot divide since we are dealing with a MOD so we will need to multiply by the inverse of the prime. It is better to precompute the inverses as well using Fermat's Little Theorem. I had a lot of bugs in implementation of segment tree such as - 1. The Lazy Function of Product Segment Tree should multiply tree[n] by x^r, where r is the size of the range under n, not just by x. 2. The OR Tree should allow long long masks and the tree should be long long. And the value of MAX_N should be properly set to 300. 3. The set bit function had a mistake 4. The prime sieve should start from 2, not 1 or 0. 5. The base case of the product function should have an OR condition, not AND, which will cause an infinite loop. ================================================ FILE: Contests/Div 2 538/Explanations/Trailing Loves Explanation.txt ================================================ The number of 0s in n! is equal to the exponent of b in (n!) Let us look at the prime factorisation of b. b = p1^k1 p2^k2 .... pm^km -------------- The exponent of a prime number p in n! is (n/p) + (n/p^2) + (n/p^3) + ... The exponent of p^k in n! is e/k, where e is the exponent of p in n! (which can be calculated by the method given above). LL get_exponent_sum(LL n, LL p, int e) { LL sum = 0; while(n > 0) { sum += n/p; n /= p; } return (sum/e); } ------------- The exponent of b in (n!) is min{exp(p1^k1), exp(p2^k2), ... , (exp(pm^km))} in n! int main() { LL n, base; cin >> n >> base; vector prime_factors; vector exponents; factorise(prime_factors, exponents, base); const LL oo = 1e18; LL trailing_zeroes = oo; for(int i = 0; i < prime_factors.size(); i++) { trailing_zeroes = min(trailing_zeroes, get_exponent_sum(n, prime_factors[i], exponents[i])); } cout << trailing_zeroes; return 0; } ================================================ FILE: Contests/Div 2 538/Explanations/Yet Another Subarray Alternate Solution Explanation.txt ================================================ This is exactly like the previous solution. But, rather than marking which indices belong to the greatest mk elements. Here we push those mk indices into a vector and sort it. And then we print every m-th index of this vector. -------------------- int main() { int no_of_elements, min_size, no_of_subarrays; cin >> no_of_elements >> min_size >> no_of_subarrays; vector A; for(int i = 0; i < no_of_elements; i++) { int element; cin >> element; A.push_back(info(i, element)); } sort(all(A)); reverse(all(A)); int greatest_elements = min_size*no_of_subarrays; long long total_sum = 0; vector special_index(greatest_elements); for(int i = 0; i < greatest_elements; i++) { total_sum += A[i].value; special_index[i] = A[i].index + 1; } sort(all(special_index)); vector partition_points(no_of_subarrays); for(int i = 0; i < no_of_subarrays; i++) { partition_points[i] = special_index[(i + 1)*min_size - 1]; } cout << total_sum << "\n"; for(int i = 0; i < no_of_subarrays - 1; i++) cout << partition_points[i] << " "; return 0; } ================================================ FILE: Contests/Div 2 538/Explanations/Yet Another Subarray Explanation.txt ================================================ Let us look at the greatest mk elements. We will divide the arrays in such a way that each subarray has exactly m of these mk elements. This is always possible since mk <= n. We will mark all the indices which belong to the greatest mk elements. Then we will do a linear sweep through the array. Whenever the current segment has m of these indices, we will end the segment and begin a new one. ----------------------- int main() { int no_of_elements, min_size, no_of_subarrays; cin >> no_of_elements >> min_size >> no_of_subarrays; vector A; for(int i = 0; i < no_of_elements; i++) { int element; cin >> element; A.push_back(info(i, element)); } sort(all(A)); reverse(all(A)); int greatest_elements = min_size*no_of_subarrays; long long total_sum = 0; vector is_special(no_of_elements, false); for(int i = 0; i < greatest_elements; i++) { is_special[A[i].index] = true; total_sum += A[i].value; } int no_of_subarrays_made = 0, current_subarray_special_elements = 0; vector partition_points; for(int i = 0; i < no_of_elements; i++) { current_subarray_special_elements += (is_special[i]); if(current_subarray_special_elements == min_size) { partition_points.push_back(i + 1); no_of_subarrays_made++; current_subarray_special_elements = 0; } } cout << total_sum << "\n"; for(int i = 0; i < no_of_subarrays_made - 1; i++) cout << partition_points[i] << " "; return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Arithmetic Progression.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; mt19937 rng(time(NULL)); int find_maximum(int &queries) { int left = 0, right = 1e9 + 5; //Always L < Max <= R while(right - left > 1) { int has_higher; int mid = (left + right)/2; queries--; cout << "> " << mid << "\n"; cout.flush(); cin >> has_higher; if(has_higher) left = mid; else right = mid; } return right; } int find_difference(int &queries, int greatest, int no_of_elements) { int remaining_range = no_of_elements - 1; vector A; vector asked(no_of_elements + 1, false); while(queries > 0 && remaining_range > 0) { int question_index = uniform_int_distribution(1, no_of_elements)(rng); if(asked[question_index]) { continue; } cout << "? " << question_index << "\n"; cout.flush(); asked[question_index] = true; int answer; cin >> answer; A.push_back(answer); queries--; remaining_range--; } sort(all(A)); if(A[A.size() - 1] != greatest) A.push_back(greatest); int difference = A[1] - A[0]; for(int i = 1; i < A.size(); i++) difference = __gcd(difference, A[i] - A[i - 1]); return difference; } int main() { int no_of_elements; cin >> no_of_elements; const int MAX_QUERIES = 60; int queries = MAX_QUERIES; int maximum = find_maximum(queries); int difference = find_difference(queries, maximum, no_of_elements); int minimum = maximum - difference*(no_of_elements - 1); cout << "! " << minimum << " " << difference << "\n"; cout.flush(); return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Flood Fill.cpp ================================================ #include #include using namespace std; typedef long long LL; const int MAX_N = 5005, oo = 5005, LEFT_COLOUR = 0, RIGHT_COLOUR = 1, NO_OF_ENDS = 2; int minimum_moves[MAX_N][MAX_N][NO_OF_ENDS]; int main() { int no_of_squares; cin >> no_of_squares; vector A(no_of_squares + 1); for(int i = 1; i <= no_of_squares; i++) cin >> A[i]; for(int i = 1; i <= no_of_squares; i++) { minimum_moves[i][i][LEFT_COLOUR] = minimum_moves[i][i][RIGHT_COLOUR] = 0; } for(int length = 2; length <= no_of_squares; length++) { for(int left = 1, right = left + length - 1; right <= no_of_squares; left++, right++) { minimum_moves[left][right][LEFT_COLOUR] = min(minimum_moves[left + 1][right][LEFT_COLOUR] + (A[left] != A[left + 1]), minimum_moves[left + 1][right][RIGHT_COLOUR] + (A[left] != A[right])); minimum_moves[left][right][RIGHT_COLOUR] = min(minimum_moves[left][right - 1][LEFT_COLOUR] + (A[left] != A[right]), minimum_moves[left][right - 1][RIGHT_COLOUR] + (A[right - 1] != A[right])); } } LL answer = min(minimum_moves[1][no_of_squares][LEFT_COLOUR], minimum_moves[1][no_of_squares][RIGHT_COLOUR]); cout << answer; return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Got Any Grapes.cpp ================================================ #include using namespace std; int main() { int green_want, black_want, purple_want; cin >> green_want >> black_want >> purple_want; int green_have, black_have, purple_have; cin >> green_have >> black_have >> purple_have; if(green_have > green_want) { int excess = green_have - green_want; green_have -= excess; black_have += excess; } if(black_have > black_want) { int excess = black_have - black_want; black_have -= excess; purple_have += excess; } cout << (green_want <= green_have && black_want <= black_have && purple_want <= purple_have ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Please Another Queries on Array.cpp ================================================ #include #include #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; const int MOD = 1e9 + 7, MAX_N = 305; typedef long long LL; vector primes; vector prime_inverse; vector mask(MAX_N, 0); int is_bit_set(LL n, int position) { return ( (n&(1LL << position)) != 0); } void set_bit(LL &n, int position) { n |= (1LL << position); } LL fast_power(LL base, LL power) { LL result = 1; while(power) { if(power%2 == 1) result = (result*base)%MOD; base = (base*base)%MOD; power = power >> 1; } return result; } void precompute_primes() { vector is_prime(MAX_N, true); for(int i = 2; i < MAX_N; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] < MAX_N; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } } void precompute_prime_inverse() { for(int i = 0; i < primes.size(); i++) { LL inverse = fast_power(primes[i], MOD - 2); prime_inverse.push_back(inverse); } } void precompute_mask() { for(int i = 1; i < MAX_N; i++) { mask[i] = 0; for(int bit = 0; bit < primes.size(); bit++) { if(i%primes[bit] == 0) { set_bit(mask[i], bit); } } } } struct Product_Tree { vector tree, lazy; Product_Tree(){} Product_Tree(int n) { tree.resize(4*n, 1); lazy.resize(4*n, 1); } void propagate(int n, int left, int right) { LL range = right - (left - 1); tree[n] = (tree[n]*fast_power(lazy[n], range))%MOD; if(left != right) { lazy[LEFT(n)] = (lazy[LEFT(n)]*lazy[n])%MOD; lazy[RIGHT(n)] = (lazy[RIGHT(n)]*lazy[n])%MOD; } lazy[n] = 1; } void update(int n, int left, int right, int query_left, int query_right, int value) { if(lazy[n] > 1) { propagate(n, left, right); } if(right < query_left || query_right < left) { return; } if(query_left <= left && right <= query_right) { lazy[n] = (lazy[n]*value)%MOD; propagate(n, left, right); return; } int mid = (left + right)/2; update(LEFT(n), left, mid, query_left, query_right, value); update(RIGHT(n), mid + 1, right, query_left, query_right, value); tree[n] = (tree[LEFT(n)]*tree[RIGHT(n)])%MOD; } LL get_product(int n, int left, int right, int query_left, int query_right) { if(lazy[n] > 1) { propagate(n, left, right); } if(right < query_left || query_right < left) { return 1LL; } if(query_left <= left && right <= query_right) { return tree[n]; } int mid = (left + right)/2; LL left_product = get_product(LEFT(n), left, mid, query_left, query_right); LL right_product = get_product(RIGHT(n), mid + 1, right, query_left, query_right); LL product = (left_product*right_product)%MOD; return product; } }; struct OR_Tree { vector tree, lazy; OR_Tree(){} OR_Tree(int n) { tree.resize(4*n, 0); lazy.resize(4*n, 0); } void propagate(int n, int left, int right) { tree[n] |= lazy[n]; if(left != right) { lazy[LEFT(n)] |= lazy[n]; lazy[RIGHT(n)] |= lazy[n]; } lazy[n] = 0; } void update(int n, int left, int right, int query_left, int query_right, LL value) { if(lazy[n]) { propagate(n, left, right); } if(right < query_left || query_right < left) { return; } if(query_left <= left && right <= query_right) { lazy[n] |= value; propagate(n, left, right); return; } int mid = (left + right)/2; update(LEFT(n), left, mid, query_left, query_right, value); update(RIGHT(n), mid + 1, right, query_left, query_right, value); tree[n] = (tree[LEFT(n)]|tree[RIGHT(n)]); } LL get_mask(int n, int left, int right, int query_left, int query_right) { if(lazy[n]) { propagate(n, left, right); } if(right < query_left || query_right < left) { return 0; } if(query_left <= left && right <= query_right) { return tree[n]; } int mid = (left + right)/2; LL left_mask = get_mask(LEFT(n), left, mid, query_left, query_right); LL right_mask = get_mask(RIGHT(n), mid + 1, right, query_left, query_right); LL mask = (left_mask|right_mask); return mask; } }; Product_Tree product_tree; OR_Tree OR_tree; int no_of_elements, no_of_queries; void read_input() { cin >> no_of_elements >> no_of_queries; product_tree = Product_Tree(no_of_elements); OR_tree = OR_Tree(no_of_elements); for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; product_tree.update(1, 1, no_of_elements, i, i, element); OR_tree.update(1, 1, no_of_elements, i, i, mask[element]); } } void solve() { string query; int left, right; cin >> query >> left >> right; if(query == "MULTIPLY") { int x; cin >> x; product_tree.update(1, 1, no_of_elements, left, right, x); OR_tree.update(1, 1, no_of_elements, left, right, mask[x]); } else if(query == "TOTIENT") { LL totient = product_tree.get_product(1, 1, no_of_elements, left, right); LL segment_mask = OR_tree.get_mask(1, 1, no_of_elements, left, right); for(int bit = 0; bit < primes.size(); bit++) { if(!is_bit_set(segment_mask, bit)) continue; totient = (totient*(primes[bit] - 1))%MOD; totient = (totient*prime_inverse[bit])%MOD; } cout << totient << "\n"; } } int main() { precompute_primes(); precompute_prime_inverse(); precompute_mask(); read_input(); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Trailing Loves.cpp ================================================ #include #include using namespace std; typedef long long LL; void factorise(vector &F, vector &E, LL n) { for(LL i = 2; i*i <= n; i++) { if(n%i == 0) { int exponent = 0; while(n%i == 0) { n /= i; exponent++; } F.push_back(i); E.push_back(exponent); } } if(n > 1) { F.push_back(n); E.push_back(1); } } LL get_exponent_sum(LL n, LL p, int e) { LL sum = 0; while(n > 0) { sum += n/p; n /= p; } return (sum/e); } int main() { LL n, base; cin >> n >> base; vector prime_factors; vector exponents; factorise(prime_factors, exponents, base); const LL oo = 1e18; LL trailing_zeroes = oo; for(int i = 0; i < prime_factors.size(); i++) { trailing_zeroes = min(trailing_zeroes, get_exponent_sum(n, prime_factors[i], exponents[i])); } cout << trailing_zeroes; return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Yet Another Subarray Problem Alternate Solution.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct info { int index, value; info(int i, int v) { index = i; value = v; } const int operator<(const info &X) { return (value < X.value); } }; int main() { int no_of_elements, min_size, no_of_subarrays; cin >> no_of_elements >> min_size >> no_of_subarrays; vector A; for(int i = 0; i < no_of_elements; i++) { int element; cin >> element; A.push_back(info(i, element)); } sort(all(A)); reverse(all(A)); int greatest_elements = min_size*no_of_subarrays; long long total_sum = 0; vector special_index(greatest_elements); for(int i = 0; i < greatest_elements; i++) { total_sum += A[i].value; special_index[i] = A[i].index + 1; } sort(all(special_index)); vector partition_points(no_of_subarrays); for(int i = 0; i < no_of_subarrays; i++) { partition_points[i] = special_index[(i + 1)*min_size - 1]; } cout << total_sum << "\n"; for(int i = 0; i < no_of_subarrays - 1; i++) cout << partition_points[i] << " "; return 0; } ================================================ FILE: Contests/Div 2 538/Programs/Yet Another Subarray Problem.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct info { int index, value; info(int i, int v) { index = i; value = v; } const int operator<(const info &X) { return (value < X.value); } }; int main() { int no_of_elements, min_size, no_of_subarrays; cin >> no_of_elements >> min_size >> no_of_subarrays; vector A; for(int i = 0; i < no_of_elements; i++) { int element; cin >> element; A.push_back(info(i, element)); } sort(all(A)); reverse(all(A)); int greatest_elements = min_size*no_of_subarrays; long long total_sum = 0; vector is_special(no_of_elements, false); for(int i = 0; i < greatest_elements; i++) { is_special[A[i].index] = true; total_sum += A[i].value; } int no_of_subarrays_made = 0, current_subarray_special_elements = 0; vector partition_points; for(int i = 0; i < no_of_elements; i++) { current_subarray_special_elements += (is_special[i]); if(current_subarray_special_elements == min_size) { partition_points.push_back(i + 1); no_of_subarrays_made++; current_subarray_special_elements = 0; } } cout << total_sum << "\n"; for(int i = 0; i < no_of_subarrays_made - 1; i++) cout << partition_points[i] << " "; return 0; } ================================================ FILE: Contests/Div 2 539/Explanations/Sasha and A Bit of Relax Explanation.txt ================================================ I thought of approaching this question by treating each bit independently, like most bitwise questions. I couldn't find a way to combine answers for different bits. I read the editorial used the insight that the XOR of the segment is 0 and then I immediately understood how to use prefix XOR to solve this problem. ------------- We keep track of the frequency of every prefix_xor and each parity. If XOR[L, ... , R] = 0, then Prefix[R] = Prefix[L - 1] For every i, let f(i, 0) be the frequency of prefix XOR i in even positions and f(i, 1) be the frequency of prefix XOR i in odd positions. We will go through the array and for each i, we will add f(Prefix[i], i%2) to the answer and then update f(Prefix[i], i%2). Remember to set f(0, 0) = 1. That represents the empty array. ------------- int main() { int no_of_elements; cin >> no_of_elements; int prefix_xor = 0; long long good_subarrays = 0; memset(frequency, 0, sizeof(frequency)); frequency[0][0] = 1; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; prefix_xor ^= element; good_subarrays += (frequency[prefix_xor][i%2]); frequency[prefix_xor][i%2]++; } cout << good_subarrays; return 0; } ================================================ FILE: Contests/Div 2 539/Explanations/Sasha and His Trip Explanation.txt ================================================ It is always better to buy the liter as early as possible as we will pay more for the same amount as time goes on. We will be greedy. We will first buy v literes in first city Then, we will go to each city and buy only one liter, and make sure the capacity is full. We will not refill, if the remaining journey x, is smaller than the the fuel we have v. ------------------- Of course, if we capacity is more than the number of cities, then we will only refuel n - 1 times. ------------------- int main() { int no_of_cities, capacity; cin >> no_of_cities >> capacity; int fuel; if(capacity >= no_of_cities - 1) { fuel = no_of_cities - 1; } else { fuel = capacity - 1; for(int i = 1; i <= no_of_cities - capacity; i++) fuel += i; } cout << fuel; return 0; } ================================================ FILE: Contests/Div 2 539/Explanations/Sasha and Magnetic Machine Explanation.txt ================================================ The number we multiply with will always be the minimum integer. So, we will iterate from 1 to 100. For each number x from the minimum till 100, we will iterate over all of x's factors and examine the change in the sum if we multiply the minimum with x and divide x by it's factor. --------- int main() { int no_of_elements; cin >> no_of_elements; const int MAX = 105; vector frequency(MAX, 0); int sum = 0; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; frequency[element]++; sum += element; } int minimum; for(int i = 1; i < MAX; i++) { if(frequency[i] > 0) { minimum = i; break; } } int answer = sum; for(int i = minimum; i < MAX; i++) { if(frequency[i] == 0) continue; if(i == minimum && frequency[i] == 1) continue; for(int p = 2; p <= i; p++) { if(i%p == 0) { int increase = minimum*(p - 1); int decrease = i - i/p; answer = min(answer, sum + increase - decrease); } } } cout << answer; return 0; } ================================================ FILE: Contests/Div 2 539/Explanations/Sasha and One More Name Explanation.txt ================================================ Given a palindrome string S, we must cut it into some k parts and then rearrange them to get a string R, such that R is a palindrome and R is not equal to S. We want to find the minimum such k. ------- Suppose - S has only one character, then only one palindromic string is possible. If S is odd palindrome, and has n - 1 same characters and one different character (central character), even then only one palindrome is possible. In these situations it is impossible to get a palindrome R =/= S. int is_cut_impossible(string &S) { int same = 0, length = S.size(); for(int i = 0; i < length; i++) { same += (S[i] == S[0]); } int not_possible = ( (length%2 == 0 && same == length ) || (length%2 == 1 && same >= length - 1) ); return not_possible; } --------- Let us suppose this is not the case. Firstly, let us check if it is possible with one cut. If we make only one cut, S[1, 2, ... i] S[i + 1, ... , n] And if we put the second part first, then it is like a cyclic rotations of S. We will check all cyclic rotations of S and check if any of those rotations yield a string R that is not equal to S and is also a palindrome. (Don't physically rotate the string. Just maintain two pointers.) for(int start = 1; start < S.size(); start++) { if(!is_equal(S, start) && is_palindrome(S, start)) { cout << "1\n"; return 0; } } ------------ If this is also not the case, then we will show that it is always possible with 2 cuts and 3 pieces. Let p be the smallest length prefix such that there are at least 2 distinct characters. This prefix will be of the form - xxxxxxxxxxA Let us look at the suffix of the same length p. It will be of the form Axxxxxxxxx. Clearly p =/= reverse(p) because and p = reverse( reverse(p) ) So we will interchange the prefix and suffix. The middle part is unchanged. The string R is a palindrome and R is not equal to S. ================================================ FILE: Contests/Div 2 539/Programs/Sasha and A Bit of Relax.cpp ================================================ #include #include using namespace std; const int MAX_N = (1 << 21), PARITY = 2; int frequency[MAX_N][PARITY]; int main() { int no_of_elements; cin >> no_of_elements; int prefix_xor = 0; long long good_subarrays = 0; memset(frequency, 0, sizeof(frequency)); frequency[0][0] = 1; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; prefix_xor ^= element; good_subarrays += (frequency[prefix_xor][i%2]); frequency[prefix_xor][i%2]++; } cout << good_subarrays; return 0; } ================================================ FILE: Contests/Div 2 539/Programs/Sasha and His Trip.cpp ================================================ #include using namespace std; int main() { int no_of_cities, capacity; cin >> no_of_cities >> capacity; int fuel; if(capacity >= no_of_cities - 1) { fuel = no_of_cities - 1; } else { fuel = capacity - 1; for(int i = 1; i <= no_of_cities - capacity; i++) fuel += i; } cout << fuel; return 0; } ================================================ FILE: Contests/Div 2 539/Programs/Sasha and Magnetic Machine.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; const int MAX = 105; vector frequency(MAX, 0); int sum = 0; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; frequency[element]++; sum += element; } int minimum; for(int i = 1; i < MAX; i++) { if(frequency[i] > 0) { minimum = i; break; } } int answer = sum; for(int i = minimum; i < MAX; i++) { if(frequency[i] == 0) continue; if(i == minimum && frequency[i] == 1) continue; for(int p = 2; p <= i; p++) { if(i%p == 0) { int increase = minimum*(p - 1); int decrease = i - i/p; answer = min(answer, sum + increase - decrease); } } } cout << answer; return 0; } ================================================ FILE: Contests/Div 2 539/Programs/Sasha and One More Name.cpp ================================================ #include #include using namespace std; void increment(int &i, int n) { i = (i + 1)%n; } void decrement(int &i, int n) { i = (i - 1 + n)%n; } int is_palindrome(string &S, int left) { int length = S.size(); int right = (left - 1); for(int forward_i = left, backward_i = right; forward_i != right; increment(forward_i, length), decrement(backward_i, length)) { if(S[forward_i] != S[backward_i]) return false; } return true; } int is_equal(string &S, int start) { for(int i = 0; i < S.size(); i++) { if(S[i] != S[(i + start)%S.size()]) { return false; } } return true; } int is_cut_impossible(string &S) { int same = 0, length = S.size(); for(int i = 0; i < length; i++) { same += (S[i] == S[0]); } int not_possible = ( (length%2 == 0 && same == length ) || (length%2 == 1 && same >= length - 1) ); return not_possible; } int main() { string S; cin >> S; if(is_cut_impossible(S)) { cout << "Impossible\n"; return 0; } for(int start = 1; start < S.size(); start++) { if(!is_equal(S, start) && is_palindrome(S, start)) { cout << "1\n"; return 0; } } cout << "2\n"; return 0; } ================================================ FILE: Contests/Div 2 546/Explanations/Nastya is Playing Computer Games Explanation.txt ================================================ Here is what is optimal. At the first hole, we will throw the stone into the neighbouring hole. Then go to the neighbouring hole and throw back to the first stone After this, whenever we visit any hole, throw the stones into the first hole. Rather than simulate the entire movement, there is a clean solution. Let us notice that we must visit each and every hole. The number of movements = Min{k - 1, n - k} + N - 1 We will throw a stone at every hole except the second hole where we throw 2 stones. Total stones thrown = N + 1 Total coins picked up = N The total number of moves is the sum of all 3. --------- int main() { int no_of_holes, position; cin >> no_of_holes >> position; int movement = min(position - 1, no_of_holes - position) + no_of_holes - 1; int stones_thrown = no_of_holes + 1; int coins_picked = no_of_holes; int total_moves = movement + stones_thrown + coins_picked; cout << total_moves; return 0; } ================================================ FILE: Contests/Div 2 546/Explanations/Nastya is Transposing Matrices Explanation.txt ================================================ Each element only moves across it's anti-diagonal. It never moves out of it. We can always make A = B if each of their anti-diagonals are equal. In a given anti-diagonal, (x + y) is invariant. -------- int main() { int rows, columns; cin >> rows >> columns; int max_diagonals = rows + columns; vector A_diagonals[max_diagonals + 5]; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int x; cin >> x; int diagonal_no = i + j; A_diagonals[diagonal_no].push_back(x); } } vector B_diagonals[max_diagonals + 5]; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int x; cin >> x; int diagonal_no = i + j; B_diagonals[diagonal_no].push_back(x); } } int possible = true; for(int i = 1; i <= max_diagonals; i++) { sort(all(A_diagonals[i])); sort(all(B_diagonals[i])); if(A_diagonals[i] != B_diagonals[i]) { possible = false; break; } } cout << (possible ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/Div 2 546/Programs/Nastya is Playing Computer Games.cpp ================================================ #include using namespace std; int main() { int no_of_holes, position; cin >> no_of_holes >> position; int movement = min(position - 1, no_of_holes - position) + no_of_holes - 1; int stones_thrown = no_of_holes + 1; int coins_picked = no_of_holes; int total_moves = movement + stones_thrown + coins_picked; cout << total_moves; return 0; } ================================================ FILE: Contests/Div 2 546/Programs/Nastya is Transposing Matrices.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int rows, columns; cin >> rows >> columns; int max_diagonals = rows + columns; vector A_diagonals[max_diagonals + 5]; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int x; cin >> x; int diagonal_no = i + j; A_diagonals[diagonal_no].push_back(x); } } vector B_diagonals[max_diagonals + 5]; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { int x; cin >> x; int diagonal_no = i + j; B_diagonals[diagonal_no].push_back(x); } } int possible = true; for(int i = 1; i <= max_diagonals; i++) { sort(all(A_diagonals[i])); sort(all(B_diagonals[i])); if(A_diagonals[i] != B_diagonals[i]) { possible = false; break; } } cout << (possible ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/Div 2 554/Explanations/Neko Does Math Explanation.txt ================================================ We want to minimize LCM(a + k, b + k) given a and b. LCM(a + k, b + k) = (a + k).(b + k)/gcd(a + k, b + k) = (a + k).(b + k)/gcd(b - a, b + k) Let us iterate over all divisors of (b - a) 1. Suppose d is a divisor of (b - a). We will find the smallest k, such that d = gcd(b - a, b + k) d also needs to be the gcd(a + k, b + k). So a = b (mod d) has to be satisfied 2. Then, we will find the LCM. 3. The key is iterating over the divisors of (b - a) ----- There is a special case when a = b. (b - a) will have no factors. k = 0 here ----- int main() { LL a, b; cin >> a >> b; vector factors; factorise(abs(b - a), factors); const LL oo = 1e18; LL minimum_lcm = (a == b ? a : oo), k = (a == b ? 0 : oo); for(int i = 0; i < factors.size(); i++) { int f = factors[i]; if(a%f != b%f) continue; LL to_add = (a%f == 0 ? 0 : f - a%f); LL lcm = ((a + to_add)*(b + to_add))/__gcd(a + to_add, b + to_add); if(a%f == 0) { if(lcm <= minimum_lcm) { minimum_lcm = lcm; k = to_add; } } else { if(lcm < minimum_lcm) { minimum_lcm = lcm; k = to_add; } } } cout << k; return 0; } ================================================ FILE: Contests/Div 2 554/Programs/Neko Does Math.cpp ================================================ #include #include #include using namespace std; typedef long long LL; LL lcm(LL a, LL b) { return (a*b)/__gcd(a, b); } void factorise(LL n, vector &F) { for(int i = 1; i*i <= n; i++) { if(n%i == 0) { F.push_back(i); if(i*i != n) F.push_back(n/i); } } } int main() { LL a, b; cin >> a >> b; vector factors; factorise(abs(b - a), factors); const LL oo = 1e18; LL minimum_lcm = (a == b ? a : oo), k = (a == b ? 0 : oo); for(int i = 0; i < factors.size(); i++) { int f = factors[i]; if(a%f != b%f) continue; LL to_add = (a%f == 0 ? 0 : f - a%f); LL lcm = ((a + to_add)*(b + to_add))/__gcd(a + to_add, b + to_add); if(a%f == 0) { if(lcm <= minimum_lcm) { minimum_lcm = lcm; k = to_add; } } else { if(lcm < minimum_lcm) { minimum_lcm = lcm; k = to_add; } } } cout << k; return 0; } ================================================ FILE: Contests/Div 2 562/Explanations/Good Triple Explanation.txt ================================================ We only need to check segments of length 9. https://www.cut-the-knot.org/proofs/2ColorsOnLine.shtml#solution ----- #include #include using namespace std; int is_good(string &S) { for(int x = 0; x < S.size(); x++) { for(int k = 1; x + 2*k < S.size(); k++) { if(S[x] == S[x + k] && S[x + k] == S[x + 2*k]) { return true; } } } return false; } int main() { string S; cin >> S; long long answer = 0; for(int left = 0; left < S.size(); left++) { for(int length = 2; length <= 9 && left + length - 1 < S.size(); length++) { string substring = S.substr(left, length); if(is_good(substring)) { int right = left + length - 1; //cout << "L = " << left << " R = " << right << " S = " << substring << "\n"; answer += (S.size() - 1) - (right - 1); break; } } } cout << answer; return 0; } ================================================ FILE: Contests/Div 2 562/Explanations/Pairs Explanation.txt ================================================ Let us take the first pair (x, y) One of these must be x and the other must be y ----- Let us fix one of these as x and collect all pairs which don't have x Now the problem is Given a graph, check if there 1 vertex that is connected to every other vertex ----- We can do this by checking the degree of each vertex. One of the degrees must be equal to the number of pairs ----- #include #include #include using namespace std; int range, no_of_pairs; vector x, y; int check_for_x(int n) { int no_of_remaining_pairs = 0; vector degree(range + 1, 0); for(int i = 1; i <= no_of_pairs; i++) { if(x[i] == n || y[i] == n) { continue; } degree[x[i]]++; degree[y[i]]++; no_of_remaining_pairs++; } for(int i = 1; i <= range; i++) { if(degree[i] == no_of_remaining_pairs) { return true; } } return false; } int main() { cin >> range >> no_of_pairs; x.resize(no_of_pairs + 1); y.resize(no_of_pairs + 1); for(int i = 1; i <= no_of_pairs; i++) { cin >> x[i] >> y[i]; } cout << (check_for_x(x[1]) || check_for_x(y[1]) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 562/Programs/Good Triple.cpp ================================================ #include #include using namespace std; int is_good(string &S) { for(int x = 0; x < S.size(); x++) { for(int k = 1; x + 2*k < S.size(); k++) { if(S[x] == S[x + k] && S[x + k] == S[x + 2*k]) { return true; } } } return false; } int main() { string S; cin >> S; long long answer = 0; for(int left = 0; left < S.size(); left++) { for(int length = 2; length <= 9 && left + length - 1 < S.size(); length++) { string substring = S.substr(left, length); if(is_good(substring)) { int right = left + length - 1; answer += (S.size() - 1) - (right - 1); break; } } } cout << answer; return 0; } ================================================ FILE: Contests/Div 2 562/Programs/Increasing by Modulo.cpp ================================================ #include #include using namespace std; int possible(int operations, int m, vector &A) { int minimum = 0; for(int i = 1; i < A.size(); i++) { if( (A[i] <= minimum && A[i] + operations >= minimum) || (A[i] > minimum && A[i] + operations - m >= minimum) ) continue; if(A[i] < minimum) return false; minimum = A[i]; } return true; } int main() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; int left = -1, right = m; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, m, A)) right = mid; else left = mid; } cout << right; return 0; } ================================================ FILE: Contests/Div 2 562/Programs/Pairs.cpp ================================================ #include #include #include using namespace std; int range, no_of_pairs; vector x, y; int check_for_x(int n) { int no_of_remaining_pairs = 0; vector degree(range + 1, 0); for(int i = 1; i <= no_of_pairs; i++) { if(x[i] == n || y[i] == n) { continue; } degree[x[i]]++; degree[y[i]]++; no_of_remaining_pairs++; } for(int i = 1; i <= range; i++) { if(degree[i] == no_of_remaining_pairs) { return true; } } return false; } int main() { cin >> range >> no_of_pairs; x.resize(no_of_pairs + 1); y.resize(no_of_pairs + 1); for(int i = 1; i <= no_of_pairs; i++) { cin >> x[i] >> y[i]; } cout << (check_for_x(x[1]) || check_for_x(y[1]) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 562/Rough Notes Link ================================================ https://1drv.ms/b/s!AoiWcyvzkQXVhzYKKX7Jt0H-xG4_ ================================================ FILE: Contests/Div 2 566/Explanations/Filing Shapes Explanation.txt ================================================ A 2x3 block can be tiled in two ways. 2 2 2 2 1 2 and 2 1 1 1 1 1 In whatever way we place the first block, the second block will have to be placed in the way above. This shows that we will always be filing blocks of 2x3 at a time. If n is odd, then nx3 cannot be tiled. If it is 3xn, then there are n/2 blocks of 2 if n is even. So the number of tilings is 2^{n/2} ---- #include using namespace std; int main() { int n; cin >> n; long long no_of_fillings = (n%2 == 1 ? 0 : (1LL << (n/2)) ); cout << no_of_fillings; return 0; } ================================================ FILE: Contests/Div 2 566/Explanations/Plus From Picture Explanation.txt ================================================ Let us precompute d(i, j), u(i, j), l(i, j) and r(i, j) which holds the number of consecutive stars from (i, j) in the down, up, left and right directions respectively. Now, a square is the center of a plus if it has at least 2 consecutive stars in each direction. Case 1 - No of Plus Centers is not 1 If the gird has more than 1 plus center or 0 plus center, then the answer is NO. ---- Case 2 - Nof Plus Centers is exactly 1 We need to check every single star on the grid. Let us say a star lies on (X, Y) and the center is on (Cx, Cy) ---- Case 2a - Cx = X or Cx = y That means (X, Y) lies on the same line as (Cx, Cy). We just need to check if it lies on the same plus sign. For this, there has to be an uninterrupted streak of stars in between (X, Y) and (Cx, Cy) Then, we will need to first find the direction of (X, Y) from (Cx, Cy) [Left, Up, Right, Down]. Suppose (X, Y) is to the left of (Cx, Cy), then we must check if X + left(Cx) - 1 <= Cx --- Case 2b - Cx != X and Cx != Y This means (X, Y) is not in the same line as (Cx, Cy) and the answer is no, regardless of the distance between them. --- #include #include const int MAX_N = 505; const char STAR = '*', EMPTY = '.'; char grid[MAX_N][MAX_N]; int up[MAX_N][MAX_N], down[MAX_N][MAX_N], left[MAX_N][MAX_N], right[MAX_N][MAX_N]; int main() { int height, width; scanf("%d %d", &height, &width); for(int i = 1; i <= height; i++) { scanf("%s", grid[i] + 1); } memset(up, 0, sizeof(up)); memset(left, 0, sizeof(left)); for(int i = 1; i <= height; i++) { for(int j = 1; j <= width; j++) { up[i][j] = (grid[i][j] == STAR ? 1 + up[i - 1][j] : 0); left[i][j] = (grid[i][j] == STAR ? 1 + left[i][j - 1] : 0); } } memset(down, 0, sizeof(down)); memset(right, 0, sizeof(right)); for(int i = height; i >= 1; i--) { for(int j = width; j >= 1; j--) { down[i][j] = (grid[i][j] == STAR ? 1 + down[i + 1][j] : 0); right[i][j] = (grid[i][j] == STAR ? 1 + right[i][j + 1] : 0); } } int no_of_plus_centers = 0, center_i = 0, center_j = 0; for(int i = 1; i <= height; i++) { for(int j = 1; j <= width; j++) { if(down[i][j] >= 2 && right[i][j] >= 2 && up[i][j] >= 2 && left[i][j] >= 2) { no_of_plus_centers++; center_i = i, center_j = j; } } } int possible = true; if(no_of_plus_centers != 1) { possible = false; } for(int i = 1; i <= height; i++) { for(int j = 1; j <= width; j++) { if(grid[i][j] == EMPTY) continue; if(i != center_i && j != center_j) { possible = false; } if(i < center_i && i + up[center_i][center_j] - 1 < center_i) { possible = false; } if(center_i < i && center_i + down[center_i][center_j] - 1 < i) { possible = false; } if(j < center_j && j + left[center_i][center_j] - 1 < center_j) { possible = false; } if(center_j < j && center_j + right[center_i][center_j] - 1 < j) { possible = false; } } } printf("%s", (possible ? "YES\n" : "NO\n")); return 0; } ================================================ FILE: Contests/Div 2 566/Programs/Filing Shapes.cpp ================================================ #include using namespace std; int main() { int n; cin >> n; long long no_of_fillings = (n%2 == 1 ? 0 : (1LL << (n/2)) ); cout << no_of_fillings; return 0; } ================================================ FILE: Contests/Div 2 566/Programs/Plus From Picture.cpp ================================================ #include #include const int MAX_N = 505; const char STAR = '*', EMPTY = '.'; char grid[MAX_N][MAX_N]; int up[MAX_N][MAX_N], down[MAX_N][MAX_N], left[MAX_N][MAX_N], right[MAX_N][MAX_N]; int main() { int height, width; scanf("%d %d", &height, &width); for(int i = 1; i <= height; i++) { scanf("%s", grid[i] + 1); } memset(up, 0, sizeof(up)); memset(left, 0, sizeof(left)); for(int i = 1; i <= height; i++) { for(int j = 1; j <= width; j++) { up[i][j] = (grid[i][j] == STAR ? 1 + up[i - 1][j] : 0); left[i][j] = (grid[i][j] == STAR ? 1 + left[i][j - 1] : 0); } } memset(down, 0, sizeof(down)); memset(right, 0, sizeof(right)); for(int i = height; i >= 1; i--) { for(int j = width; j >= 1; j--) { down[i][j] = (grid[i][j] == STAR ? 1 + down[i + 1][j] : 0); right[i][j] = (grid[i][j] == STAR ? 1 + right[i][j + 1] : 0); } } int no_of_plus_centers = 0, center_i = 0, center_j = 0; for(int i = 1; i <= height; i++) { for(int j = 1; j <= width; j++) { if(down[i][j] >= 2 && right[i][j] >= 2 && up[i][j] >= 2 && left[i][j] >= 2) { no_of_plus_centers++; center_i = i, center_j = j; } } } int possible = true; if(no_of_plus_centers != 1) { possible = false; } for(int i = 1; i <= height; i++) { for(int j = 1; j <= width; j++) { if(grid[i][j] == EMPTY) continue; if(i != center_i && j != center_j) { possible = false; } if(i < center_i && i + up[center_i][center_j] - 1 < center_i) { possible = false; } if(center_i < i && center_i + down[center_i][center_j] - 1 < i) { possible = false; } if(j < center_j && j + left[center_i][center_j] - 1 < center_j) { possible = false; } if(center_j < j && center_j + right[center_i][center_j] - 1 < j) { possible = false; } } } printf("%s", (possible ? "YES\n" : "NO\n")); return 0; } ================================================ FILE: Contests/Div 2 566/Rough Notes Link ================================================ https://1drv.ms/b/s!AoiWcyvzkQXVh1hzrJWSS_3VPtDD?e=ck92iL ================================================ FILE: Contests/Div 2 585/Explanations/Swap Letters Explanation.txt ================================================ Now, let us get the impossibility criteria clear. When is it not possible ? If the strings S and T are equal, it means whenever there is an A, it occurs twice and whenever there is a B, it occurs twice. If the number of As or number of Bs is odd, then there is no solution. ----- Now let us suppose that both the As and Bs are even. We will ignore all the positions (A, A) and (B, B) since they are already equal. Let us look at (A, B) If we have two (A, B) and (A, B). One operation can make both pairs equal. If we have two (B, A) and (B, A). One operation can also make both pairs equal. ---- Case 1 - The number of pairs (A, B) and (B, A) is even. Then we will pair up pairs of (A, B) and pairs of (B, A) and get our solution. ---- Case 2 - The number of pairs (A, B) and (B, A) is both odd. We will match as above until we have only one pair of (A, B) and (B, A) left. When we have only one left, we will do one swap on the same position on (B, A). Now, it becomes (A, B) Now we have two (A, B) pairs and we will do one operation to make the pairs equal ! --- Case 3 - One of the number of pairs (A, B) and (B,A) is odd. This will not happen since it means that A and B occur an odd number of times. We have already checked this condition when we were doing the impossibility check ---- int main() { int length; string S, T; cin >> length >> S >> T; const int NO_OF_ALPHABETS = 2, A = 0, B = 1; vector frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < S.size(); i++) { frequency[S[i] - 'a']++; } for(int i = 0; i < T.size(); i++) { frequency[T[i] - 'a']++; } if(frequency[A]%2 == 1 || frequency[B]%2 == 1) { cout << "-1\n"; return 0; } vector ABs; for(int i = 0; i < length; i++) { if(S[i] == 'a' && T[i] == 'b') { ABs.push_back(i + 1); } } vector BAs; for(int i = 0; i < length; i++) { if(S[i] == 'b' && T[i] == 'a') { BAs.push_back(i + 1); } } int no_of_operations = 0; if(ABs.size()%2 == 1 && BAs.size()%2 == 1) { no_of_operations = ABs.size()/2 + BAs.size()/2 + 2; } else if(ABs.size()%2 == 0 && BAs.size()%2 == 0) { no_of_operations = ABs.size()/2 + BAs.size()/2; } else //Redundant but just to be safe { cout << "-1\n"; return 0; } cout << no_of_operations << "\n"; for(int i = 0; i + 1 < ABs.size(); i += 2) { cout << ABs[i] << " " << ABs[i + 1] << "\n"; } for(int i = 0; i + 1 < BAs.size(); i += 2) { cout << BAs[i] << " " << BAs[i + 1] << "\n"; } if(ABs.size()%2 == 1 && BAs.size()%2 == 1) { int last_AB = ABs.size() - 1, last_BA = BAs.size() - 1; cout << ABs[last_AB] << " " << ABs[last_AB] << "\n"; cout << ABs[last_AB] << " " << BAs[last_BA] << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 585/Explanations/The Number of Products Explanation.txt ================================================ Let us use an elegant idea for this. Notice that the actual values of the elements do not matter - only the signs. Let us replace the positive numbers by 0 and the negative numbers by 1. Then let us maintain an array Sum, where Sum[i] holds the sum of the first i elements (mod 2). ----- If Sum[L - 1] = Sum[R], then it means that (Sum[R] - Sum[L - 1] = 0), which means that negative numbers occur an even number of times in the range. Every time in the sum vector, there are two elements which have the same value, they correspond to (L - 1, R) which gives us a segment(L, R) which has a positive product. ------ We want to count the ranges of the first x elements too so we will make Sum[0] = 0, even though A[0] does not exist. Now the number of segments that have positive products is simply C(zeros, 2) + C(ones, 2) - The number of ways to choose 2 zeroes and the number of ways to choose 2 ones in the sum vector. ---- The number of segments that give negative products is simply the total number of segments - positive product segments The total number of segments is C(N, 2) + N - Because we want to include singleton segments as well. ----- int main() { int no_of_elements; cin >> no_of_elements; vector sign(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; sign[i] = (x > 0 ? 0 : 1); } vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = (sum_till[i - 1] + sign[i])%2; } long long no_of_zeroes = 0, no_of_ones = 0; for(int i = 0; i <= no_of_elements; i++) { if(sum_till[i] == 0) { no_of_zeroes++; } else { no_of_ones++; } } long long no_of_positive_products = choose_2(no_of_zeroes) + choose_2(no_of_ones); long long no_of_negative_prodcuts = choose_2(no_of_elements) + no_of_elements - no_of_positive_products; cout << no_of_negative_prodcuts << " " << no_of_positive_products << "\n"; return 0; } ================================================ FILE: Contests/Div 2 585/Explanations/Yellow Cards Explanation ================================================ How do we minimise the number of eliminations ? We will try to use out as many cards as possible without eliminating a single player. This means we will first give every player 1 card less than the number of cards he is allowed. This is a1(k1 - 1) + a2(k2 - 1) If the number of yellow cards is lesser than this, we will not have a single elimination. If it is more than this, we will have one elimination for every card that we cross from this threshold. Of course, the number cannot be greater than (k1 + k2) as that is the total number of people. ------- int total_people = team_1 + team_2; int max_cards_without_elimination = team_1*(yellow_1 - 1) + team_2*(yellow_2 - 1); int minimum_eliminations, maximum_eliminations; if(max_cards_without_elimination >= yellow) { minimum_eliminations = 0; } else { minimum_eliminations = min(total_people, (yellow - max_cards_without_elimination)); } ------ Now, let us try to maximise the number of eliminations. First, let us assume without loss of generality that k1 < k2. (If not, we just swap (k1, k2) and (a1, a2)) ---- We will give as many yellow cards as possible to the players of team 1. This is K/k1. Of course, this number cannot be greater than a1. K = K - K/k1 Then, we will give as many yellow cards as possible to the second team. This number is also K/k2 and cannot be greater than a2. ----- maximum_eliminations = min(team_1, yellow/yellow_1); yellow -= maximum_eliminations*yellow_1; maximum_eliminations += min(team_2, yellow/yellow_2); ================================================ FILE: Contests/Div 2 585/Programs/Swap Letters.cpp ================================================ #include #include #include using namespace std; int main() { int length; string S, T; cin >> length >> S >> T; const int NO_OF_ALPHABETS = 2, A = 0, B = 1; vector frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < S.size(); i++) { frequency[S[i] - 'a']++; } for(int i = 0; i < T.size(); i++) { frequency[T[i] - 'a']++; } if(frequency[A]%2 == 1 || frequency[B]%2 == 1) { cout << "-1\n"; return 0; } vector ABs; for(int i = 0; i < length; i++) { if(S[i] == 'a' && T[i] == 'b') { ABs.push_back(i + 1); } } vector BAs; for(int i = 0; i < length; i++) { if(S[i] == 'b' && T[i] == 'a') { BAs.push_back(i + 1); } } int no_of_operations = 0; if(ABs.size()%2 == 1 && BAs.size()%2 == 1) { no_of_operations = ABs.size()/2 + BAs.size()/2 + 2; } else if(ABs.size()%2 == 0 && BAs.size()%2 == 0) { no_of_operations = ABs.size()/2 + BAs.size()/2; } else //Redundant but just to be safe { cout << "-1\n"; return 0; } cout << no_of_operations << "\n"; for(int i = 0; i + 1 < ABs.size(); i += 2) { cout << ABs[i] << " " << ABs[i + 1] << "\n"; } for(int i = 0; i + 1 < BAs.size(); i += 2) { cout << BAs[i] << " " << BAs[i + 1] << "\n"; } if(ABs.size()%2 == 1 && BAs.size()%2 == 1) { int last_AB = ABs.size() - 1, last_BA = BAs.size() - 1; cout << ABs[last_AB] << " " << ABs[last_AB] << "\n"; cout << ABs[last_AB] << " " << BAs[last_BA] << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 585/Programs/The Number of Products.cpp ================================================ #include #include using namespace std; long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { int no_of_elements; cin >> no_of_elements; vector sign(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { int x; cin >> x; sign[i] = (x > 0 ? 0 : 1); } vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = (sum_till[i - 1] + sign[i])%2; } long long no_of_zeroes = 0, no_of_ones = 0; for(int i = 0; i <= no_of_elements; i++) { if(sum_till[i] == 0) { no_of_zeroes++; } else { no_of_ones++; } } long long no_of_positive_products = choose_2(no_of_zeroes) + choose_2(no_of_ones); long long no_of_negative_prodcuts = choose_2(no_of_elements) + no_of_elements - no_of_positive_products; cout << no_of_negative_prodcuts << " " << no_of_positive_products << "\n"; return 0; } ================================================ FILE: Contests/Div 2 585/Programs/Yellow Cards.cpp ================================================ #include #include using namespace std; int main() { int team_1, yellow_1, team_2, yellow_2, yellow; cin >> team_1 >> team_2 >> yellow_1 >> yellow_2 >> yellow; int total_people = team_1 + team_2; int max_cards_without_elimination = team_1*(yellow_1 - 1) + team_2*(yellow_2 - 1); int minimum_eliminations, maximum_eliminations; if(max_cards_without_elimination >= yellow) { minimum_eliminations = 0; } else { minimum_eliminations = min(total_people, (yellow - max_cards_without_elimination)); } if(yellow_2 < yellow_1) { swap(yellow_1, yellow_2); swap(team_1, team_2); } maximum_eliminations = min(team_1, yellow/yellow_1); yellow -= maximum_eliminations*yellow_1; maximum_eliminations += min(team_2, yellow/yellow_2); cout << minimum_eliminations << " " << maximum_eliminations << "\n"; return 0; } ================================================ FILE: Contests/Div 2 585/Rough Notes ================================================ https://1drv.ms/b/s!AoiWcyvzkQXViGyGD7z-k0Yo5Rij?e=UMzxCH ================================================ FILE: Contests/Div 2 588/Explanations/Anadi and Domino Explanation.txt ================================================ 1. I didn't notice that there are only 7 vertices. 2. If there are < 7 vertices, then it is always possible. 3. If there are 7 vertices, then 2 vertices will have the same number. We will iterate over all pairs and calculate the number of lost edges in each case. It is better to use an adjacency matrix in this question rather than an adjacency vector. ----- int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; vector > has_edge(no_of_vertices + 1, vector (no_of_vertices + 1, false)); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; has_edge[u][v] = true; has_edge[v][u] = true; } int answer = 0; if(no_of_vertices < 7) { answer = no_of_edges; } else if(no_of_vertices == 7) { for(int i = 1; i <= no_of_vertices; i++) { for(int j = i + 1; j <= no_of_vertices; j++) { int lost_edges = 0; for(int k = 1; k <= no_of_vertices; k++) { if(has_edge[i][k] && has_edge[j][k]) { lost_edges++; } } answer = max(answer, no_of_edges - lost_edges); } } } cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 588/Explanations/Ania and Minimizing Explanation.txt ================================================ If it is a single digit number, then make it 0. In all other cases, leading 0s are not allowed. Make the first digit 1. Make as many 0s as possible starting from the leftmost position. ---- int main() { int length, no_of_steps; cin >> length >> no_of_steps; string N; cin >> N; for(int i = 0; i < length && no_of_steps > 0; i++) { if(i == 0) { if(length == 1) { if(N[i] != '0') { N[i] = '0'; no_of_steps--; } continue; } if(N[i] != '1') { N[i] = '1'; no_of_steps--; } continue; } if(N[i] == '0') { continue; } N[i] = '0'; no_of_steps--; } cout << N << "\n"; return 0; } ================================================ FILE: Contests/Div 2 588/Explanations/Dawid and Bags of Candies Explanation.txt ================================================ Just check all possibilities. We could also check if there is any sequence which sums upto S/2. ---- int main() { const int NO_OF_CANDIES = 4; vector A(NO_OF_CANDIES + 1, 0); for(int i = 1; i <= NO_OF_CANDIES; i++) cin >> A[i]; cout << ( ( (A[1] + A[2] == A[3] + A[4]) || (A[1] + A[3] == A[2] + A[4]) || (A[1] + A[4] == A[2] + A[3]) || (A[1] == A[2] + A[3] + A[4]) || (A[2] == A[1] + A[3] + A[4]) || (A[3] == A[1] + A[2] + A[4]) || (A[4] == A[1] + A[2] + A[3]) ) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 588/Explanations/Kamil and Making a Stream Explanation.txt ================================================ Now, let us notice one thing. GCD[1, p] is the gcd of [1, p] GCD[1, v] is the gcd of [1, v] where p is the parent of v. GCD[1, v] = gcd(GCD[1, P], A[v]) This means that the GCD of the child must divide the GCD of the parent. Although the value of A[i] is huge, this means that the distinct values of GCD in each vertex will not be many. There can be at most log(10^12) ~ 40 different values of GCD at each node. ---- 1. For each node, we will keep track of the frequency of all it's GCDs 2. We will get the answer by multiplying the value with the frequency. 3. Then, we will traverse to the child node. ----- void dfs(int v, map frequency) { visited[v] = true; map new_frequency; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { new_frequency[gcd(value[v], it->first)] += it->second; } new_frequency[value[v]]++; for(map :: iterator it = new_frequency.begin(); it != new_frequency.end(); it++) { answer += (it->first)*(it->second); answer %= MOD; } for(int i = 0; i < tree[v].size(); i++) { int child = tree[v][i]; if(visited[child]) { continue; } dfs(child, new_frequency); } } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1; i <= no_of_vertices; i++) { cin >> value[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } map frequency; dfs(1, frequency); cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 588/Explanations/Konrad and Company Evaluation Explanation.txt ================================================ In any counting question, it is always a good idea to iterate over the middle to count triplets. We want to count the number of vertices (u, v, w) that are connected. Let us iterate over the middle vertex v and count the number of incoming and outgoing edges. The total count is the sum of (indegree[v]*outdegree[v]) over all v. ----- We will draw a graph where u->v, if u < v How do we process updates when v becomes the largest vertex in the graph ? Although the question says salary increases by (n + i), ignore it. When v becomes the largest element in the graph, we need to reverse the direction of all edges going out of v and make them come into v. We have to correspondingly update the indegree and outdegree of v and all it's neighbours. ----- How do we do this in time ? At first, I maintained an adjacency set and for each neighbour of v, I erased it from v's adjacency set and inserted v into the adjacency set of it's neighbour. However, this adds an additional log factor. It is more efficient to simply use Adjacency Lists ! We will first insert v into the adjacency lists of all it's neighbours. Instead of erasing the elements of v one by one, we will just clear v's adjacency list all at once when we are done. v will anyway be empty and become a sink after we are done, so we can do this ! Before updating the edge, indegree and outdegree of a vertex, we will remove it's contribution from the sum and then add it's new contribution to the sum. It is easier to do this than to try to count the amount it's contribution has changed. ----- long long contribution(int v) { return indegree[v]*outdegree[v]; } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; if(u > v) { swap(u, v); } graph[u].push_back(v); //Reverse indegree[v]++; outdegree[u]++; } int no_of_queries; cin >> no_of_queries; long long no_of_paths = 0; for(int i = 1; i <= no_of_vertices; i++) { no_of_paths += contribution(i); } cout << no_of_paths << "\n"; for(int i = 1; i <= no_of_queries; i++) { int v; cin >> v; no_of_paths -= contribution(v); for(auto child_v : graph[v]) { //cout << "u = " << u << "\n"; no_of_paths -= contribution(child_v); //cout << "Old Contribution = " << contribution(u) << "\n"; indegree[child_v]--; outdegree[v]--; graph[child_v].push_back(v); indegree[v]++; outdegree[child_v]++; no_of_paths += contribution(child_v); //cout << "New Contribution = " << contribution(u) << "\n"; } graph[v].clear(); no_of_paths += contribution(v); cout << no_of_paths << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 588/Explanations/Marcin and Training Camp Explanation.txt ================================================ Fact - Every mask chosen M, either has frequency(M) > 1 or is a submask of another mask M' such that frequency(M') > 1 --- Proof - Let us say we have chosen bitmask M1 in our set. Either the frequency[M1] > 1 or there is another mask M2 such that M1 is a submask of M2. Then either frequency[M2] > 1 or there is another mask M3 such that M2 is a submask of M3. And so on. The number of masks chosen is finite so this cannot go on indefinitely. We will finally end up at mask Mk, such that frequency(Mk) > 1 M1 -> M2 -> .... -> Mk All the masks before Mk are submasks of Mk ---- How do we use this idea ? First, we will add all masks into our set, if the frequency(mask) > 1 --- vector distinct_masks; map selected; for(int i = 1; i <= no_of_students; i++) { if(mask_frequency[mask[i]] > 1 && !selected[mask[i]]) { distinct_masks.push_back(mask[i]); selected[mask[i]] = true; } } ---- Call the masks who's frequency > 1 'Master' masks. Now, we will go over the remaining masks. If there is any mask such that it is a submask of one of the 'Master' masks, then we will include it in our set as well. If there is some mask M1, such that it is not a submask of any of the 'Master' Masks, then it can't be included in our set. Suppose we choose M1, we have to choose M2 such that M1 is a submask of M2, and then M3 and so on. We will eventually end up at a mask Mk, such that there is no mask M(k + 1) such that Mk is a submask of M(k + 1). Also, M(k) has frequency = 1. Since, M1 is not a submask of any of the 'Master' masks. So, we cannot choose the entire sequence. The only masks we can choose are the masks which are submasks of the 'Master' Masks ----- for(int i = 1; i <= no_of_students; i++) { if(selected[mask[i]]) { continue; } for(int j = 0; j < distinct_masks.size(); j++) { if(is_submask(distinct_masks[j], mask[i])) { selected[mask[i]] = true; break; } } } ---- Then, we just add up the skills of all the players for(int i = 1; i <= no_of_students; i++) { if(selected[mask[i]]) { continue; } for(int j = 0; j < distinct_masks.size(); j++) { if(is_submask(distinct_masks[j], mask[i])) { selected[mask[i]] = true; break; } } } ================================================ FILE: Contests/Div 2 588/Programs/Anadi and Domino.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; vector > has_edge(no_of_vertices + 1, vector (no_of_vertices + 1, false)); for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; has_edge[u][v] = true; has_edge[v][u] = true; } int answer = 0; if(no_of_vertices < 7) { answer = no_of_edges; } else if(no_of_vertices == 7) { for(int i = 1; i <= no_of_vertices; i++) { for(int j = i + 1; j <= no_of_vertices; j++) { int lost_edges = 0; for(int k = 1; k <= no_of_vertices; k++) { if(has_edge[i][k] && has_edge[j][k]) { lost_edges++; } } answer = max(answer, no_of_edges - lost_edges); } } } cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 588/Programs/Ania and Minimizing.cpp ================================================ #include #include using namespace std; int main() { int length, no_of_steps; cin >> length >> no_of_steps; string N; cin >> N; for(int i = 0; i < length && no_of_steps > 0; i++) { if(i == 0) { if(length == 1) { if(N[i] != '0') { N[i] = '0'; no_of_steps--; } continue; } if(N[i] != '1') { N[i] = '1'; no_of_steps--; } continue; } if(N[i] == '0') { continue; } N[i] = '0'; no_of_steps--; } cout << N << "\n"; return 0; } ================================================ FILE: Contests/Div 2 588/Programs/Dawid and Bags of Candies.cpp ================================================ #include #include using namespace std; int main() { const int NO_OF_CANDIES = 4; vector A(NO_OF_CANDIES + 1, 0); for(int i = 1; i <= NO_OF_CANDIES; i++) cin >> A[i]; cout << ( ( (A[1] + A[2] == A[3] + A[4]) || (A[1] + A[3] == A[2] + A[4]) || (A[1] + A[4] == A[2] + A[3]) || (A[1] == A[2] + A[3] + A[4]) || (A[2] == A[1] + A[3] + A[4]) || (A[3] == A[1] + A[2] + A[4]) || (A[4] == A[1] + A[2] + A[3]) ) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Div 2 588/Programs/Kamil and Making a Stream.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e5 + 5, MOD = 1e9 + 7; long long answer; vector tree[MAX_N]; vector visited(MAX_N, 0); vector value(MAX_N, 0); long long gcd(long long x, long long y) { if(min(x, y) == 0) return max(x, y); else return gcd(max(x, y)%min(x, y), min(x,y)); } void dfs(int v, map frequency) { visited[v] = true; map new_frequency; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { new_frequency[gcd(value[v], it->first)] += it->second; } new_frequency[value[v]]++; for(map :: iterator it = new_frequency.begin(); it != new_frequency.end(); it++) { answer += (it->first)*(it->second); answer %= MOD; } for(int i = 0; i < tree[v].size(); i++) { int child = tree[v][i]; if(visited[child]) { continue; } dfs(child, new_frequency); } } int main() { int no_of_vertices; cin >> no_of_vertices; for(int i = 1; i <= no_of_vertices; i++) { cin >> value[i]; } int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(v); tree[v].push_back(u); } map frequency; dfs(1, frequency); cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 588/Programs/Konrad and Company Evaluation.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 1e5 + 5; vector indegree(MAX_N, 0), outdegree(MAX_N, 0); vector graph[MAX_N], transpose_graph[MAX_N]; long long contribution(int v) { return indegree[v]*outdegree[v]; } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; if(u > v) { swap(u, v); } graph[u].push_back(v); //Reverse indegree[v]++; outdegree[u]++; } int no_of_queries; cin >> no_of_queries; long long no_of_paths = 0; for(int i = 1; i <= no_of_vertices; i++) { no_of_paths += contribution(i); } cout << no_of_paths << "\n"; for(int i = 1; i <= no_of_queries; i++) { int v; cin >> v; no_of_paths -= contribution(v); for(auto child_v : graph[v]) { //cout << "u = " << u << "\n"; no_of_paths -= contribution(child_v); //cout << "Old Contribution = " << contribution(u) << "\n"; indegree[child_v]--; outdegree[v]--; graph[child_v].push_back(v); indegree[v]++; outdegree[child_v]++; no_of_paths += contribution(child_v); //cout << "New Contribution = " << contribution(u) << "\n"; } graph[v].clear(); no_of_paths += contribution(v); cout << no_of_paths << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 588/Programs/Marcin and Training Camp.cpp ================================================ #include #include #include #include #include #include using namespace std; int is_submask(long long mask, long long submask) { return ((mask&submask) == submask); } int main() { int no_of_students; cin >> no_of_students; map mask_frequency; vector mask(no_of_students + 1); for(int i = 1; i <= no_of_students; i++) { cin >> mask[i]; mask_frequency[mask[i]]++; } vector skill_level(no_of_students + 1, 0); for(int i = 1; i <= no_of_students; i++) { cin >> skill_level[i]; } vector distinct_masks; map selected; for(int i = 1; i <= no_of_students; i++) { if(mask_frequency[mask[i]] > 1 && !selected[mask[i]]) { distinct_masks.push_back(mask[i]); selected[mask[i]] = true; } } for(int i = 1; i <= no_of_students; i++) { if(selected[mask[i]]) { continue; } for(int j = 0; j < distinct_masks.size(); j++) { if(is_submask(distinct_masks[j], mask[i])) { selected[mask[i]] = true; break; } } } long long best_max_skill = 0; for(int i = 1; i <= no_of_students; i++) { if(selected[mask[i]]) { best_max_skill += skill_level[i]; } } cout << best_max_skill << "\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Explanations/Complete Tripartite Explanation.txt ================================================ Two vertices in the same group do not have any edge. Let us pick a vertex and put all vertices that don't share an edge with it in 1 group We will try to make 3 groups like this 1. We have to ensure that there are exactly 3 groups, no more and no less 2. We have to ensure that for each vertex v, all it's neighbours are in different groups 3. For each vertex v, the number of it's neighbours must be equal to the size of the other 2 groups This ensures that v has an edge with every vertex in the other two groups ------ int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; set graph[no_of_vertices + 1]; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].insert(v); graph[v].insert(u); } const int NO_OF_GROUPS = 3; vector group(no_of_vertices + 1, 0); vector group_sizes(NO_OF_GROUPS + 1, 0); for(int g = 1; g <= NO_OF_GROUPS; g++) { int first = 0; for(first = 1; first <= no_of_vertices && group[first] != 0; first++); if(first == no_of_vertices + 1) { cout << "-1\n"; return 0; } group[first] = g; for(int second = 1; second <= no_of_vertices; second++) { if(graph[first].find(second) == graph[first].end()) { group[second] = g; group_sizes[g]++; } } } for(int v = 1; v <= no_of_vertices; v++) { if(group[v] == 0) { cout << "-1\n"; return 0; } } for(int v = 1; v <= no_of_vertices; v++) { for(auto it = graph[v].begin(); it != graph[v].end(); it++) { int u = *it; if(group[u] == group[v]) { cout << "-1\n"; return 0; } } } for(int v = 1; v <= no_of_vertices; v++) { int other_groups = group_sizes[1] + group_sizes[2] + group_sizes[3] - group_sizes[group[v]]; if(graph[v].size() != other_groups) { cout << "-1\n"; return 0; } } for(int v = 1; v <= no_of_vertices; v++) { cout << group[v] << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Explanations/Distinct Digits Explanation.txt ================================================ We can iterate over every integer in between L and R and check if each integer has distinct digits. We will never have to go too far to find an integer with all distinct digits or find that it doesn't exist. We can check if N is made up of all distinct digits by capturing the frequency of all it's digits and checking if each of their frequencies is <= 1 ----- #include #include using namespace std; int distinct_digits(int n) { vector frequency(10, 0); while(n > 0) { if(frequency[n%10] > 0) return false; frequency[n%10]++; n /= 10; } return true; } int main() { int left, right; cin >> left >> right; for(int i = left; i <= right; i++) { if(distinct_digits(i)) { cout << i << endl; return 0; } } cout << "-1\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Explanations/Filing the Grid Explanation.txt ================================================ How do we check if a tiling is not possible ? Suppose R[i] = x and it means that the first x-columns of the i-th row must be black and the (x + 1)-th column must be white. We will check if C[x + 1] >= i, If this is the case, then in the (x + 1)-th column, we have to make more than i-rows black. This causes a contradiction. We will check this condition for every row and every column ------- for(int i = 1; i <= rows; i++) { int first_empty_column = blocked_cells_row[i] + 1; if(blocked_cells_column[first_empty_column] >= i) { cout << "0\n"; return 0; } } for(int j = 1; j <= columns; j++) { int first_empty_row = blocked_cells_column[j] + 1; if(blocked_cells_row[first_empty_row] >= j) { cout << "0\n"; return 0; } } ----- A question that might arise here is that if R[i] = x, we are checking if the (x + 1)-th cell is allowed to be white (as it should). But what if we are forced to make one of the first x columns of the i-th row white ? Well, if the y-th column of the i-th row must be white, then it means that C[y] = i - 1, We will encounter this case, when we are checking the columns. ------ 1. For every row R[i] = X, we will check if we can colour the cell(i, X + 1), white. 1a. This is possible if C[X + 1] < i 2. For every column C[j] = Y, we will check if we can colour the cell(Y + 1, j) white 2a. This is possible if R[Y + 1] < j ----- A cell(i, j) is blocked if we are forced to colour it either black or white and we do not have a choice in colouring it. If R[j] = x, then the first X rows of column j must be black and the (X + 1)-th row of column j must be white. These (X + 1) cells are forced. If C[i] = y, then the first Y rows of column i must be black and the (Y + 1)-th column of row i must be white. These (Y + 1) cells are forced. ----- Then, we will visit each cell and check if it is 'free' or 'forced'. Cell (i, j) is forced if R[j] + 1 >= i or if C[i] + 1 >= j ----- LL free_cells = 0; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(i <= blocked_cells_column[j] + 1 || j <= blocked_cells_row[i] + 1) { continue; } else { free_cells++; } } } ----- Suppose, there are F free cells. The answer is 2^F because each of the F free cells can be either black or white. We must calculate 2^F using binary exponentiation. ================================================ FILE: Contests/Div 2 589/Explanations/Primes and Multiplication Explanation.txt ================================================ Whenever we are asked to calculate a long sum or product, we must try to group the summands and try to calculate the contribution of each prime factor ---- What is the contribution of prime factor P ? We will encounter P as many times as [N/P] We will encounter P^2 as many times as [N/P^2] We will encounter P^3 as many times as [N/P^3] and so on The exponent of P is [N/P] + [N/P^2] + ... We basically want to find the number of 0s in n! in base p. This is a famous problem. ---- We can factor the number in O(root(n)) time into it's prime factors. void factorise(LL n, vector &P) { for(LL i = 2; i*i <= n; i++) { if(n%i == 0) { P.push_back(i); while(n%i == 0) { n /= i; } } } if(n > 1) { P.push_back(n); } } ---- For each of it's prime factors, we will calculate the exponent to which it is raised. We need to be careful with how we evaluate this. We need to avoid overflow. So, the number of multiples of p till n = n/p The number of multiples of p^2 till n = n/p^2 We might not be able to square p if it's too large. Instead, we will divide and bring down n. We will make n = n/p ---- LL get_exponent(LL n, LL p) { LL exponent = 0; LL temp_p = p; while(n > 0) { exponent += n/p; n /= p; } return exponent; } ---- Then, we will simply multiply all of them in the answer int main() { LL x, n; cin >> x >> n; vector prime_factors; factorise(x, prime_factors); const LL MOD = 1e9 + 7; LL answer = 1; for(int i = 0; i < prime_factors.size(); i++) { LL exponent = get_exponent(n, prime_factors[i]); answer *= power_mod(prime_factors[i], exponent, MOD); answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Programs/Complete Tripartite.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; set graph[no_of_vertices + 1]; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].insert(v); graph[v].insert(u); } const int NO_OF_GROUPS = 3; vector group(no_of_vertices + 1, 0); vector group_sizes(NO_OF_GROUPS + 1, 0); for(int g = 1; g <= NO_OF_GROUPS; g++) { int first = 0; for(first = 1; first <= no_of_vertices && group[first] != 0; first++); if(first == no_of_vertices + 1) { cout << "-1\n"; return 0; } group[first] = g; for(int second = 1; second <= no_of_vertices; second++) { if(graph[first].find(second) == graph[first].end()) { group[second] = g; group_sizes[g]++; } } } for(int v = 1; v <= no_of_vertices; v++) { if(group[v] == 0) { cout << "-1\n"; return 0; } } for(int v = 1; v <= no_of_vertices; v++) { for(auto it = graph[v].begin(); it != graph[v].end(); it++) { int u = *it; if(group[u] == group[v]) { cout << "-1\n"; return 0; } } } for(int v = 1; v <= no_of_vertices; v++) { int other_groups = group_sizes[1] + group_sizes[2] + group_sizes[3] - group_sizes[group[v]]; if(graph[v].size() != other_groups) { cout << "-1\n"; return 0; } } for(int v = 1; v <= no_of_vertices; v++) { cout << group[v] << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Programs/Distinct Digits.cpp ================================================ #include #include using namespace std; int distinct_digits(int n) { vector frequency(10, 0); while(n > 0) { if(frequency[n%10] > 0) return false; frequency[n%10]++; n /= 10; } return true; } int main() { int left, right; cin >> left >> right; for(int i = left; i <= right; i++) { if(distinct_digits(i)) { cout << i << endl; return 0; } } cout << "-1\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Programs/Filing the Grid.cpp ================================================ #include #include typedef long long LL; using namespace std; LL power_mod(LL n, LL power, LL mod) { LL result = 1; while(power) { if(power%2 == 1) result = (result*n)%mod; n = (n*n)%mod; power = power >> 1; } return result; } int main() { int rows, columns; cin >> rows >> columns; vector blocked_cells_row(rows + 3, 0); for(int i = 1; i <= rows; i++) cin >> blocked_cells_row[i]; vector blocked_cells_column(columns + 3, 0); for(int i = 1; i <= columns; i++) cin >> blocked_cells_column[i]; for(int i = 1; i <= rows; i++) { int first_empty_column = blocked_cells_row[i] + 1; if(blocked_cells_column[first_empty_column] >= i) { cout << "0\n"; return 0; } } for(int j = 1; j <= columns; j++) { int first_empty_row = blocked_cells_column[j] + 1; if(blocked_cells_row[first_empty_row] >= j) { cout << "0\n"; return 0; } } LL free_cells = 0; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(i <= blocked_cells_column[j] + 1 || j <= blocked_cells_row[i] + 1) { continue; } else { free_cells++; } } } const LL MOD = 1e9 + 7; LL answer = power_mod(2, free_cells, MOD); cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 589/Programs/Primes and Multiplication.cpp ================================================ #include #include typedef long long LL; using namespace std; LL get_exponent(LL n, LL p) { LL exponent = 0; LL temp_p = p; while(n > 0) { exponent += n/p; n /= p; } return exponent; } void factorise(LL n, vector &P) { for(LL i = 2; i*i <= n; i++) { if(n%i == 0) { P.push_back(i); while(n%i == 0) { n /= i; } } } if(n > 1) { P.push_back(n); } } LL power_mod(LL n, LL power, LL mod) { LL result = 1; while(power) { if(power%2 == 1) result = (result*n)%mod; n = (n*n)%mod; power = power >> 1; } return result; } int main() { LL x, n; cin >> x >> n; vector prime_factors; factorise(x, prime_factors); const LL MOD = 1e9 + 7; LL answer = 1; for(int i = 0; i < prime_factors.size(); i++) { LL exponent = get_exponent(n, prime_factors[i]); answer *= power_mod(prime_factors[i], exponent, MOD); answer %= MOD; } cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 2 592/Explanations/Minimizing Difference Explanation.txt ================================================ Quora Editorial - https://qr.ae/TWoHA1 Let us consider the sorted array. The difference between the minimum and maximum element is initially (A[n] - A[1]). --- In order to reduce this difference, we have to make some prefix of length i equal and some suffix of length j equal. For example, suppose we want to make the difference = (A[j] - A[i]). Then, we need to make the entire prefix of length i = A[i] This takes (i*A[i] - Sum_till[i]) operations. We also want to make the suffix of length j = A[j] This takes (Sum_from[j] - (n - j + 1)*A[j]) --- Now, we have to somehow iterate over all possible values of the prefix = L and all possible values of the suffix = R, provided that the number of operations we use is <= K. Key Observation - If the prefix = L and the Suffix = R, then one of {L, R} will be from the array. Proof - 1. Suppose we have more elements in the prefix than in the suffix, then we can get [L - 1, R - 1], with the same (or lesser) number of operations. We can also get [L - 2, R - 2] and so on till L or R (or both) becomes equal to some array element A[i]. 2. Suppose we have more elements in the suffix than in the prefix, then we can get [L + 1, R + 1], with the same (or lesser) number of operations. Similarly, we can get [L + 2, R + 2] and so on till L or R becomes equal to some array element in A. ---- This is a very important observation as it simplifies our job greatly. Here, is what we will do. 1. Iterate i = 1 to n, and make the prefix = A[i] 2. This will make us use (i*A[i] - Sum_till[i]) operations. 3. With our remaining operations, we need to find the best value of R (which may be from the array or not). 4. The maximum value of R is A[n] and the minimum value of R is A[i]. We will binary search for the best possible value of R. ----- Let us maintain the invariant that it is not possible to make the suffix of the array = L1 and it is always possible to make the suffix of the array = R1. We will do binary search and get Mid = (L1 + R1)/2. How many operations do we need to make the suffix of the array = Mid ? Let A[k] be the first element in A that is >= Mid. Then, the number of operations used is (Sum_from[k] - (n - k + 1)*Mid) If these number of operations are allowed, then we will set R2 = Mid If these number of operations are not allowed, then we will set L2 = Mid We will continue doing this till (R2 - L2) > 1 When R2 - L2 = 1, then R2 is the number we want as it is the first integer such that we can make some suffix = R2 ---- for(int i = 1; i <= no_of_elements; i++) { long long operations_used_in_prefix = i*A[i] - sum_till[i]; if(operations_used_in_prefix > no_of_operations) { continue; } //Maintain the invariant that it is always possible to make the suffix of the array = Right long long left = A[i], right = A[no_of_elements]; while(right - left > 1) { long long mid = (right + left)/2; int pos = upper_bound(A.begin(), A.end(), mid - 1) - A.begin(); //Make suffix = mid long long operations_used_in_suffix = sum_from[pos] - (no_of_elements - pos + 1)*mid; if(operations_used_in_prefix + operations_used_in_suffix <= no_of_operations) { right = mid; } else { left = mid; } } best_minimum = min(best_minimum, right - A[i]); } ----- Now, this is not enough. We have to do the same thing in the other direction as well. 1. Iterate from i = n to i = 1 2. Make the entire suffix of the array = A[i] 3. Then, binary search the best value of L such that some prefix of the array can be = L using the remaining operations. We will use a similar binary search idea as mentioned above. --- for(int i = no_of_elements; i >= 1; i--) { long long operations_used_in_suffix = sum_from[i] - (no_of_elements - i + 1)*A[i]; if(operations_used_in_suffix > no_of_operations) { continue; } //Maintain the invariant that it is always possible to make the prefix of array = Left long long left = A[1], right = A[i]; while(right - left > 1) { long long mid = (left + right)/2; int pos = upper_bound(A.begin(), A.end(), mid) - A.begin() - 1; //Make Prefix = Mid long long operations_used_in_prefix = pos*mid - sum_till[pos]; if(operations_used_in_suffix + operations_used_in_prefix <= no_of_operations) { left = mid; } else { right = mid; } } best_minimum = min(best_minimum, A[i] - left); } ----- Of course, we need to check if it is possible to make the entire array = x, If this is possible it is always better to make x from some element from the array. ---- for(int i = 1; i <= no_of_elements; i++) { if(i*A[i] - sum_till[i] + sum_from[i + 1] - (no_of_elements - i)*A[i] <= no_of_operations) { best_minimum = 0; break; } } ----- ================================================ FILE: Contests/Div 2 592/Explanations/Pens and Pencils Explanation.txt ================================================ We can calculate the number of pens and pencils required and see if it fits into the bag. The number of pens is ceil(a/c) and the number of pencils is ceil(b/d). --- int ceil(int n, int d) { return (n/d + (n%d != 0)); } void solve() { int lectures, practicals, pen_limit, pencil_limit, bag_capacity; cin >> lectures >> practicals >> pen_limit >> pencil_limit >> bag_capacity; int pens_required = ceil(lectures, pen_limit); int pencils_required = ceil(practicals, pencil_limit); if(pens_required + pencils_required <= bag_capacity) { cout << pens_required << " " << pencils_required << "\n"; } else { cout << "-1\n"; } } ================================================ FILE: Contests/Div 2 592/Explanations/Rooms and Staircases Explanation.txt ================================================ If there is a 1, then we can switch over and travel all the rooms all over again. It is 2*max(i, N - i + 1) We will choose the best ladder. --- void solve() { int length; string S; cin >> length >> S; int no_of_rooms = length; for(int i = 0; i < S.size(); i++) { if(S[i] == '1') { no_of_rooms = max(no_of_rooms, 2*max(i + 1, length - i)); } } cout << no_of_rooms << "\n"; } ================================================ FILE: Contests/Div 2 592/Explanations/The Football Season Explanation.txt ================================================ Let us suppose that the number of wins, draws and losses is w, d and l and the number of points in each case is W, D and 0 respectively. We know that, w + d + l = N w.W + d.D = P ---- We have 2 equations. From the second equation, we can iterate over the value of w and determine d and from w and d, we can determine l. My first approach was to brute force w from 1 to 10^6 and then to brute force d from 1 to 10^6. If it is not possible in either case, then declare it is never possible. This limit 10^6 was arbitrarily chosen. However, this solution was accepted. --- A couple of crucial observations - w(D) = d(W) This observation is simple but extremely elegant and powerful. If we win D matches, it is the same as drawing W matches. --- Second Observation - Wins and Draws are NOT symmetric. D < W always ---- Suppose we have drawn more than W matches Then, we can reduce the number of draws by W and increase the number of wins by D. The number of 'total matches drawn or won' changes by (D - W). This is negative. This reduces the number of matches. ---- Since, we have a sum bound on w and d i.e. w + d + l = N, Let us try to minimise the sum of (w + d) If d >= W, then reduce d by W and increase w by D. This reduces the total number of matches, keeping the points the same. --- This proves that if a solution is possible, then it is possible with the number of draws in [0, W - 1]. --- We will iterate over the number of draws in this range. For each i in this range, we will check if a triplet is possible. --- Suppose we reduce the number of wins by D and increase the number of draws by W. Then the number of matches increases by (W - D). Since W > D, this increases the number of matches. Suppose we reduce the number of draws by W and increase the number of wins by D, then the number of matches decreases by (D - W). Since W > D, this decreases the number of matches. We want to minimise the number of matches. So, we will always increase the wins by D and reduce the draws by W. If there is some solution, there will also be a solution where the number of draws is < W. This is the crucial insight. After that, we just have to iterate over the number of draws in [0, W - 1] --- #include using namespace std; int main() { long long no_of_games, points, win_point, draw_point; cin >> no_of_games >> points >> win_point >> draw_point; int limit = win_point - 1; for(int draws = 0; points >= draws*draw_point && draws <= limit; draws++) { if( (points - draws*draw_point)%win_point == 0) { long long wins = (points - draws*draw_point)/win_point; long long losses = no_of_games - wins - draws; if(losses >= 0) { cout << wins << " " << draws << " " << losses; return 0; } } } cout << "-1\n"; return 0; } ================================================ FILE: Contests/Div 2 592/Programs/Minimizing Difference.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; long long no_of_operations; cin >> no_of_elements >> no_of_operations; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; } vector sum_from(no_of_elements + 2, 0); for(int i = no_of_elements; i >= 1; i--) { sum_from[i] = sum_from[i + 1] + A[i]; } long long best_minimum = A[no_of_elements] - A[1]; for(int i = 1; i <= no_of_elements; i++) { if(i*A[i] - sum_till[i] + sum_from[i + 1] - (no_of_elements - i)*A[i] <= no_of_operations) { best_minimum = 0; break; } } for(int i = 1; i <= no_of_elements; i++) { long long operations_used_in_prefix = i*A[i] - sum_till[i]; if(operations_used_in_prefix > no_of_operations) { continue; } //Maintain the invariant that it is always possible to make the suffix of the array = Right long long left = A[i], right = A[no_of_elements]; while(right - left > 1) { long long mid = (right + left)/2; int pos = upper_bound(A.begin(), A.end(), mid - 1) - A.begin(); //Make suffix = mid long long operations_used_in_suffix = sum_from[pos] - (no_of_elements - pos + 1)*mid; if(operations_used_in_prefix + operations_used_in_suffix <= no_of_operations) { right = mid; } else { left = mid; } } best_minimum = min(best_minimum, right - A[i]); } for(int i = no_of_elements; i >= 1; i--) { long long operations_used_in_suffix = sum_from[i] - (no_of_elements - i + 1)*A[i]; if(operations_used_in_suffix > no_of_operations) { continue; } //Maintain the invariant that it is always possible to make the prefix of array = Left long long left = A[1], right = A[i]; while(right - left > 1) { long long mid = (left + right)/2; int pos = upper_bound(A.begin(), A.end(), mid) - A.begin() - 1; //Make Prefix = Mid long long operations_used_in_prefix = pos*mid - sum_till[pos]; if(operations_used_in_suffix + operations_used_in_prefix <= no_of_operations) { left = mid; } else { right = mid; } } best_minimum = min(best_minimum, A[i] - left); } cout << best_minimum << "\n"; return 0; } ================================================ FILE: Contests/Div 2 592/Programs/Pens and Pencils.cpp ================================================ #include #include using namespace std; int ceil(int n, int d) { return (n/d + (n%d != 0)); } void solve() { int lectures, practicals, pen_limit, pencil_limit, bag_capacity; cin >> lectures >> practicals >> pen_limit >> pencil_limit >> bag_capacity; int pens_required = ceil(lectures, pen_limit); int pencils_required = ceil(practicals, pencil_limit); if(pens_required + pencils_required <= bag_capacity) { cout << pens_required << " " << pencils_required << "\n"; } else { cout << "-1\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 592/Programs/Rooms and Staircases.cpp ================================================ #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; int no_of_rooms = length; for(int i = 0; i < S.size(); i++) { if(S[i] == '1') { no_of_rooms = max(no_of_rooms, 2*max(i + 1, length - i)); } } cout << no_of_rooms << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 592/Programs/The Football Season.cpp ================================================ #include using namespace std; int main() { long long no_of_games, points, win_point, draw_point; cin >> no_of_games >> points >> win_point >> draw_point; int limit = win_point - 1; for(int draws = 0; points >= draws*draw_point && draws <= limit; draws++) { if( (points - draws*draw_point)%win_point == 0) { long long wins = (points - draws*draw_point)/win_point; long long losses = no_of_games - wins - draws; if(losses >= 0) { cout << wins << " " << draws << " " << losses; return 0; } } } cout << "-1\n"; return 0; } ================================================ FILE: Contests/Div 2 596/Explanations/Forgetting Things Explanation.txt ================================================ If the prefixes are same, then we can just put 1 and 2. If the prefixes differ by 1, then we can put 9 and 0. If one prefix is 9 and the oether is 1, then we can put 9 and 00 --- int main() { int old_left, new_left; cin >> old_left >> new_left; if(old_left == new_left) { cout << old_left << "1 " << new_left << "2\n"; } else if(old_left + 1 == new_left) { cout << old_left << "9 " << new_left << "0\n"; } else if(old_left == 9 && new_left == 1) { cout << old_left << "9 " << new_left << "00\n"; } else { cout << "-1\n"; } return 0; } ================================================ FILE: Contests/Div 2 596/Explanations/P Binary Explanation.txt ================================================ To check if it is possible to write n in i bits, (n - ip) must have exactly i bits set in it's binary representation. ----- (n - ip) will not be more than a 32 bit number in the given range so we only need to check from 1 to 32. If it is possible for any value of i, it is the minimum. If it is not possible for any i in [0, 32], it's not possible. ----- int main() { long long n, p; cin >> n >> p; int answer = 100; for(int i = 0; i < 32; i++) { if(__builtin_popcount(n - i*p) > i || (n - i*p) < i) { continue; } answer = i; break; } cout << (answer == 100 ? -1 : answer); return 0; } ================================================ FILE: Contests/Div 2 596/Explanations/Power Products Explanation.txt ================================================ Let us look at N in terms of it's prime factorisation. Suppose N = p1^a1 p2^a2 ... pk^ak To make it a perfect power of M, all the exponents have to be a multiple of M. Let us define the 'complement' of an integer N as an integer C such that N.C is a perfect power of M. --- For Example, N = 2^3 3^2 5^1 And we want to make it a perfect 3rd power, then the complement C = 3 5^2 --- We will replace each exponent by it's remainder (mod M) as that is all that matters. Suppose, we had N = 2^5 3^2 5^3, then we will replace N = 2^2 3 --- We will perform a scan through the array. For each integer A[i], we will replace all it's exponent. Then, we will add the frequency of it's complement to the left and add it to our answer. --- int main() { sieve(); int no_of_elements, power; scanf("%d %d", &no_of_elements, &power); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); vector > factors; get_factors(factors, A[i]); for(int f = 0; f < factors.size(); f++) { int p = factors[f].first; int exponent = (factors[f].second)%power; for(int e = 1; e <= exponent; e++) { A[i] *= p; } } } long long answer = 0; map frequency; for(int i = 1; i <= no_of_elements; i++) { long long complement = get_complement(A[i], power); answer += frequency[complement]; frequency[A[i]]++; } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 596/Explanations/TV Subscriptions Explanation.txt ================================================ We only need to keep track of the leftmost occurence of each element. We will maintain two pointers - L and R to keep a sliding window. When we increment R, we will check if the leftmost occurence of A[R] is < L, This would mean that A[R] is a distinct element in the current segment [L, R]. Otherwise, it would not. Although there are 2 for loops, the time complexity is O(n) since each of the N elements is visited at most twice by each of the pointers. We will find out the minimum number of distinct elements of all segments of length K. --- using namespace std; void solve() { int no_of_elements, no_of_distinct_elements, segment_length; cin >> no_of_elements >> no_of_distinct_elements >> segment_length; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int distinct_elements = 0; map last_occurence; for(int i = 1; i <= segment_length; i++) { if(last_occurence[A[i]] == 0) { distinct_elements++; } last_occurence[A[i]] = i; } int minimum_distinct_elements = distinct_elements; for(int i = segment_length + 1; i <= no_of_elements; i++) { int left = i - segment_length, right = i; int left_element = A[left], right_element = A[right]; if(last_occurence[left_element] == left) { distinct_elements--; } if(last_occurence[right_element] <= left) { distinct_elements++; } last_occurence[right_element] = i; minimum_distinct_elements = min(minimum_distinct_elements, distinct_elements); } cout << minimum_distinct_elements << "\n"; } ================================================ FILE: Contests/Div 2 596/Programs/Forgetting Things.cpp ================================================ #include using namespace std; int main() { int old_left, new_left; cin >> old_left >> new_left; if(old_left == new_left) { cout << old_left << "1 " << new_left << "2\n"; } else if(old_left + 1 == new_left) { cout << old_left << "9 " << new_left << "0\n"; } else if(old_left == 9 && new_left == 1) { cout << old_left << "9 " << new_left << "00\n"; } else { cout << "-1\n"; } return 0; } ================================================ FILE: Contests/Div 2 596/Programs/P-Binary.cpp ================================================ #include #include #include using namespace std; int main() { long long n, p; cin >> n >> p; int answer = 100; for(int i = 0; i < 32; i++) { if(__builtin_popcount(n - i*p) > i || (n - i*p) < i) { continue; } answer = i; break; } cout << (answer == 100 ? -1 : answer); return 0; } ================================================ FILE: Contests/Div 2 596/Programs/Power Products.cpp ================================================ #include #include #include #include using namespace std; const int N = 1e5 + 5; const long long oo = 1e10; vector primes; void sieve() { vector is_prime(N + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i < N; i++) { if(is_prime[i]) { primes.push_back(i); } for(int j = 0; j < primes.size() && i*primes[j] < N; j++) { is_prime[i*primes[j]] = false; if(primes[j]%i == 0) { break; } } } } void get_factors(vector > &F, long long &n) { for(int i = 0; n > 1 && i < primes.size(); i++) { if(n%primes[i] != 0) { continue; } int exponent = 0; while(n%primes[i] == 0) { n /= primes[i]; exponent++; } F.push_back(make_pair(primes[i], exponent)); } if(n > 1) { F.push_back(make_pair(n, 1)); n /= n; } } long long get_complement(long long n, long long power) { long long complement = 1; for(int i = 0; n > 1 && i < primes.size(); i++) { if(primes[i]*primes[i] > n) { break; } if(n%primes[i] != 0) { continue; } int exponent = 0; while(n%primes[i] == 0) { n /= primes[i]; exponent++; } while(exponent%power != 0) { exponent++; if(complement > oo/primes[i]) { complement = -1; return -1; } else { complement *= primes[i]; } } } if(n == 1) { return complement; } int exponent = 1; while(exponent%power != 0) { exponent++; if(complement > oo/n) { complement = -1; return -1; } else { complement *= n; } } return complement; } int main() { sieve(); int no_of_elements, power; scanf("%d %d", &no_of_elements, &power); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); vector > factors; get_factors(factors, A[i]); for(int f = 0; f < factors.size(); f++) { int p = factors[f].first; int exponent = (factors[f].second)%power; for(int e = 1; e <= exponent; e++) { A[i] *= p; } } } long long answer = 0; map frequency; for(int i = 1; i <= no_of_elements; i++) { long long complement = get_complement(A[i], power); answer += frequency[complement]; frequency[A[i]]++; } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Div 2 596/Programs/TV Subscriptions.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements, no_of_distinct_elements, segment_length; cin >> no_of_elements >> no_of_distinct_elements >> segment_length; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int distinct_elements = 0; map last_occurence; for(int i = 1; i <= segment_length; i++) { if(last_occurence[A[i]] == 0) { distinct_elements++; } last_occurence[A[i]] = i; } int minimum_distinct_elements = distinct_elements; for(int i = segment_length + 1; i <= no_of_elements; i++) { int left = i - segment_length, right = i; int left_element = A[left], right_element = A[right]; if(last_occurence[left_element] == left) { distinct_elements--; } if(last_occurence[right_element] <= left) { distinct_elements++; } last_occurence[right_element] = i; minimum_distinct_elements = min(minimum_distinct_elements, distinct_elements); } cout << minimum_distinct_elements << "\n"; } int main() { int no_of_tests; cin >> no_of_tests; while(no_of_tests--) { solve(); } return 0; } ================================================ FILE: Contests/Div 2 597/Explanations/Constanze's Machine Explanation.txt ================================================ If the string contains any 'w' or 'm', then the answer is 0. Otherwise, Let f(i) be the number of ways of making the first i letters. If, S[i, i - 1] = 'nn', then f(i) = f(i - 1) + f(i - 2) since the last letter can either be 'n' and appended at the end of a string of length (i - 1) or it can be 'm' and appended at the end of a string of length (i - 2) If we treat it like 'n', then we can get f(i - 1) strings of length (i - 1) and put an 'n' at the end. If we treat it like 'm', then we can get f(i - 2) strings of length(i - 2) and put an 'm' at the end. Hence, f(i) = f(i - 1) + f(i - 2) --- Similarly, if S[i, i - 1] = 'uu', then f(i) = f(i - 1) + f(i - 2) --- Otherwise, f(i) = f(i - 1), as there is only one choice for the last letter and it can be appended at the end of a string of length (i - 1) letters. --- The answer is f(N) --- int main() { string S; cin >> S; for(int i = 0; i < S.size(); i++) { if(S[i] == 'm' || S[i] == 'w') { cout << "0\n"; return 0; } } const int MOD = 1e9 + 7; vector no_of_strings_till(S.size() + 1, 0); no_of_strings_till[0] = 1; for(int i = 1; i < S.size(); i++) { if(S[i] == 'n' && S[i - 1] == 'n') { if(i == 1) { no_of_strings_till[i] = 2; continue; } no_of_strings_till[i] = (no_of_strings_till[i - 1] + no_of_strings_till[i - 2])%MOD; } else if(S[i] == 'u' && S[i - 1] == 'u') { if(i == 1) { no_of_strings_till[i] = 2; continue; } no_of_strings_till[i] = (no_of_strings_till[i - 1] + no_of_strings_till[i - 2])%MOD; } else { no_of_strings_till[i] = no_of_strings_till[i - 1]; } } cout << no_of_strings_till[S.size() - 1]; return 0; } ================================================ FILE: Contests/Div 2 597/Explanations/Good Ol Number Colouring Explanation.txt ================================================ Essentially an integer n is coloured white if it is possible to write n = Xa + Yb, where x and Y are any positive integers. If gcd(a, b) = 1, then there is always a positive integer L, such that it is possible to reach all integers >= L by a linear combination of a and b. If (a, b) are coprime, then the number of integers not coloured white is finite. Otherwise, it is infinite. ----- void solve() { int a, b; cin >> a >> b; cout << (__gcd(a, b) == 1 ? "Finite\n" : "Infinite\n"); } ================================================ FILE: Contests/Div 2 597/Explanations/Restricted RPS Explanation.txt ================================================ We will do linear passes over the string. Pass 1 - We will try to be greedy. Whatever move is played, we will try to make the winning move. If not, we will mark it as 'X'. For example, if the 5th move is 'Rocks', then we will try to play a 'Paper'. If we have no Paper, we will put 'X'. This maximises the number of wins as every move has been made for a win. ----- Pass 2 - Now, we will fill up the 'X's with any available move. It doesn't really matter ----- We need to check if the total number of wins is the number desired. ----- void solve() { int total, papers, scissors, rocks; cin >> total >> rocks >> papers >> scissors; string moves; cin >> moves; int wins = 0; string answer; for(int i = 0; i < moves.size(); i++) { switch(moves[i]) { case 'R':{ if(papers > 0) { wins++; papers--; answer += 'P'; break; } else { answer += 'X'; break; } } case 'P':{ if(scissors > 0) { wins++; scissors--; answer += 'S'; break; } else { answer += 'X'; break; } } case 'S':{ if(rocks > 0) { wins++; rocks--; answer += 'R'; break; } else { answer += 'X'; break; } } } } if(2*wins < total) { cout << "No\n"; return; } for(int i = 0; i < answer.size(); i++) { if(answer[i] != 'X') { continue; } if(rocks > 0) { answer[i] = 'R'; rocks--; continue; } if(papers > 0) { answer[i] = 'P'; papers--; continue; } if(scissors > 0) { answer[i] = 'S'; scissors--; continue; } } cout << "Yes\n"; cout << answer << "\n"; } ================================================ FILE: Contests/Div 2 597/Programs/Constanze's Machine.cpp ================================================ #include #include #include using namespace std; int main() { string S; cin >> S; for(int i = 0; i < S.size(); i++) { if(S[i] == 'm' || S[i] == 'w') { cout << "0\n"; return 0; } } const int MOD = 1e9 + 7; vector no_of_strings_till(S.size() + 1, 0); no_of_strings_till[0] = 1; for(int i = 1; i < S.size(); i++) { if(S[i] == 'n' && S[i - 1] == 'n') { if(i == 1) { no_of_strings_till[i] = 2; continue; } no_of_strings_till[i] = (no_of_strings_till[i - 1] + no_of_strings_till[i - 2])%MOD; } else if(S[i] == 'u' && S[i - 1] == 'u') { if(i == 1) { no_of_strings_till[i] = 2; continue; } no_of_strings_till[i] = (no_of_strings_till[i - 1] + no_of_strings_till[i - 2])%MOD; } else { no_of_strings_till[i] = no_of_strings_till[i - 1]; } } cout << no_of_strings_till[S.size() - 1]; return 0; } ================================================ FILE: Contests/Div 2 597/Programs/Good Ol Number Colouring.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int a, b; cin >> a >> b; cout << (__gcd(a, b) == 1 ? "Finite\n" : "Infinite\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 597/Programs/Restricted RPS.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int total, papers, scissors, rocks; cin >> total >> rocks >> papers >> scissors; string moves; cin >> moves; int wins = 0; string answer; for(int i = 0; i < moves.size(); i++) { switch(moves[i]) { case 'R':{ if(papers > 0) { wins++; papers--; answer += 'P'; break; } else { answer += 'X'; break; } } case 'P':{ if(scissors > 0) { wins++; scissors--; answer += 'S'; break; } else { answer += 'X'; break; } } case 'S':{ if(rocks > 0) { wins++; rocks--; answer += 'R'; break; } else { answer += 'X'; break; } } } } if(2*wins < total) { cout << "No\n"; return; } for(int i = 0; i < answer.size(); i++) { if(answer[i] != 'X') { continue; } if(rocks > 0) { answer[i] = 'R'; rocks--; continue; } if(papers > 0) { answer[i] = 'P'; papers--; continue; } if(scissors > 0) { answer[i] = 'S'; scissors--; continue; } } cout << "Yes\n"; cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 599/Explanations/Character Swap Explanation.txt ================================================ If the frequency of any alphabet in both S and T is not even, then it is not possible. The reason is that the same character should appear twice - Once at S[i], and then at T[i]. One important realisation is that we are allowed to swap (S[i] with T[i] also) - A swap of (i, i) is allowed. I did not realise this till I read the editorial. Now, let us try to solve it in O(N^2). ----- Whenever we find a pair (S[i], T[i]) that are not equal, we will look for a (j > i) such that either 1. S[i] = S[j] Then, swap (S[j], T[i]). This will ensure i has the correct position. 2. S[i] = T[j] Then, swap (S[j], T[j]) first. Then, we get Case 1 above with S[i] = S[j]. One more swap suffices. ---- We will use at most 2 swaps for every position and it can always be done in 2n steps :) --- void solve() { int length; cin >> length; string S, T; cin >> S >> T; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < length; i++) { frequency[S[i] - 'a']++; frequency[T[i] - 'a']++; } for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency[i]%2 == 1) { cout << "No\n"; return; } } vector > swaps; for(int i = 0; i < length; i++) { if(S[i] == T[i]) { continue; } for(int j = i + 1; j < length; j++) { if(S[j] == T[j]) { continue; } if(S[i] == T[j]) { swap(S[j], T[j]); swaps.push_back(make_pair(j, j)); } if(S[i] == S[j]) { swap(S[j], T[i]); swaps.push_back(make_pair(j, i)); break; } } } cout << "Yes\n"; cout << swaps.size() << "\n"; for(int i = 0; i < swaps.size(); i++) { cout << swaps[i].first + 1 << " " << swaps[i].second + 1 << "\n"; } } ================================================ FILE: Contests/Div 2 599/Explanations/Maximum Square Explanation.txt ================================================ I did this in O(n^2) time. Suppose we want to check if it is possible to make a square of length L. Then, we need at least L planks of height >= L --- void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int max_length = 0; for(int l = 1; l <= no_of_elements; l++) { int planks = 0; for(int i = 1; i <= no_of_elements; i++) { planks += (A[i] >= l); } if(planks >= l) max_length = max(max_length, l); } cout << max_length << "\n"; } --- Now, we can also do this in O(N Log N) time. We can solve this by binary search. If we can get a square of length L, then we can also get (L - 1). If we can't get L, we can't get (L + 1). This is a monotonic function and can be binary searched. --- We can also do this in O(N Log N) time by sorting the list in descending order. The answer is = min{A[i], i} at each step. For the first i values, A[i] is the minimum so far. If A[i] > i, then we can make a square of length i since all the planks so far are >= A[i] > i If i > A[i], then we can make a square of length A[i] since all the planks are height >= A[i] and we have already seen i > A[i] planks. So, a square of length A[i] is possible. We need the maximum of all these values. for(int i = 1; i <= N; i++) { answer = max(answer, min(A[i], i)); } --- ================================================ FILE: Contests/Div 2 599/Explanations/Tile Painting Explanation.txt ================================================ Bezout's Identity tells us that there are always two integers (A, B) such that Ax + By = gcd(x, y) We can reach any multiple of G as well. To reach, KG, we need to multiply A and B by K. --- In general, if we are given a set S of integers - {A_1, A_2, ... , A_k} Then, we can reach any multiple of gcd(S) Whatever colour we choose for x, we have to choose the same colour for (x + G) too --- Now, coming to our specific question. Let N = p1^a1 p2^a2 ... pk^ak Now, the gcd of any two primes is (p1, p2) = 1 So, if N has at least 2 primes in it's prime factorisation, then we can reach every integer as (Ap1 + Bp2) Otherwise, N has only 1 prime factor p. We can choose colours for [1, p] (p + 1) has to be the same colour as 1, (p + 2) as 2 and so on So there are p colours totally. We need to handle the special case of N = 1 seperately. --- void factorise(long long n, vector &F) { for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { F.push_back(i); while(n%i == 0) { n /= i; } } } if(n > 1) { F.push_back(n); } } int main() { long long n; cin >> n; vector prime_divisors; factorise(n, prime_divisors); cout << (prime_divisors.size() > 1 || n == 1 ? 1 : prime_divisors[0]) << "\n"; return 0; } ================================================ FILE: Contests/Div 2 599/Programs/Character Swap.cpp ================================================ #include #include #include #include using namespace std; void solve() { int length; cin >> length; string S, T; cin >> S >> T; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < length; i++) { frequency[S[i] - 'a']++; frequency[T[i] - 'a']++; } for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency[i]%2 == 1) { cout << "No\n"; return; } } vector > swaps; for(int i = 0; i < length; i++) { if(S[i] == T[i]) { continue; } for(int j = i + 1; j < length; j++) { if(S[j] == T[j]) { continue; } if(S[i] == T[j]) { swap(S[j], T[j]); swaps.push_back(make_pair(j, j)); } if(S[i] == S[j]) { swap(S[j], T[i]); swaps.push_back(make_pair(j, i)); break; } } } cout << "Yes\n"; cout << swaps.size() << "\n"; for(int i = 0; i < swaps.size(); i++) { cout << swaps[i].first + 1 << " " << swaps[i].second + 1 << "\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 599/Programs/Maximum Square.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int max_length = 0; for(int l = 1; l <= no_of_elements; l++) { int planks = 0; for(int i = 1; i <= no_of_elements; i++) { planks += (A[i] >= l); } if(planks >= l) max_length = max(max_length, l); } cout << max_length << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 599/Programs/Tile Painting.cpp ================================================ #include #include using namespace std; void factorise(long long n, vector &F) { for(long long i = 2; i*i <= n; i++) { if(n%i == 0) { F.push_back(i); while(n%i == 0) { n /= i; } } } if(n > 1) { F.push_back(n); } } int main() { long long n; cin >> n; vector prime_divisors; factorise(n, prime_divisors); cout << (prime_divisors.size() > 1 || n == 1 ? 1 : prime_divisors[0]) << "\n"; return 0; } ================================================ FILE: Contests/Div 2 600/Explanations/Antenna Coverage Explanation.txt.txt ================================================ Let f(i) be the minimum antennas needed to cover [0, i] For each antenna, find the range [L, R] where it is active For each antenna, calculate the cost of extending it to it's right so that it covers the point i. Be careful to only cover extensions to the right. We could extend an antenna to it's left and add f(i - 1), but it is never optimal. ------ #include #include using namespace std; int main() { int no_of_elements, range; cin >> no_of_elements >> range; vector > A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i].first >> A[i].second; } vector minimum_cost(range + 1); for(int i = 0; i <= range; i++) { minimum_cost[i] = (i); for(int j = 0; j < no_of_elements; j++) { int left = max(0, A[j].first - A[j].second), right = min(range, A[j].first + A[j].second); if(left <= i && i <= right) { minimum_cost[i] = (i == 0 ? 0 : minimum_cost[i - 1]); break; } if(right < i) { int additional_cost = i - right; int previous_antenna = max(0, left - additional_cost - 1); minimum_cost[i] = min(minimum_cost[i], additional_cost + minimum_cost[previous_antenna]); } } } cout << minimum_cost[range] << "\n"; return 0; } ================================================ FILE: Contests/Div 2 600/Explanations/Harmonious Graph Explanation.txt ================================================ 1. Let us look at each Connected Component seperately. 2. For each connected component, let us look at the minimum L and the maximum R. 3. Now, we have x segments - [L, R]. 4. We will sort these segments by their Left Borders and keep track of the right most point we have met so far. If L_i < R, then it means we need to make another connection. 5. We have to update R = max(R, R_i) at every step. If R is the rightmost point we have had so far and L_i < R, then it means L_i should be reachable from wherever we were able to reach R. This is the reason we will make 1 connection per component where L_i < R. Now the entire component [L_i, R_i] is reachable to the current segment. ------ struct component { int minimum, maximum; component() { minimum = oo, maximum = 0; }; component(int Min, int Max) { minimum = Min, maximum = Max; } }; void dfs(int v, component &C) { if(visited[v]) { return; } visited[v] = true; C.minimum = min(C.minimum, v); C.maximum = max(C.maximum, v); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; dfs(child, C); } } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } vector components; for(int i = 1; i <= no_of_vertices; i++) { if(!visited[i]) { component this_component; dfs(i, this_component); components.push_back(this_component); } } //Components are already sorted by their Lefts int right_most_point = 0; int no_of_connections = 0; for(int i = 0; i < components.size(); i++) { if(components[i].minimum < right_most_point) { no_of_connections++; } right_most_point = max(right_most_point, components[i].maximum); } cout << no_of_connections << "\n"; return 0; } ================================================ FILE: Contests/Div 2 600/Explanations/Silly Mistakes Explanation.txt ================================================ This problem has a lot of implementation. Let us maximise the number of partitions even though it is not required as it is the easiest thing to do. We will keep track of the following things in segment [L, R] - 1. The number of people in 2. The state of the people there - (Entry/Exit) 3. The exact people who made an appearance in the day - This is required to ensure that nobody enters, exits and then enters again on the same day. We will end a day as soon as the number of people becomes 0. At the end of the day, we will clear the vector containing the exact people who came in that day. Then, we will set the flag that indicates the list of people who came on that day to 0 again. (We need to do this. We can't set all the flags of everyone to 0 everyday as that would be O(n^2)) ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_N = 1e6 + 5; int possible = true; int no_of_people = 0; vector no_of_entries_today(MAX_N, 0); vector people_today; vector has_entered(1e6 + 5, 0); vector day_events; for(int left = 1, right = 1; right <= no_of_elements; right++) { if(A[right] > 0) { has_entered[A[right]] = true; no_of_people++; people_today.push_back(A[right]); no_of_entries_today[A[right]]++; if(no_of_entries_today[A[right]] > 1) { possible = false; break; } } else if(A[right] < 0) { if(!has_entered[-A[right]]) { possible = false; break; } has_entered[-A[right]] = false; no_of_people--; } if(no_of_people == 0) { day_events.push_back(right - (left - 1)); left = right + 1; for(int p = 0; p < people_today.size(); p++) { no_of_entries_today[people_today[p]] = 0; } people_today.clear(); } } if(no_of_people > 0) { possible = false; } if(!possible) { cout << "-1\n"; return 0; } cout << day_events.size() << "\n"; for(int i = 0; i < day_events.size(); i++) { cout << day_events[i] << " "; } return 0; } ================================================ FILE: Contests/Div 2 600/Explanations/Single Push Explanation.txt ================================================ Let us keep track of the number of segments we have to change. Let (k[i] = B[i] - A[i]) If (k[i] != k[i - 1]), then it means that we must begin a new segment starting at i. Also, A[0] = B[0] = 0 for convenience. We also need to ensure that k is never negative. ------ void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } int segments = 0; for(int i = 1; i <= no_of_elements; i++) { if(A[i] == B[i]) { continue; } if(A[i] > B[i]) { segments = 100000000; break; } if(B[i] - A[i] != B[i - 1] - A[i - 1]) { segments++; } } cout << (segments > 1 ? "No\n" : "Yes\n"); } ================================================ FILE: Contests/Div 2 600/Explanations/Sweets Eating Explanation.txt ================================================ Here is the strategy - If we eat the first i sweets, we want to minimise the penalty against each sweet. So, we will eat the sweets with the highest penalty first - We will eat the sweets in descending order. Now, suppose f(i) is the penalty of eating the first i sweets. We will eat sweets [i, i - k] on day 1. All sweets [1, i - k - 1] will get pushed back by 1 day. This means that the penalty against sweet j becomes (d + 1)*p(j) from d*p(j). The total penalty increases by sum [i - k]. So, f(i) = (Sum[i] - Sum[i - k]) + f(i - k) + Sum[i - k] We need to handle the base case of i <= k i.e. - When there is only one day seperately. ------ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, max_per_day; cin >> no_of_elements >> max_per_day; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; } vector penalty(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { long long day_1 = 0, remaining_days = 0; if(i <= max_per_day) { day_1 = sum_till[i]; } else { day_1 = sum_till[i] - sum_till[i - max_per_day]; remaining_days = penalty[i - max_per_day] + sum_till[i - max_per_day]; } penalty[i] = day_1 + remaining_days; } for(int i = 1; i <= no_of_elements; i++) { cout << penalty[i] << " "; } return 0; }   ================================================ FILE: Contests/Div 2 600/Programs/Antenna Coverage.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, range; cin >> no_of_elements >> range; vector > A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { cin >> A[i].first >> A[i].second; } vector minimum_cost(range + 1); for(int i = 0; i <= range; i++) { minimum_cost[i] = (i); for(int j = 0; j < no_of_elements; j++) { int left = max(0, A[j].first - A[j].second), right = min(range, A[j].first + A[j].second); if(left <= i && i <= right) { minimum_cost[i] = (i == 0 ? 0 : minimum_cost[i - 1]); break; } if(right < i) { int additional_cost = i - right; int previous_antenna = max(0, left - additional_cost - 1); minimum_cost[i] = min(minimum_cost[i], additional_cost + minimum_cost[previous_antenna]); } } } cout << minimum_cost[range] << "\n"; return 0; } ================================================ FILE: Contests/Div 2 600/Programs/Harmonious Graph.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 2e5 + 5, oo = 1e9; vector graph[MAX_N]; vector visited(MAX_N, false); struct component { int minimum, maximum; component() { minimum = oo, maximum = 0; }; component(int Min, int Max) { minimum = Min, maximum = Max; } }; void dfs(int v, component &C) { if(visited[v]) { return; } visited[v] = true; C.minimum = min(C.minimum, v); C.maximum = max(C.maximum, v); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; dfs(child, C); } } int main() { int no_of_vertices, no_of_edges; cin >> no_of_vertices >> no_of_edges; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; graph[u].push_back(v); graph[v].push_back(u); } vector components; for(int i = 1; i <= no_of_vertices; i++) { if(!visited[i]) { component this_component; dfs(i, this_component); components.push_back(this_component); } } //Components are already sorted by their Lefts int right_most_point = 0; int no_of_connections = 0; for(int i = 0; i < components.size(); i++) { if(components[i].minimum < right_most_point) { no_of_connections++; } right_most_point = max(right_most_point, components[i].maximum); } cout << no_of_connections << "\n"; return 0; } ================================================ FILE: Contests/Div 2 600/Programs/Silly Mistakes.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int MAX_N = 1e6 + 5; int possible = true; int no_of_people = 0; vector no_of_entries_today(MAX_N, 0); vector people_today; vector has_entered(1e6 + 5, 0); vector day_events; for(int left = 1, right = 1; right <= no_of_elements; right++) { if(A[right] > 0) { has_entered[A[right]] = true; no_of_people++; people_today.push_back(A[right]); no_of_entries_today[A[right]]++; if(no_of_entries_today[A[right]] > 1) { possible = false; break; } } else if(A[right] < 0) { if(!has_entered[-A[right]]) { possible = false; break; } has_entered[-A[right]] = false; no_of_people--; } if(no_of_people == 0) { day_events.push_back(right - (left - 1)); left = right + 1; for(int p = 0; p < people_today.size(); p++) { no_of_entries_today[people_today[p]] = 0; } people_today.clear(); } } if(no_of_people > 0) { possible = false; } if(!possible) { cout << "-1\n"; return 0; } cout << day_events.size() << "\n"; for(int i = 0; i < day_events.size(); i++) { cout << day_events[i] << " "; } return 0; } ================================================ FILE: Contests/Div 2 600/Programs/Single Push.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> B[i]; } int segments = 0; for(int i = 1; i <= no_of_elements; i++) { if(A[i] == B[i]) { continue; } if(A[i] > B[i]) { segments = 100; break; } if(B[i] - A[i] != B[i - 1] - A[i - 1]) { segments++; } } cout << (segments > 1 ? "No\n" : "Yes\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 2 600/Programs/Sweets Eating.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, max_per_day; cin >> no_of_elements >> max_per_day; vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } sort(all(A)); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_till[i] = sum_till[i - 1] + A[i]; } vector penalty(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { long long day_1 = 0, remaining_days = 0; if(i <= max_per_day) { day_1 = sum_till[i]; } else { day_1 = sum_till[i] - sum_till[i - max_per_day]; remaining_days = penalty[i - max_per_day] + sum_till[i - max_per_day]; } penalty[i] = day_1 + remaining_days; } for(int i = 1; i <= no_of_elements; i++) { cout << penalty[i] << " "; } return 0; }   ================================================ FILE: Contests/Div 2 608/Programs/Shwarma Tent.cpp ================================================ #include #include using namespace std; int max_3(int a, int b, int c) { return max(a, max(b, c)); } int main() { const int oo = 1e9; int no_of_students, school_x, school_y; cin >> no_of_students >> school_x >> school_y; vector X(no_of_students + 1); vector Y(no_of_students + 1); int up = 0, right = 0, down = 0, left = 0; for(int i = 1; i <= no_of_students; i++) { int x, y; cin >> x >> y; up += (y > school_y); down += (y < school_y); left += (x < school_x); right += (x > school_x); } if(up >= max_3(left, right, down)) { cout << up << "\n"; cout << school_x << " " << school_y + 1 << "\n"; } else if(left >= max_3(up, down, right)) { cout << left << "\n"; cout << school_x - 1 << " " << school_y << "\n"; } else if(right >= max_3(up, down, left)) { cout << right << "\n"; cout << school_x + 1 << " " << school_y << "\n"; } else if(down >= max_3(left, right, up)) { cout << down << "\n"; cout << school_x << " " << school_y - 1 << "\n"; } return 0; } ================================================ FILE: Contests/Div 2 85/Explanation/Petya and Divisors Explanation.txt ================================================ The main insight of this question is to use an array, last_index_multiple(d) = i, if the index of the last multiple of d is i. I remember a similar idea used where I had to find the lexicographically smallest array such that it was all pairwise coprime. Even there, the idea was to factorise and check if it was used. Here we take in every number n, factorise it. And check if the last index of any factor is >= i - y. If yes, then we don't count it. Else we do. --------------------------------------------------- #include #include using namespace std; int main() { int no_of_queries; scanf("%d", &no_of_queries); const int MAX_N = 1e5 + 15; vector last_multiple_index(MAX_N, 0); for(int i = 1; i <= no_of_queries; i++) { int number, y; scanf("%d %d", &number, &y); int last_index = i - y; int divisors = 0, bad_divisors = 0; for(int d = 1; d*d <= number; d++) { if(number%d == 0) { divisors += (d*d == number ? 1 : 2); if(last_multiple_index[d] >= last_index) { bad_divisors++; } if(d*d != number && last_multiple_index[number/d] >= last_index) { bad_divisors++; } last_multiple_index[d] = last_multiple_index[number/d] = i; } } int good_divisors = divisors - bad_divisors; printf("%d\n", good_divisors); } return 0; } ================================================ FILE: Contests/Div 2 85/Explanation/Petya and Inequiations Explanation.txt ================================================ Try to find the maximum value of the sum of squares - Turns out this happens when all the elements except one = 1, and the last element = Y - (n - 1) Let us say there is another arrangement where we have at most (n - 2) ones. I will show that you can always do better by making it (n - 1) 1's Choose the largest and second largest element - Let it be a and b. Without loss of generality, a < b, and a > b > 1 Sum of squares = a^2 + b^2 = X Now, let us make the two numbers 1, (b + a - 1) Keeping the sum invariant. Let us examine the sum of squares now 1^2 + (b + a - 1)^2 = 1 + a^2 + b^2 + 1 - 2a - 2b + 2ab = (a^2 + b^2) + 2(1 + ab - a - b) = X + 2( 1 + ab - a - b) Now, all I have to do is show that (1 + ab - a - b) is positive When a and b are two positive integers > 1, their product is always greater than their sum. xy - x - y + 1 = x(y - 1) - y + 1 = (x - 1)(y - 1), both terms are positive, so (x - 1)(y - 1) > 0 This completes the proof --------- Now, get the maximum possible sum of squares for a given sum = 1^2 + 1^2 + ... + (Y - (N - 1))^2 Test cases I missed - What happens when N > Y. -------------------------------------------------------------------------------------------------------- int main() { int n, sum_limit; long long square_sum_lower_bound; scanf("%d %I64d %d", &n, &square_sum_lower_bound, &sum_limit); long long largest_element = sum_limit - (n - 1); long long max_square_sum = (n - 1) + largest_element*largest_element; if(max_square_sum < square_sum_lower_bound || n > sum_limit) { printf("-1\n"); return 0; } for(int i = 1; i <= n; i++) printf("%I64d\n", (i == n ? largest_element : 1)); return 0; } ================================================ FILE: Contests/Div 2 85/Explanation/Petya and Strings Explanation.txt ================================================ Little Petya loves presents. His mum bought him two strings of the same size for his birthday. The strings consist of uppercase and lowercase Latin letters. Now Petya wants to compare those two strings lexicographically. The letters' case does not matter, that is an uppercase letter is considered equivalent to the corresponding lowercase letter. Help Petya perform the comparison. ------------------------------------------------------- Maybe if I had more time, I would make both strings lower character and then use strcmp so that there's no abrupt end ... But I wanted to finish this as soon as possible. #define tolower(c) (c < 'a' ? (c + 'a' - 'A') : c) int main() { char string_1[MAX_LENGTH], string_2[MAX_LENGTH]; scanf("%s %s", string_1, string_2); for(int i = 0; string_1[i] != '\0'; i++) { if(tolower(string_1[i]) > tolower(string_2[i]) ) { printf("1\n"); return 0; } else if(tolower(string_1[i]) < tolower(string_2[i]) ) { printf("-1\n"); return 0; } } printf("0\n"); return 0; } ================================================ FILE: Contests/Div 2 85/Programs/Petya and Divisors.cpp ================================================ #include #include using namespace std; int main() { int no_of_queries; scanf("%d", &no_of_queries); const int MAX_N = 1e5 + 15; vector last_multiple_index(MAX_N, 0); for(int i = 1; i <= no_of_queries; i++) { int number, y; scanf("%d %d", &number, &y); int last_index = i - y; int divisors = 0, bad_divisors = 0; for(int d = 1; d*d <= number; d++) { if(number%d == 0) { divisors += (d*d == number ? 1 : 2); if(last_multiple_index[d] >= last_index) { bad_divisors++; } if(d*d != number && last_multiple_index[number/d] >= last_index) { bad_divisors++; } last_multiple_index[d] = last_multiple_index[number/d] = i; } } int good_divisors = divisors - bad_divisors; printf("%d\n", good_divisors); } return 0; } ================================================ FILE: Contests/Div 2 85/Programs/Petya and Inequiations.cpp ================================================ #include int main() { int n, sum_limit; long long square_sum_lower_bound; scanf("%d %I64d %d", &n, &square_sum_lower_bound, &sum_limit); long long largest_element = sum_limit - (n - 1); long long max_square_sum = (n - 1) + largest_element*largest_element; if(max_square_sum < square_sum_lower_bound || n > sum_limit) { printf("-1\n"); return 0; } for(int i = 1; i <= n; i++) printf("%I64d\n", (i == n ? largest_element : 1)); return 0; } ================================================ FILE: Contests/Div 2 85/Programs/Petya and Strings.cpp ================================================ #include #include #define MAX_LENGTH 100 + 1 #define tolower(c) (c < 'a' ? (c + 'a' - 'A') : c) int main() { char string_1[MAX_LENGTH], string_2[MAX_LENGTH]; scanf("%s %s", string_1, string_2); for(int i = 0; string_1[i] != '\0'; i++) { if(tolower(string_1[i]) > tolower(string_2[i]) ) { printf("1\n"); return 0; } else if(tolower(string_1[i]) < tolower(string_2[i]) ) { printf("-1\n"); return 0; } } printf("0\n"); return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Consecutive Subsequences Explanation.txt ================================================ Let f(A[i]) denote the longest sequence ending at A[i]. Now, A[i] is appended to the sequence ending at A[i] - 1 So, f(A[i]) = 1 + f(A[i] - 1) As n is large use maps. Don't use unordered maps as unordered maps have worst case complexity O(n) so the algorithm degrades to O(n^2) and causes TLE. ------------------------------ I've solved two problems seperately. First, find the longest sequence length and the last element. Then collect the indices. If I know the longest sequence has length L, and last element X Then I need to store the index of (X - L + 1) (X - L + 2) ... (X -1) (X) At first the index list is empty. I store the index of element (X - L + 1). Then, after that store the index of i, where A[i] = A[index.back()] + 1 Because we know that i must be the index of the element that is one more than the last element in the list. ---------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int last_element, longest_sequence = 0; map answer_with_last_element; for(int i = 1; i <= no_of_elements; i++) { answer_with_last_element[A[i]] = 1 + answer_with_last_element[A[i] - 1]; if(answer_with_last_element[A[i]] > longest_sequence) { longest_sequence = answer_with_last_element[A[i]]; last_element = A[i]; } } vector index; for(int i = 1; i <= no_of_elements; i++) { if(index.size() == 0) { if(A[i] == last_element - longest_sequence + 1) index.push_back(i); } else if(A[i] == A[index.back()] + 1) { index.push_back(i); } } printf("%d\n", longest_sequence); for(int i = 0; i < longest_sequence; i++) printf("%d ", index[i]); return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Cyclic Components Explanation.txt ================================================ Store each component in a seperate vector. In the contest, I used a more complicated solution. But there's an easier solution with an observation - A component is a cycle if each vertex has degree 2. This can be proven through induction. --------------------------------------------------------- void dfs_and_mark_component(int v, int no) { component[no].push_back(v); component_no[v] = no; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(component_no[child] == UNMARKED) dfs_and_mark_component(child, no); } } int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } memset(component_no, UNMARKED, sizeof(component_no)); int no_of_components = 0; for(int i = 1; i <= no_of_vertices; i++) { if(component_no[i] == UNMARKED) dfs_and_mark_component(i, no_of_components++); } int no_of_cycles = 0; for(int i = 0; i < no_of_components; i++) { int is_cycle = true; for(int j = 0; j < component[i].size(); j++) { int v = component[i][j]; if(graph[v].size() != 2) { is_cycle = false; } } no_of_cycles += (is_cycle == true); } printf("%d\n", no_of_cycles); return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Divide by Three Multiply by Two Alternate Solution Explanation.txt ================================================ http://qr.ae/TUTyWZ For any x, we cannot have both (2x and x/3) in the array. This is because from x, we can go either to 2x or to x/3. If we go to 2x, we can never reach x/3 as we can never divide by 2. Similar reasoning for x/3. For any element A[i], the chain from A[i] is uniquely determined. All we need to do is find the first element. This is the element x, for which x/2 and 3x are both absent from the array. ----------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); map present; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64u", &A[i]); present[A[i]] = true; } ULL first_element; for(int i = 1; i <= no_of_elements; i++) { int comes_from_multiplication = (A[i]%2 == 0 && present[A[i]/2]); int comes_from_division = (A[i] <= 1e18 && present[3*A[i]]); if(!comes_from_multiplication && !comes_from_division) { first_element = A[i]; } } vector solution; solution.push_back(first_element); while(solution.size() < no_of_elements) { ULL last_element = solution.back(); if(last_element%3 == 0 && present[last_element/3]) { solution.push_back(last_element/3); } else { solution.push_back(2*last_element); } } for(int i = 0; i < no_of_elements; i++) printf("%I64u ", solution[i]); return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Divide by Three, Multiply by Two Explanation.txt ================================================ http://qr.ae/TUTyWZ Notice that Exp(3) only decreases from left to right. Exp(2) only increases. -Exp(3) only increases. This means Exp(2) - Exp(3) increases from left to right. In going from one element to another, only one of these values changes by 1. SO, the quantity Exp(2) - Exp(3) is a monotonic and increases by 1 for each element. The beautiful solution is to simply sort the array according to (Exp(2) - Exp(3)) ------------------------------------- struct info { int two, three; unsigned long long number; }; int compare(const info &A, const info &B) { if(A.two - A.three < B.two - B.three) return true; else return false; } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { unsigned long long element; scanf("%I64u", &element); A[i].number = element; A[i].two = 0, A[i].three = 0; while(element%2 == 0) A[i].two++, element /= 2; while(element%3 == 0) A[i].three++, element /= 3; } sort(all(A), compare); for(int i = 0; i < no_of_elements; i++) printf("%I64u ", A[i].number); return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Less or Equal Explanation.txt ================================================ Let us sort the array. The question is asking for any number in the range [A[k], A[k + 1] - 1] This is not possible when A[k] = A[k + 1] Otherwise, just output A[k] The special case is k = 0, when we must output a number smaller than all the elements of the array. If A[1] = 1, then we cannot output any number as we must output a number that is at least 1. Else, we simply output 1. ------------------------------------------------- int main() { int no_of_elements, position; scanf("%d %d", &no_of_elements, &position); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); sort(all(A)); int answer; if(position == 0) { answer = (A[1] > 1 ? 1 : -1); } else { answer = (position < no_of_elements && A[position] == A[position + 1] ? -1 : A[position]); } printf("%d\n", answer); return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Two Gram Explanation.txt ================================================ There are only (n - 1) two-grams. Keep track of the frequency of each two-gram. The most frequent two-gram is the answer. -------------------------------------------------- int main() { int length; string S; cin >> length >> S; map frequency; int max_frequency = 0; string answer; for(int i = 0; i + 1 < length; i++) { string two_gram = S.substr(i, 2); frequency[two_gram]++; if(frequency[two_gram] > max_frequency) max_frequency = frequency[two_gram], answer = two_gram; } cout << answer; return 0; } ================================================ FILE: Contests/Div 3 479/Explanations/Wrong Subtraction Explanation.txt ================================================ The process is simple enough to simulate. ---------------------------------- #include int main() { int n, no_of_operations; scanf("%d %d", &n, &no_of_operations); while(no_of_operations--) { n = (n%10 == 0 ? n/10 : n - 1); } printf("%d\n", n); return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Consecutive Subsequences.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int last_element, longest_sequence = 0; map answer_with_last_element; for(int i = 1; i <= no_of_elements; i++) { answer_with_last_element[A[i]] = 1 + answer_with_last_element[A[i] - 1]; if(answer_with_last_element[A[i]] > longest_sequence) { longest_sequence = answer_with_last_element[A[i]]; last_element = A[i]; } } vector index; for(int i = 1; i <= no_of_elements; i++) { if(index.size() == 0) { if(A[i] == last_element - longest_sequence + 1) index.push_back(i); } else if(A[i] == A[index.back()] + 1) { index.push_back(i); } } printf("%d\n", longest_sequence); for(int i = 0; i < longest_sequence; i++) printf("%d ", index[i]); return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Cyclic Components.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 2e5 + 15, UNMARKED = -1; vector graph[MAX_N]; vector component[MAX_N]; int component_no[MAX_N]; void dfs_and_mark_component(int v, int no) { component[no].push_back(v); component_no[v] = no; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(component_no[child] == UNMARKED) dfs_and_mark_component(child, no); } } int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } memset(component_no, UNMARKED, sizeof(component_no)); int no_of_components = 0; for(int i = 1; i <= no_of_vertices; i++) { if(component_no[i] == UNMARKED) dfs_and_mark_component(i, no_of_components++); } int no_of_cycles = 0; for(int i = 0; i < no_of_components; i++) { int is_cycle = true; for(int j = 0; j < component[i].size(); j++) { int v = component[i][j]; if(graph[v].size() != 2) { is_cycle = false; } } no_of_cycles += (is_cycle == true); } printf("%d\n", no_of_cycles); return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Divide by Three, Multiply by Two Alternate Solution.cpp ================================================ #include #include #include typedef unsigned long long ULL; using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); map present; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64u", &A[i]); present[A[i]] = true; } ULL first_element; for(int i = 1; i <= no_of_elements; i++) { int comes_from_multiplication = (A[i]%2 == 0 && present[A[i]/2]); int comes_from_division = (A[i] <= 1e18 && present[3*A[i]]); if(!comes_from_multiplication && !comes_from_division) { first_element = A[i]; } } vector solution; solution.push_back(first_element); while(solution.size() < no_of_elements) { ULL last_element = solution.back(); if(last_element%3 == 0 && present[last_element/3]) { solution.push_back(last_element/3); } else { solution.push_back(2*last_element); } } for(int i = 0; i < no_of_elements; i++) printf("%I64u ", solution[i]); return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Divide by Three, Multiply by Two.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct info { int two, three; unsigned long long number; }; int compare(const info &A, const info &B) { if(A.two - A.three < B.two - B.three) return true; else return false; } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { unsigned long long element; scanf("%I64u", &element); A[i].number = element; A[i].two = 0, A[i].three = 0; while(element%2 == 0) A[i].two++, element /= 2; while(element%3 == 0) A[i].three++, element /= 3; } sort(all(A), compare); for(int i = 0; i < no_of_elements; i++) printf("%I64u ", A[i].number); return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Less or Equal.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, position; scanf("%d %d", &no_of_elements, &position); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); sort(all(A)); int answer; if(position == 0) { answer = (A[1] > 1 ? 1 : -1); } else { answer = (position < no_of_elements && A[position] == A[position + 1] ? -1 : A[position]); } printf("%d\n", answer); return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Two Gram.cpp ================================================ #include #include #include using namespace std; int main() { int length; string S; cin >> length >> S; map frequency; int max_frequency = 0; string answer; for(int i = 0; i + 1 < length; i++) { string two_gram = S.substr(i, 2); frequency[two_gram]++; if(frequency[two_gram] > max_frequency) max_frequency = frequency[two_gram], answer = two_gram; } cout << answer; return 0; } ================================================ FILE: Contests/Div 3 479/Programs/Wrong Subtraction.cpp ================================================ #include int main() { int n, no_of_operations; scanf("%d %d", &n, &no_of_operations); while(no_of_operations--) { n = (n%10 == 0 ? n/10 : n - 1); } printf("%d\n", n); return 0; } ================================================ FILE: Contests/Div 3 481/Explanations/Almost Arithmetic Progression Explanation.txt ================================================ Any AP is uniquely determined by it's first two elements. Let us check all possible first two elements A[0] +/- 1 A[1] +/- 1 For each of the 9 possible first two terms, check if an AP with that difference is possible with only adding or subtracting one to each element. If it's possible, then |term1 + k*d - A[k]| <= 1 If it is greater then it is not possible. If |term1 + k*d - A[k]| = 1, no of operations++ Keep track of the total no of operations and minimum total in all 9 configurations. In my program, if it's not possible, I set the number of operations to oo. -------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &A[i]); const int oo = 1e7; int add[3] = {-1, 0, 1}, min_operations = oo; for(int i = 0; i < 3; i++) { int term_1 = A[0] + add[i]; for(int j = 0; j < 3; j++) { int term_2 = A[1] + add[j]; int difference = term_2 - term_1; int no_of_operations = (term_1 != A[0]) + (term_2 != A[1]); for(int k = 2; k < no_of_elements; k++) { if(abs(term_1 + k*difference - A[k]) == 1) { no_of_operations++; } else if(abs(term_1 + k*difference - A[k]) > 1) { no_of_operations = oo; } } min_operations = min(min_operations, no_of_operations); } } printf("%d\n", min_operations >= oo ? -1 : min_operations); return 0; } ================================================ FILE: Contests/Div 3 481/Explanations/File Name Explanation.txt ================================================ For every character i, check if the previous two characters were x, if it was, then remove it. ------------------------------------- int main() { int length; string S; cin >> length >> S; int removable_characters = 0; for(int i = 2; i < length; i++) removable_characters += (S[i] == 'x' && S[i - 1] == 'x' && S[i - 2] == 'x'); cout << removable_characters; return 0; } ================================================ FILE: Contests/Div 3 481/Explanations/Letters Explanation.txt ================================================ Maintain a prefix sum array of the array. Then do binary search to find the first i, such that S[i] >= x and S[i - 1] < x i is the dorm no And x - S[i - 1] is the room no I used upper bound here quite clearly. upper bound(x) returns the first element which is GREATER than x. So upper bound(x - 1) does the trick quite nicely ! ----------------------------------------------- int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector A(no_of_elements + 1); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); sum_till[i] = sum_till[i - 1] + A[i]; } while(no_of_queries--) { long long x; scanf("%I64d", &x); int dorm_no = upper_bound(all(sum_till), x - 1) - sum_till.begin(); long long room_no = x - sum_till[dorm_no - 1]; printf("%d %I64d\n", dorm_no, room_no); } return 0; } ================================================ FILE: Contests/Div 3 481/Explanations/Mentors Explanation.txt ================================================ Here's what you do. SOrt the skills. The no of juniors = no of people less skilled. This can be gotten with binary search. Then read in the pairs of quarrels one by one. If Skill[x] > Skill[y], then juniors[x]-- And vice versa. At the end, simply print the juniors. ----------------------------------------------- int main() { int no_of_programmers, no_of_pairs; scanf("%d %d", &no_of_programmers, &no_of_pairs); vector skill(no_of_programmers + 1, 0); for(int i = 1; i <= no_of_programmers; i++) scanf("%d", &skill[i]); vector sorted_skill(no_of_programmers + 1, 0); for(int i = 1; i <= no_of_programmers; i++) sorted_skill[i] = skill[i]; sort(all(sorted_skill)); vector no_of_juniors(no_of_programmers + 1); for(int i = 1; i <= no_of_programmers; i++) { no_of_juniors[i] = upper_bound(all(sorted_skill), skill[i] - 1) - sorted_skill.begin() - 1; } for(int i = 1; i <= no_of_pairs; i++) { int u, v; scanf("%d %d", &u, &v); if(skill[u] > skill[v]) { no_of_juniors[u]--; } else if(skill[v] - skill[u]) { no_of_juniors[v]--; } } for(int i = 1; i <= no_of_programmers; i++) printf("%d ", no_of_juniors[i]); return 0; } ================================================ FILE: Contests/Div 3 481/Explanations/Remove Duplicates Explanation.txt ================================================ Read the integers right to left and keep track of what has been used so far. Put that into the solution and then print the solution in reverse. ---------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); const int MAX = 1015; vector used(MAX, false); vector ans; for(int i = no_of_elements; i >= 1; i--) { if(!used[A[i]]) { used[A[i]] = true; ans.push_back(A[i]); } } reverse(all(ans)); printf("%d\n", ans.size()); for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]); return 0; } ================================================ FILE: Contests/Div 3 481/Programs/Almost Arithmetic Progression.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &A[i]); const int oo = 1e7; int add[3] = {-1, 0, 1}, min_operations = oo; for(int i = 0; i < 3; i++) { int term_1 = A[0] + add[i]; for(int j = 0; j < 3; j++) { int term_2 = A[1] + add[j]; int difference = term_2 - term_1; int no_of_operations = (term_1 != A[0]) + (term_2 != A[1]); for(int k = 2; k < no_of_elements; k++) { if(abs(term_1 + k*difference - A[k]) == 1) { no_of_operations++; } else if(abs(term_1 + k*difference - A[k]) > 1) { no_of_operations = oo; } } min_operations = min(min_operations, no_of_operations); } } printf("%d\n", min_operations >= oo ? -1 : min_operations); return 0; } ================================================ FILE: Contests/Div 3 481/Programs/File Name.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; int removable_characters = 0; for(int i = 2; i < length; i++) removable_characters += (S[i] == 'x' && S[i - 1] == 'x' && S[i - 2] == 'x'); cout << removable_characters; return 0; } ================================================ FILE: Contests/Div 3 481/Programs/Letters.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector A(no_of_elements + 1); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); sum_till[i] = sum_till[i - 1] + A[i]; } while(no_of_queries--) { long long x; scanf("%I64d", &x); int dorm_no = upper_bound(all(sum_till), x - 1) - sum_till.begin(); long long room_no = x - sum_till[dorm_no - 1]; printf("%d %I64d\n", dorm_no, room_no); } return 0; } ================================================ FILE: Contests/Div 3 481/Programs/Mentors.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_programmers, no_of_pairs; scanf("%d %d", &no_of_programmers, &no_of_pairs); vector skill(no_of_programmers + 1, 0); for(int i = 1; i <= no_of_programmers; i++) scanf("%d", &skill[i]); vector sorted_skill(no_of_programmers + 1, 0); for(int i = 1; i <= no_of_programmers; i++) sorted_skill[i] = skill[i]; sort(all(sorted_skill)); vector no_of_juniors(no_of_programmers + 1); for(int i = 1; i <= no_of_programmers; i++) { no_of_juniors[i] = upper_bound(all(sorted_skill), skill[i] - 1) - sorted_skill.begin() - 1; } for(int i = 1; i <= no_of_pairs; i++) { int u, v; scanf("%d %d", &u, &v); if(skill[u] > skill[v]) { no_of_juniors[u]--; } else if(skill[v] - skill[u]) { no_of_juniors[v]--; } } for(int i = 1; i <= no_of_programmers; i++) printf("%d ", no_of_juniors[i]); return 0; } ================================================ FILE: Contests/Div 3 481/Programs/Remove Duplicates.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); const int MAX = 1015; vector used(MAX, false); vector ans; for(int i = no_of_elements; i >= 1; i--) { if(!used[A[i]]) { used[A[i]] = true; ans.push_back(A[i]); } } reverse(all(ans)); printf("%d\n", ans.size()); for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]); return 0; } ================================================ FILE: Contests/Div 3 486/Explanation/Diverse Team Explanation.txt ================================================ It's pretty simple. Keep track of distinct ratings and compare it with the required team size. ----- int main() { int no_of_students, team_size; scanf("%d %d", &no_of_students, &team_size); const int MAX_RATING = 115; vector team; vector rating_used(MAX_RATING, false); for(int i = 1; i <= no_of_students; i++) { int rating_i; scanf("%d", &rating_i); if(!rating_used[rating_i]) team.push_back(i); rating_used[rating_i] = true; } if(team.size() >= team_size) { printf("YES\n"); for(int i = 0; i < team_size; i++) printf("%d ", team[i]); } else { printf("NO\n"); } return 0; } ================================================ FILE: Contests/Div 3 486/Explanation/Divisibility by 25 Explanation.txt ================================================ Check if it's possible to get all four suffixes. Now, whether it is possible to get a given suffix can be done in better time complexity but it will cost more complexity in the code. Here's what I did - 1. Iterate over every pair of digits and simulate making this pair the last two digits. 2. Check if the first digit is 0. If so, keep swapping it till the first digit becomes non-zero. 3. If the last two digits are the suffix we desire, then keep track of the number of moves we have used. We want the minimum number. ---- int min_moves_for_suffix(string S, string suffix) { int moves = oo; for(int first = 0; first < S.size(); first++) { for(int second = 0; second < S.size(); second++) { if(first == second) continue; string N = S; int moves_here = 0; for(int i = first; i < N.size() - 1.; i++) { swap(N[i], N[i + 1]); moves_here++; } //Second may have been disturbed by first for(int i = second - (second > first); i < N.size() - 2; i++) { swap(N[i], N[i + 1]); moves_here++; } int first_non_zero = 0; while(N[first_non_zero] == '0') first_non_zero++; for(int i = first_non_zero; i > 0; i--) { swap(N[i], N[i - 1]); moves_here++; } if(N[N.size() - 2] == suffix[0] && N[N.size() - 1] == suffix[1]) moves = min(moves, moves_here); } } return moves; } ----------------------- Now for a number to be a multiple of 25, it must have 1 of 4 suffixes. int main() { string N; cin >> N; int minimum_moves = oo; minimum_moves = min( min(min_moves_for_suffix(N, "25"), min_moves_for_suffix(N, "50")), min(min_moves_for_suffix(N, "75"), min_moves_for_suffix(N, "00")) ); cout << (minimum_moves >= oo ? -1 : minimum_moves); return 0; } ================================================ FILE: Contests/Div 3 486/Explanation/Equal Sums Explanation.txt ================================================ Firstly, keep an array called used, which contains all the sums [S - A[i]], where S is the sum of the entire array for each i. Then go through the array and check for each i, if [S - A[i]] is present in used. Be careful to check that used [S - A[i]] is present in some index other than i. ---------------- int main() { int no_of_sequences; scanf("%d", &no_of_sequences); map > used; for(int i = 1; i <= no_of_sequences; i++) { int length_i; scanf("%d", &length_i); vector A(length_i + 1); for(int j = 1; j <= length_i; j++) scanf("%d", &A[j]); long long sum = 0; for(int j = 1; j <= length_i; j++) sum += A[j]; for(int j = 1; j <= length_i; j++) { long long remaining_sum = sum - A[j]; if(used.find(remaining_sum) != used.end() && used[remaining_sum].first != i) { printf("YES\n"); printf("%d %d\n", used[remaining_sum].first, used[remaining_sum].second); printf("%d %d\n", i, j); return 0; } else { used[remaining_sum] = make_pair(i, j); } } } printf("NO\n"); return 0; } ================================================ FILE: Contests/Div 3 486/Explanation/Points and Powers of Two Explanation.txt ================================================ Fact - This is only possible for at most 3 points. Let P[1] < P[2] < P[3]. Let us suppose distance between P[1] and P[2] is x. And distance between P[2] and P[3] is x, then distance between P[1] and P[3] is 2x. If the distance between P[2] and P[3] is anything other than x, (say y). Then P[2] - P[1] = x, P[3] - P[2] = y P[3] - P[1] = x + y, x, y and x + y cannot all be powers of 2 unless x = y. Now if we introduce a 4th point P[4]. P[4] - P[3] = x, But then P[4] - P[1] = 3x, which is not a power of 2. This completes our proof. ------------------------ Now for each number and for each power of 2, we will do binary search to check if (A[i] + 2^p) is present in the array. We will first look for a triplet. If not there, we will look for a pair. If not there, we will print any one element of the array. --------- int answer_i = -1, answer_j = -1; for(int i = 0; i < number_of_points; i++) { for(long long power = 1; power <= 1e12; power *= 2) { int j = upper_bound(all(P), P[i] + power - 1) - P.begin(); if(P[j] - P[i] == power) { int k = upper_bound(all(P), P[j] + power - 1) - P.begin(); if(P[k] - P[j] == power)//Answer can't be more than 3 { printf("3\n"); printf("%I64d %I64d %I64d\n", P[i], P[j], P[k]); return 0; } else { answer_i = i, answer_j = j; } } } } if(answer_i != -1 && answer_j != -1) { printf("2\n"); printf("%I64d %I64d\n", P[answer_i], P[answer_j]); } else { printf("1\n"); printf("%I64d\n", P[0]); } ================================================ FILE: Contests/Div 3 486/Explanation/Substring Sort Explanation.txt ================================================ 1. Write a custom sort function that sorts strings by length. int sort_by_length(const string &A, const string &B) { return (A.size() < B.size()); } -------- 2. If any S[i] is not a substring of S[i + 1], then we don't have a desireable order. Let us suppose there is some j such that j > i + 1 and S[i] is a substring of S[j] but not of S[i + 1]. Then we have to put S[j] after S[i] and S[i + 1] after S[j]. Either way S[j] cannot be a substring of S[i + 1] because S[j] is longer. (If they are the same length, they are clearly not equal.) ------------ If every S[i] is a substring of S[i + 1], then the sorted order is the order we want. int main() { int no_of_strings; cin >> no_of_strings; vector S(no_of_strings); for(int i = 0; i < no_of_strings; i++) cin >> S[i]; sort(all(S), sort_by_length); for(int i = 1; i < no_of_strings; i++) { if(!substring_of(S[i], S[i - 1])) { cout << "NO\n"; return 0; } } cout << "YES\n"; for(int i = 0; i < no_of_strings; i++) cout << S[i] << "\n"; return 0; } ================================================ FILE: Contests/Div 3 486/Programs/Diverse Team.cpp ================================================ #include #include #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_students, team_size; scanf("%d %d", &no_of_students, &team_size); const int MAX_RATING = 115; vector team; vector rating_used(MAX_RATING, false); for(int i = 1; i <= no_of_students; i++) { int rating_i; scanf("%d", &rating_i); if(!rating_used[rating_i]) team.push_back(i); rating_used[rating_i] = true; } if(team.size() >= team_size) { printf("YES\n"); for(int i = 0; i < team_size; i++) printf("%d ", team[i]); } else { printf("NO\n"); } return 0; } ================================================ FILE: Contests/Div 3 486/Programs/Divisibility by 25.cpp ================================================ #include #include #include using namespace std; const int oo = 100; int min_moves_for_suffix(string S, string suffix) { int moves = oo; for(int first = 0; first < S.size(); first++) { for(int second = 0; second < S.size(); second++) { if(first == second) continue; string N = S; int moves_here = 0; for(int i = first; i < N.size() - 1.; i++) { swap(N[i], N[i + 1]); moves_here++; } //Second may have been disturbed by first for(int i = second - (second > first); i < N.size() - 2; i++) { swap(N[i], N[i + 1]); moves_here++; } int first_non_zero = 0; while(N[first_non_zero] == '0') first_non_zero++; for(int i = first_non_zero; i > 0; i--) { swap(N[i], N[i - 1]); moves_here++; } if(N[N.size() - 2] == suffix[0] && N[N.size() - 1] == suffix[1]) moves = min(moves, moves_here); } } return moves; } int main() { string N; cin >> N; int minimum_moves = oo; minimum_moves = min( min(min_moves_for_suffix(N, "25"), min_moves_for_suffix(N, "50")), min(min_moves_for_suffix(N, "75"), min_moves_for_suffix(N, "00")) ); cout << (minimum_moves >= oo ? -1 : minimum_moves); return 0; } ================================================ FILE: Contests/Div 3 486/Programs/Equal Sums.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_sequences; scanf("%d", &no_of_sequences); map > used; for(int i = 1; i <= no_of_sequences; i++) { int length_i; scanf("%d", &length_i); vector A(length_i + 1); for(int j = 1; j <= length_i; j++) scanf("%d", &A[j]); long long sum = 0; for(int j = 1; j <= length_i; j++) sum += A[j]; for(int j = 1; j <= length_i; j++) { long long remaining_sum = sum - A[j]; if(used.find(remaining_sum) != used.end() && used[remaining_sum].first != i) { printf("YES\n"); printf("%d %d\n", used[remaining_sum].first, used[remaining_sum].second); printf("%d %d\n", i, j); return 0; } else { used[remaining_sum] = make_pair(i, j); } } } printf("NO\n"); return 0; } ================================================ FILE: Contests/Div 3 486/Programs/Points and Powers of Two.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int number_of_points; scanf("%d", &number_of_points); vector P(number_of_points); for(int i = 0; i < number_of_points; i++) scanf("%I64d", &P[i]); sort(all(P)); int answer_i = -1, answer_j = -1; for(int i = 0; i < number_of_points; i++) { for(long long power = 1; power <= 1e12; power *= 2) { int j = upper_bound(all(P), P[i] + power - 1) - P.begin(); if(P[j] - P[i] == power) { int k = upper_bound(all(P), P[j] + power - 1) - P.begin(); if(P[k] - P[j] == power)//Answer can't be more than 3 { printf("3\n"); printf("%I64d %I64d %I64d\n", P[i], P[j], P[k]); return 0; } else { answer_i = i, answer_j = j; } } } } if(answer_i != -1 && answer_j != -1) { printf("2\n"); printf("%I64d %I64d\n", P[answer_i], P[answer_j]); } else { printf("1\n"); printf("%I64d\n", P[0]); } return 0; } ================================================ FILE: Contests/Div 3 486/Programs/Substring Sort.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int sort_by_length(const string &A, const string &B) { return (A.size() < B.size()); } int substring_of(string S, string sub_S) { for(int i = 0; i + sub_S.size() - 1 < S.size(); i++) { int substring = true; for(int j = 0; j < sub_S.size(); j++) { if(S[i + j] != sub_S[j]) { substring = false; } } if(substring) return true; } return false; } int main() { int no_of_strings; cin >> no_of_strings; vector S(no_of_strings); for(int i = 0; i < no_of_strings; i++) cin >> S[i]; sort(all(S), sort_by_length); for(int i = 1; i < no_of_strings; i++) { if(!substring_of(S[i], S[i - 1])) { cout << "NO\n"; return 0; } } cout << "YES\n"; for(int i = 0; i < no_of_strings; i++) cout << S[i] << "\n"; return 0; } ================================================ FILE: Contests/Div 3 490/Explanations/Alphabetic Removals Explanation.txt ================================================ Keep track of the frequency of each alphabet. If the frequency[a] >= k, then ban the alphabet a. Reduce k by frequency[a]. if there is a situation when frequency[x] < k, then do an O(n) scan on the array and ban specific positions of the string. In the end print a character in the string, if both it's position and alphabet aren't bad. ------------------------------ vector frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < S.size(); i++) frequency[S[i] - 'a']++; vector is_allowed(length, true); vector banned(NO_OF_ALPHABETS, false); for(int alphabet = 0; alphabet < NO_OF_ALPHABETS && k > 0; alphabet++) { if(frequency[alphabet] <= k) { banned[alphabet] = true; k -= frequency[alphabet]; } else if(frequency[alphabet] > k) { for(int i = 0; i < length && k > 0; i++) { if(S[i] == 'a' + alphabet) { k--; is_allowed[i] = false; } } } } for(int i = 0; i < length; i++) if(is_allowed[i] && !banned[S[i] - 'a']) cout << S[i]; ================================================ FILE: Contests/Div 3 490/Explanations/Equalise the Remainders Explanation.txt ================================================ Firstly, we need to print the modified array not just print the number of changes required. So, we will keep track of the positions of each index of modulus. That is we will know the indices of all the A[i]%m = x, --------------------- Now, we will make a pass from i = 0 to m - 1 If any modulus occurs more than N/m times, then we will remove the excess indices and put them in 'extra' If any modulus occurs less than N/m times, we will remove from extra from the end [Since the ones in the end will be closer to the current modulus.] and put it here. We need to do two passes, not one. (This is an unusual feature of this problem.) Because The first element might be deficient and the last may be in excess. ----------------------------- long long no_of_changes = 0; vector extra; for(int runs = 1; runs <= 2; runs++) { for(int i = 0; i < m; i++) { while(position[i].size() > target) { int index = position[i].back(); extra.push_back(index); position[i].pop_back(); } while(position[i].size() < target && extra.size() > 0) { int index = extra.back(); no_of_changes += (A[index]%m < i ? i - A[index]%m : m - A[index]%m + i); A[index] += (A[index]%m < i ? i - A[index]%m : m - A[index]%m + i); position[i].push_back(index); extra.pop_back(); } } } ================================================ FILE: Contests/Div 3 490/Explanations/Mishika and Contests Explanation.txt ================================================ Have two pointers - One at the front, one at the back and move whichever pointer is allowed. #include #include using namespace std; int main() { int no_of_problems, skill; scanf("%d %d", &no_of_problems, &skill); vector difficulty(no_of_problems + 1); for(int i = 1; i <= no_of_problems; i++) scanf("%d", &difficulty[i]); int solvable = 0; int left = 1, right = no_of_problems; while( (difficulty[left] <= skill || difficulty[right] <= skill) && left <= right) { if(difficulty[left] <= skill) left++, solvable++; else if(difficulty[right] <= skill) right--, solvable++; } printf("%d\n", solvable); return 0; } ================================================ FILE: Contests/Div 3 490/Explanations/Reachability from Capital Explanation.txt ================================================ 1. If the graph were not directed, it would be equivalent to counting the number of components in the graph. 2. As the graph is directed, let us condense each strongly connected component to a single vertex and draw an edge between two vertices if any vertex of one component has an edge with any component of the other 3. The number of components in this 'component' graph is the number of vertices we must connect. 4. How to get strongly connected components ? First, we will perform DFS on the tree. Then, we will perform DFS on the reverse tree ----- #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 5015; vector graph[MAX_N]; vector visited(MAX_N, false); vector visit_order; vector reverse_graph[MAX_N]; vector component(MAX_N, 0); vector component_graph[MAX_N]; vector reachable_component(MAX_N, false); void dfs(int v) { visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) dfs(child); } visit_order.push_back(v); } void reverse_dfs(int v, int c) { component[v] = c; for(int i = 0; i < reverse_graph[v].size(); i++) { int child = reverse_graph[v][i]; if(component[child] == 0) reverse_dfs(child, c); } } void component_dfs(int v) { reachable_component[v] = true; for(int i = 0; i < component_graph[v].size(); i++) { int child_v = component_graph[v][i]; if(!reachable_component[child_v]) dfs(child_v); } } int main() { int no_of_vertices, no_of_edges, source; scanf("%d %d %d", &no_of_vertices, &no_of_edges, &source); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); reverse_graph[v].push_back(u); } for(int i = 1; i <= no_of_vertices; i++) { if(!visited[i]) { dfs(i); } } int no_of_components = 0; reverse(all(visit_order)); for(int i = 0; i < no_of_vertices; i++) { int v = visit_order[i]; if(component[v] == 0) { reverse_dfs(v, ++no_of_components); } } vector incoming(no_of_components + 1); for(int v = 1; v <= no_of_vertices; v++) { for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(component[v] != component[child]) { component_graph[component[v]].push_back(component[child]); incoming[component[child]]++; } } } component_dfs(component[source]); int new_edges = 0; for(int i = 1; i <= no_of_components; i++) { if(!reachable_component[i] && incoming[i] == 0) { new_edges++; } } printf("%d\n", new_edges); return 0; } ================================================ FILE: Contests/Div 3 490/Explanations/Reversing Encryption Explanation.txt ================================================ Perform the reverses in increasing order of the divisors of n ! This undoes all the reverses done in the encryption preserving order ! ----------------------------------- int main() { int length; string S; cin >> length >> S; vector divisors; get_divisors(divisors, length); sort(divisors.begin(), divisors.end()); for(int i = 0; i < divisors.size(); i++) { reverse(S.begin(), S.begin() + divisors[i]); } cout << S; return 0; } ================================================ FILE: Contests/Div 3 490/Programs/Alphabetic Removals.cpp ================================================ #include #include #include using namespace std; int main() { int length, k; string S; cin >> length >> k >> S; const int NO_OF_ALPHABETS = 26; vector frequency(NO_OF_ALPHABETS, 0); for(int i = 0; i < S.size(); i++) frequency[S[i] - 'a']++; vector is_allowed(length, true); vector banned(NO_OF_ALPHABETS, false); for(int alphabet = 0; alphabet < NO_OF_ALPHABETS && k > 0; alphabet++) { if(frequency[alphabet] <= k) { banned[alphabet] = true; k -= frequency[alphabet]; } else if(frequency[alphabet] > k) { for(int i = 0; i < length && k > 0; i++) { if(S[i] == 'a' + alphabet) { k--; is_allowed[i] = false; } } } } for(int i = 0; i < length; i++) if(is_allowed[i] && !banned[S[i] - 'a']) cout << S[i]; return 0; } ================================================ FILE: Contests/Div 3 490/Programs/Equalise the Remainders.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 5; vector position[MAX_N]; int main() { typedef long long LL; int no_of_elements, m; scanf("%d %d", &no_of_elements, &m); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); int target = no_of_elements/m; for(int i = 1; i <= no_of_elements; i++) { position[A[i]%m].push_back(i); } long long no_of_changes = 0; vector extra; for(int runs = 1; runs <= 2; runs++) { for(int i = 0; i < m; i++) { while(position[i].size() > target) { int index = position[i].back(); extra.push_back(index); position[i].pop_back(); } while(position[i].size() < target && extra.size() > 0) { int index = extra.back(); no_of_changes += (A[index]%m < i ? i - A[index]%m : m - A[index]%m + i); A[index] += (A[index]%m < i ? i - A[index]%m : m - A[index]%m + i); position[i].push_back(index); extra.pop_back(); } } } printf("%I64d\n", no_of_changes); for(int i = 1; i <= no_of_elements; i++) printf("%I64d ", A[i]); return 0; } ================================================ FILE: Contests/Div 3 490/Programs/Mishika and Contests.cpp ================================================ #include #include using namespace std; int main() { int no_of_problems, skill; scanf("%d %d", &no_of_problems, &skill); vector difficulty(no_of_problems + 1); for(int i = 1; i <= no_of_problems; i++) scanf("%d", &difficulty[i]); int solvable = 0; int left = 1, right = no_of_problems; while( (difficulty[left] <= skill || difficulty[right] <= skill) && left <= right) { if(difficulty[left] <= skill) left++, solvable++; else if(difficulty[right] <= skill) right--, solvable++; } printf("%d\n", solvable); return 0; } ================================================ FILE: Contests/Div 3 490/Programs/Reachability from Capital.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 5015; vector graph[MAX_N]; vector visited(MAX_N, false); vector visit_order; vector reverse_graph[MAX_N]; vector component(MAX_N, 0); vector component_graph[MAX_N]; vector reachable_component(MAX_N, false); void dfs(int v) { visited[v] = true; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) dfs(child); } visit_order.push_back(v); } void reverse_dfs(int v, int c) { component[v] = c; for(int i = 0; i < reverse_graph[v].size(); i++) { int child = reverse_graph[v][i]; if(component[child] == 0) reverse_dfs(child, c); } } void component_dfs(int v) { reachable_component[v] = true; for(int i = 0; i < component_graph[v].size(); i++) { int child_v = component_graph[v][i]; if(!reachable_component[child_v]) dfs(child_v); } } int main() { int no_of_vertices, no_of_edges, source; scanf("%d %d %d", &no_of_vertices, &no_of_edges, &source); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); reverse_graph[v].push_back(u); } for(int i = 1; i <= no_of_vertices; i++) { if(!visited[i]) { dfs(i); } } int no_of_components = 0; reverse(all(visit_order)); for(int i = 0; i < no_of_vertices; i++) { int v = visit_order[i]; if(component[v] == 0) { reverse_dfs(v, ++no_of_components); } } vector incoming(no_of_components + 1); for(int v = 1; v <= no_of_vertices; v++) { for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(component[v] != component[child]) { component_graph[component[v]].push_back(component[child]); incoming[component[child]]++; } } } component_dfs(component[source]); int new_edges = 0; for(int i = 1; i <= no_of_components; i++) { if(!reachable_component[i] && incoming[i] == 0) { new_edges++; } } printf("%d\n", new_edges); return 0; } ================================================ FILE: Contests/Div 3 490/Programs/Reversing Encryption.cpp ================================================ #include #include #include #include using namespace std; void get_divisors(vector &divisors, int n) { for(int i = 1; i*i <= n; i++) { if(n%i == 0) { divisors.push_back(i); if(i*i != n) divisors.push_back(n/i); } } } int main() { int length; string S; cin >> length >> S; vector divisors; get_divisors(divisors, length); sort(divisors.begin(), divisors.end()); for(int i = 0; i < divisors.size(); i++) { reverse(S.begin(), S.begin() + divisors[i]); } cout << S; return 0; } ================================================ FILE: Contests/Div 3 494/Explanations/Binary String Constructing Explanation.txt ================================================ Let us be greedy and construct exactly x different positions and then put all the remaining characters together. We are guaranteed that it is always possible. -------------------------- int main() { int ones, zeroes, differences; cin >> zeroes >> ones >> differences; string answer; if(ones > zeroes) { answer += '1'; ones--; } else { answer += '0'; zeroes--; } for(int i = 1; i <= differences; i++) { int len = answer.size(); if(answer[len - 1] == '0') { answer += '1'; ones--; } else { answer += '0'; zeroes--; } } string S; for(int i = 0; i < answer.size(); i++) { S += answer[i]; if(answer[i] == '1' && ones > 0) { while(ones--) S += '1'; } if(answer[i] == '0' && zeroes > 0) { while(zeroes--) S += '0'; } } cout << S; return 0; } ================================================ FILE: Contests/Div 3 494/Explanations/Coins and Queries Explanation.txt ================================================ It is always optimal to use the largest coin size we have at the current moment. Suppose we don't use coin x, we will have to use more coins of size y < x ... Since y is a divisor of x. So, let us be greedy and do it in O(N log N) time. ------------------- void solve(map &frequency) { int target; scanf("%d", &target); int coins_used = 0; for(int bit = 30; bit >= 0; bit--) { if(frequency[1 << bit] == 0) continue; int coins_used_here = min(frequency[(1 << bit)], target/(1 << bit)); target = target - coins_used_here*(1 << bit); coins_used += coins_used_here; } printf("%d\n", target > 0 ? -1 : coins_used); } ================================================ FILE: Contests/Div 3 494/Explanations/Intense Heat Explanation.txt ================================================ First, we will compute prefix sums so we can find the mean of a subarray [L, R] in O(1) time. Now, we shall visit all subarrays in O(n^2) time. --------------------------------- int main() { int no_of_days, k; scanf("%d %d", &no_of_days, &k); vector temperature(no_of_days + 1); for(int i = 1; i <= no_of_days; i++) scanf("%d", &temperature[i]); vector sum_till(no_of_days + 1, 0); for(int i = 1; i <= no_of_days; i++) sum_till[i] = sum_till[i - 1] + temperature[i]; double best = 0; for(int length = k; length <= no_of_days; length++) { for(int left = 1, right = left + length - 1; right <= no_of_days; left++, right++) { double average_here = (1.0*(sum_till[right] - sum_till[left - 1]))/(1.0*length); best = max(best, average_here); } } printf("%.12f\n", best); return 0; } ================================================ FILE: Contests/Div 3 494/Explanations/Polycarp's Pockets Explanation.txt ================================================ We want the element which has the highest frequency. int main() { int no_of_elements; scanf("%d", &no_of_elements); const int MAX_N = 115; vector frequency(MAX_N, 0); while(no_of_elements--) { int element; scanf("%d", &element); frequency[element]++; } int max_frequency = 0; for(int i = 0; i < MAX_N; i++) max_frequency = max(max_frequency, frequency[i]); printf("%d\n", max_frequency); return 0; } ================================================ FILE: Contests/Div 3 494/Programs/Binary String Constructing.cpp ================================================ #include #include using namespace std; int main() { int ones, zeroes, differences; cin >> zeroes >> ones >> differences; string answer; if(ones > zeroes) { answer += '1'; ones--; } else { answer += '0'; zeroes--; } for(int i = 1; i <= differences; i++) { int len = answer.size(); if(answer[len - 1] == '0') { answer += '1'; ones--; } else { answer += '0'; zeroes--; } } string S; for(int i = 0; i < answer.size(); i++) { S += answer[i]; if(answer[i] == '1' && ones > 0) { while(ones--) S += '1'; } if(answer[i] == '0' && zeroes > 0) { while(zeroes--) S += '0'; } } cout << S; return 0; } ================================================ FILE: Contests/Div 3 494/Programs/Coins and Queries.cpp ================================================ #include #include #include using namespace std; void solve(map &frequency) { int target; scanf("%d", &target); int coins_used = 0; for(int bit = 30; bit >= 0; bit--) { if(frequency[1 << bit] == 0) continue; int coins_used_here = min(frequency[(1 << bit)], target/(1 << bit)); target = target - coins_used_here*(1 << bit); coins_used += coins_used_here; } printf("%d\n", target > 0 ? -1 : coins_used); } int main() { map frequency; int no_of_coins, no_of_queries; scanf("%d %d", &no_of_coins, &no_of_queries); while(no_of_coins--) { int value; scanf("%d", &value); frequency[value]++; } while(no_of_queries--) solve(frequency); return 0; } ================================================ FILE: Contests/Div 3 494/Programs/Intense Heat.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_days, k; scanf("%d %d", &no_of_days, &k); vector temperature(no_of_days + 1); for(int i = 1; i <= no_of_days; i++) scanf("%d", &temperature[i]); vector sum_till(no_of_days + 1, 0); for(int i = 1; i <= no_of_days; i++) sum_till[i] = sum_till[i - 1] + temperature[i]; double best = 0; for(int length = k; length <= no_of_days; length++) { for(int left = 1, right = left + length - 1; right <= no_of_days; left++, right++) { double average_here = (1.0*(sum_till[right] - sum_till[left - 1]))/(1.0*length); best = max(best, average_here); } } printf("%.12f\n", best); return 0; } ================================================ FILE: Contests/Div 3 494/Programs/Polycarp's Pockets.cpp ================================================ #include #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); const int MAX_N = 115; vector frequency(MAX_N, 0); while(no_of_elements--) { int element; scanf("%d", &element); frequency[element]++; } int max_frequency = 0; for(int i = 0; i < MAX_N; i++) max_frequency = max(max_frequency, frequency[i]); printf("%d\n", max_frequency); return 0; } ================================================ FILE: Contests/Div 3 521/Explanations/Cutting Out Explanation.txt ================================================ Let us binary search on the number of arrays we can have. Suppose we have to check if X arrays are possible. How do we do it ? For every element A[i] in the array, we will try to distribute it as evenly as possible in the array B. Each array will have (frequency[A[i]]/x) copies of A[i] At the end, we will say if we have managed to put k elements in B If Yes, then we can can create X copies of B ----- int possible(int no_of_arrays, int length, vector &answer) { vector filled; for(auto it = frequency.begin(); it != frequency.end() && filled.size() < length; it++) { int required_frequency = (it->second)/no_of_arrays; for(int i = 1; i <= required_frequency; i++) { filled.push_back(it->first); } } if(filled.size() >= length) { answer = filled; } return (filled.size() >= length); } int main() { int no_of_elements, k; cin >> no_of_elements >> k; A.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } //L is always possible, R is always not possible vector answer; int left = 0, right = no_of_elements + 1; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, k, answer)) { left = mid; } else { right = mid; } } for(int i = 0; i < k; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 521/Explanations/Disturbed People.txt ================================================ We solve the problem by being greedy. Whenever we find a triplet - "1 0 1" we switch off the rightmost 1. We could also switch off all the leftmost 1s. The two solutions are equivalent. Now every triplet 1 0 1 needs one of the border 1s to be switched off. So, we always switch off rightmost switches. ------------ int main() { int no_of_houses; cin >> no_of_houses; vector light_on(no_of_houses + 1); for(int i = 1; i <= no_of_houses; i++) cin >> light_on[i]; int excess_houses = 0; for(int i = 2; i < no_of_houses; i++) { if(light_on[i - 1] && !light_on[i] && light_on[i + 1]) { light_on[i + 1] = false; excess_houses++; } } cout << excess_houses << "\n"; return 0; } ================================================ FILE: Contests/Div 3 521/Explanations/Frog Jumping.txt ================================================ The total displacement towards right is positive, and left is negative. The answer is their difference. All we need to do is calculate the number of jumps in either direction and then the displacement in both directions. void solve() { long long left_jump, right_jump, total_jumps; cin >> right_jump >> left_jump >> total_jumps; long long no_of_right_jumps = total_jumps/2 + total_jumps%2; long long no_of_left_jumps = total_jumps/2; long long right_distance = no_of_right_jumps*right_jump; long long left_distance = no_of_left_jumps*left_jump; long long distance = right_distance - left_distance; cout << distance << "\n"; } ================================================ FILE: Contests/Div 3 521/Explanations/Good Array.txt ================================================ Suppose the sum is S. If we remove A[i] from the array, the sum is S - A[i]. Now if i is a nice index, there is some index j, j =/= i such that A[j] = (S - A[i])/2 We simply keep track of the frequency of each element and solve this problem. ---------- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; const int MAX = 1e6 + 5; vector frequency(MAX, 0); for(int i = 1; i <= no_of_elements; i++) frequency[A[i]]++; long long sum = 0; for(int i = 1; i <= no_of_elements; i++) sum += A[i]; vector nice_indices; for(int i = 1; i <= no_of_elements; i++) { long long remaining_sum = sum - A[i]; long long target = remaining_sum/2; if(target < MAX && remaining_sum%2 == 0 && frequency[target] > 0 && !(frequency[target] == 1 and A[i] == target)) { nice_indices.push_back(i); } } cout << nice_indices.size() << "\n"; for(int i = 0; i < nice_indices.size(); i++) cout << nice_indices[i] << " "; return 0; } ================================================ FILE: Contests/Div 3 521/Explanations/Thematic Contests Explanation.txt ================================================ We will keep track of the frequency of each topic. ----- Let us try to fix the end of the segment. If the last contest has X problems, then the second last problem has X/2 problems. We will continue like this till either X is odd or there is no topic which has X problems ----- int get_count_ending(int ending, vector &A) { int count = 0; for(int i = A.size() - 1, current = ending; i >= 0 && A[i] >= current; i--) { count += current; if(current%2 == 1) { break; } current /= 2; } return count; } ----- Now, we will iterate over the possible end. It can be at most A[end] ----- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map frequency; for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } vector frequencies; for(auto it = frequency.begin(); it != frequency.end(); it++) { frequencies.push_back(it->second); } sort(all(frequencies)); int maximum = 0; for(int i = 0; i <= frequencies.back(); i++) { maximum = max(maximum, get_count_ending(i, frequencies)); } cout << maximum << "\n"; return 0; } ================================================ FILE: Contests/Div 3 521/Programs/Cutting Out.cpp ================================================ #include #include #include #include using namespace std; map frequency; vector A; int possible(int no_of_arrays, int length, vector &answer) { vector filled; for(auto it = frequency.begin(); it != frequency.end() && filled.size() < length; it++) { int required_frequency = (it->second)/no_of_arrays; for(int i = 1; i <= required_frequency; i++) { filled.push_back(it->first); } } if(filled.size() >= length) { answer = filled; } return (filled.size() >= length); } int main() { int no_of_elements, k; cin >> no_of_elements >> k; A.resize(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } //L is always possible, R is always not possible vector answer; int left = 0, right = no_of_elements + 1; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, k, answer)) { left = mid; } else { right = mid; } } for(int i = 0; i < k; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 521/Programs/Disturbed People.cpp ================================================ #include #include using namespace std; int main() { int no_of_houses; cin >> no_of_houses; vector light_on(no_of_houses + 1); for(int i = 1; i <= no_of_houses; i++) cin >> light_on[i]; int excess_houses = 0; for(int i = 2; i < no_of_houses; i++) { if(light_on[i - 1] && !light_on[i] && light_on[i + 1]) { light_on[i + 1] = false; excess_houses++; } } cout << excess_houses << "\n"; return 0; } ================================================ FILE: Contests/Div 3 521/Programs/Frog Jumping.cpp ================================================ #include using namespace std; void solve() { long long left_jump, right_jump, total_jumps; cin >> right_jump >> left_jump >> total_jumps; long long no_of_right_jumps = total_jumps/2 + total_jumps%2; long long no_of_left_jumps = total_jumps/2; long long right_distance = no_of_right_jumps*right_jump; long long left_distance = no_of_left_jumps*left_jump; long long distance = right_distance - left_distance; cout << distance << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 521/Programs/Good Array.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; const int MAX = 1e6 + 5; vector frequency(MAX, 0); for(int i = 1; i <= no_of_elements; i++) frequency[A[i]]++; long long sum = 0; for(int i = 1; i <= no_of_elements; i++) sum += A[i]; vector nice_indices; for(int i = 1; i <= no_of_elements; i++) { long long remaining_sum = sum - A[i]; long long target = remaining_sum/2; if(target < MAX && remaining_sum%2 == 0 && frequency[target] > 0 && !(frequency[target] == 1 and A[i] == target)) { nice_indices.push_back(i); } } cout << nice_indices.size() << "\n"; for(int i = 0; i < nice_indices.size(); i++) cout << nice_indices[i] << " "; return 0; } ================================================ FILE: Contests/Div 3 521/Programs/Pictures with Kittens (Easy Version).cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, segment, total; cin >> no_of_elements >> segment >> total; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } const int oo = 1e9; vector > max_till(no_of_elements + 1, vector (total + 1, -oo)); max_till[0][total] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int remaining = total - 1; remaining >= 0; remaining--) { if(remaining == total) { max_till[i][remaining] = 0; continue; } for(int last = i - 1; last >= 0 && last >= i - segment; last--) { if(max_till[last][remaining + 1] != -oo) { max_till[i][remaining] = max(max_till[i][remaining], A[i] + max_till[last][remaining + 1]); } } //cout << "F(" << i << "," << remaining << ") = " << max_till[i][remaining] << "\n"; } } long long answer = -oo; for(int i = no_of_elements - segment + 1; i <= no_of_elements; i++) { answer = max(answer, max_till[i][0]); } cout << (answer == -oo ? -1 : answer) << "\n"; return 0; } ================================================ FILE: Contests/Div 3 521/Programs/Thematic Contests.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int get_count_ending(int ending, vector &A) { int count = 0; for(int i = A.size() - 1, current = ending; i >= 0 && A[i] >= current; i--) { count += current; if(current%2 == 1) { break; } current /= 2; } return count; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } map frequency; for(int i = 1; i <= no_of_elements; i++) { frequency[A[i]]++; } vector frequencies; for(auto it = frequency.begin(); it != frequency.end(); it++) { frequencies.push_back(it->second); } sort(all(frequencies)); int maximum = 0; for(int i = 0; i <= frequencies.back(); i++) { maximum = max(maximum, get_count_ending(i, frequencies)); } cout << maximum << "\n"; return 0; } ================================================ FILE: Contests/Div 3 531/Explanations/Array K Colouring Explanation.txt ================================================ We have to ensure that for all elements of a given value x, we use all k colours. So, let us sort the array by value. We will colour the first element in colour 1, second in colour 2 and so on. When we go to colour k + 1, we will check if that colour has already been used on such a colour. This approach works because - 1. We are using colours 1 by 1, so guaranteed each colour will be used once. 2. For a given value, we are using all k colours before using the same again. This greedy strategy helps us. -------- int main() { int no_of_elements, no_of_colours; cin >> no_of_elements >> no_of_colours; vector A(no_of_elements); for(int i=0; i < no_of_elements ;i++) { cin >> A[i].value; A[i].position=i; } sort(all(A)); vector last_brick_of_colour(no_of_colours + 1, 0); vector colour(no_of_elements + 1); for(int c = 0, i = 0; i < no_of_elements; i++, c = (c + 1)%no_of_colours) { if(last_brick_of_colour[c] == A[i].value) { cout << "NO\n"; return 0; } colour[A[i].position] = c; last_brick_of_colour[c] = A[i].value; } cout << "YES\n"; for(int i = 0; i < no_of_elements; i++) cout << colour[i] + 1 << " "; return 0; } ================================================ FILE: Contests/Div 3 531/Explanations/Balanced Ternary String Explanation.txt ================================================ We will do four operations at the end of which the string will be the lexicographically smallest balanced string. 1. The number of 0s is < N/3. Go through the string from beginning to end. Replace A[i] with 0 if frequency(A[i]) > N/3. This is because it is always better to put the new 0s in the leftmost positions rather than the rightmost ones. After we have finished this, we are guaranteed that the number of 0s is >= N/3. ------------- 2. The number of 2s is < N/3 Go through the string from end to beginning. Replace A[i] with 2 if frequency(A[i]) > N/3 It is always better to put 2s in the end rather than the beginning. After we have finished this, we are sure that the number of 2s is >= N/3. ------- Now, after these two operations, the number of 1s is <= N/3. If the number of 1s is > N/3, then one among the 0s and 2s have to be less than N/3 which is not possible. ---- So, all we need to do is place the remaining 1s. The excess 2s need to be replaced with 1. 3. We need to replace the rightmost 0s. Because it is always better. to post a 1 instead of a 0 in the end rather than in the beginning. 4. We need to replace the leftmost 2s. After we are done, the number of 1s is = N/3. The number of 2s and 0s are both >= N/3, which is only possible if both are = N/3. -------- So here are the four operations - 1. If the number of 0s is < N/3, place them as early as possible. 2. If the number of 2s is < N/3, place the 2s as late as possible. 3. If the 0s are in excess now, replace the latest 0s with 1s. 4. If the 2s are in excess now, replace the earliest 2s with 1s. ================================================ FILE: Contests/Div 3 531/Programs/Array K Colouring.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; struct bricks { int value, position; int operator<(const bricks &b) const { return (value < b.value); } }; int main() { int no_of_elements, no_of_colours; cin >> no_of_elements >> no_of_colours; vector A(no_of_elements); for(int i=0; i < no_of_elements ;i++) { cin >> A[i].value; A[i].position=i; } sort(all(A)); vector last_brick_of_colour(no_of_colours + 1, 0); vector colour(no_of_elements + 1); for(int c = 0, i = 0; i < no_of_elements; i++, c = (c + 1)%no_of_colours) { if(last_brick_of_colour[c] == A[i].value) { cout << "NO\n"; return 0; } colour[A[i].position] = c; last_brick_of_colour[c] = A[i].value; } cout << "YES\n"; for(int i = 0; i < no_of_elements; i++) cout << colour[i] + 1 << " "; return 0; } ================================================ FILE: Contests/Div 3 531/Programs/Balanced Ternary String.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); const int MAX = 3; vector frequency(MAX, 0); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%1d", &A[i]); frequency[A[i]]++; } for(int i = 1; i <= no_of_elements && frequency[0] < no_of_elements/3; i++) { if(A[i] != 0 && frequency[A[i]] > no_of_elements/3) { frequency[A[i]]--; frequency[0]++; A[i] = 0; } } for(int i = no_of_elements; i >= 1 && frequency[2] < no_of_elements/3; i--) { if(A[i] != 2 && frequency[A[i]] > no_of_elements/3) { frequency[A[i]]--; frequency[2]++; A[i] = 2; } } for(int i = 1; i <= no_of_elements && frequency[1] < no_of_elements/3 && frequency[2] > no_of_elements/3; i++) { if(A[i] == 2) { frequency[2]--; frequency[1]++; A[i] = 1; } } for(int i = no_of_elements; i >= 1 && frequency[1] < no_of_elements/3 && frequency[0] > no_of_elements/3; i--) { if(A[i] == 0) { frequency[0]--; frequency[1]++; A[i] = 1; } } for(int i = 1; i <= no_of_elements; i++) { printf("%d", A[i]); } return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Colored Boots Explanation.txt ================================================ We can be greedy. First, we will match alphabets to each other. Then we will map alphabets to question marks. And lastly, we will map the question marks to each other. It is important to map question marks to each other only after we have mapped question marks to alphabets. When we map question marks to alphabets, we get one pair for each question mark we have used. But, if we map question marks to each other first, then we will be left with at most one question mark in the end. We must map alphabets to each other first because we don't want to map any alphabet to a question mark if we can map it to another alphabet. Mapping alphabets to each other rather than to question marks does not reduce the number of pairs and generally increases it. ------- void match(char a, char b) { int common_elements = min(A_indices[a].size(), B_indices[b].size()); while(common_elements > 0) { pair current_pair = make_pair(A_indices[a].back(), B_indices[b].back()); answer.push_back(current_pair); A_indices[a].pop_back(); B_indices[b].pop_back(); common_elements--; } } int main() { int length; string A, B; cin >> length >> A >> B; for(int i = 0; i < length; i++) { A_indices[A[i]].push_back(i); B_indices[B[i]].push_back(i); } for(char ch = 'a'; ch <= 'z'; ch++) match(ch, ch); for(char ch = 'a'; ch <= 'z'; ch++) match('?', ch); for(char ch = 'a'; ch <= 'z'; ch++) match(ch, '?'); match('?', '?'); cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i].first + 1 << " " << answer[i].second + 1 << "\n"; } return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Game 23 Explanation.txt ================================================ We will make the power of 2 and 3 equal in m and n. If m and n are not equal after that, then it is impossible. Else, we are done. --- int main() { ULL target, source; cin >> source >> target; int target_power_of_2 = exponent(target, 2); int target_power_of_3 = exponent(target, 3); int source_power_of_2 = exponent(source, 2); int source_power_of_3 = exponent(source, 3); int no_of_moves = 0; for(int i = source_power_of_2 + 1; i <= target_power_of_2; i++) { if(source <= target/2) { source *= 2; no_of_moves++; } } for(int i = source_power_of_3 + 1; i <= target_power_of_3; i++) { if(source <= target/3) { source *= 3; no_of_moves++; } } const int IMPOSSIBLE = -1; cout << (source == target ? no_of_moves : IMPOSSIBLE); return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Maximal Continuous Rest Explanation.txt ================================================ We will use the normal DP to keep track of the largest substring. We also need to check the sum of the prefix and suffix. Ensure that the length of the substring is not greater than the length of the string ! --- int main() { int length; cin >> length; vector A(length + 1); for(int i = 1; i <= length; i++) cin >> A[i]; int maximum_1s_till_here = 0, maximum_1s = 0; for(int i = 1; i <= length; i++) { maximum_1s_till_here = (A[i] == 1 ? maximum_1s_till_here + 1 : 0); maximum_1s = max(maximum_1s, maximum_1s_till_here); } int prefix = 0; for(int i = 1; i <= length; i++) { if(A[i] != 1) break; prefix++; } int suffix = 0; for(int i = length; i >= 1; i--) { if(A[i] != 1) break; suffix++; } maximum_1s = max(maximum_1s, prefix + suffix); maximum_1s = min(maximum_1s, length); cout << maximum_1s; return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Polycarp Restores Permutation Explanation.txt ================================================ Let us notice that 1. The first element of the permutation uniquely determines the permutation. 2. If we can reach [p1, p2, ... , pn], then we can also reach [p1 + x, p2 + x, ... , pn + x]. Also note that we cannot reach any other permutation. So we will set p1 = 1 and generate a permutation P. Then, we will check if P is a block of n consecutive integers. Then we will have [1, p2, p3, ... , pn]. We can reach [1 + x, p2 + x, ... , pn + x]. We cannot reach any other permutation. --- To check if it is a block of n consecutive integers, we will first find the smallest element x in P. 1. If x <= 0, then we will add |x| + 1 to every element in P. 2. Let the maximum element in P be x. If x > n, then we will subtract |x - n| from every element in P. ------- After doing these two operations, P should be a permutation of [1, n]. Suppose P is a permutation, then we are done. If P is not a permutation, then it can be because of 2 reasons - 1. P has duplicates. This property will always hold. 2. P has some element that is not in [1, n]. This property will also always be true regardless of the first element. ---- int main() { int length; cin >> length; vector difference(length); for(int i = 1; i <= length - 1; i++) cin >> difference[i]; vector permutation(length + 1); permutation[1] = 1; int minimum = 1, maximum = 1; for(int i = 2; i <= length; i++) { permutation[i] = permutation[i - 1] + difference[i - 1]; minimum = min(minimum, permutation[i]); maximum = max(maximum, permutation[i]); } if(minimum < 1) { for(int i = 1; i <= length; i++) permutation[i] += abs(minimum) + 1; } if(maximum > length) { for(int i = 1; i <= length; i++) permutation[i] -= (maximum - length); } int is_permutation = true; vector frequency(length + 1, 0); for(int i = 1; i <= length; i++) { if(permutation[i] < 1 || permutation[i] > length) { is_permutation = false; continue; } frequency[permutation[i]]++; } for(int i = 1; i <= length; i++) { if(frequency[i] != 1) is_permutation = false; } if(!is_permutation) { cout << "-1\n"; return 0; } for(int i = 1; i <= length; i++) cout << permutation[i] << " "; return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Privatization of Roads in Berland Explanation.txt ================================================ Let us make an observation - If we colour the edges with D colours, then every vertex with more than D edges will have 2 edges of the same colour Let us keep track of the degree of each vertex. We will make a suffix sum array over the array of frequencies of every degree. Let us look at the rightmost i, such that Suffix Sum[i] > k, If we paint the graph in (i - 1) colours, then all of the Suffix Sum[i] vertices will have 2 monochromatic edges, which is more than k So that means (i - 1) or fewer colours is not possible. Then, i is the answer. ----- Now, we will see how we will colour the edges in exactly i colours We will do a DFS and keep track of which colour the edge {Parent[v], v} was painted in Suppose it was painted in colour c, then we will paint the first edge of v (c + 1) mod k, then the next edge (c + 2) mod k, and so on This ensures that only those vertices with degree > i, have two edges of the same colour and this number will not be more than K ----- #include #include using namespace std; const int MAX_N = 2e5 + 5; int no_of_colours = 0; vector < pair > tree[MAX_N]; vector colour(MAX_N, 0); void dfs(int v, int parent_v, int last_colour) { int next_colour = (last_colour + 1)%no_of_colours; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i].first; if(child_v == parent_v) { continue; } colour[tree[v][i].second] = next_colour; dfs(child_v, v, next_colour); next_colour = (next_colour + 1)%no_of_colours; } } int main() { int no_of_vertices, k; cin >> no_of_vertices >> k; vector degree(no_of_vertices + 1, 0); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(make_pair(v, i)); tree[v].push_back(make_pair(u, i)); degree[u]++; degree[v]++; } vector frequency(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { frequency[degree[i]]++; } vector suffix_sum(no_of_vertices + 5, 0); for(int i = no_of_vertices; i >= 1; i--) { suffix_sum[i] = suffix_sum[i + 1] + frequency[i]; } for(int i = no_of_vertices; i >= 1; i--) { if(suffix_sum[i] > k) { no_of_colours = i; break; } } dfs(1, 0, -1); cout << no_of_colours << "\n"; for(int i = 1; i <= no_of_edges; i++) { cout << colour[i] + 1 << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Same Sum Blocks Explanation.txt ================================================ Let us do this problem by brute force. We will solve the problem independently for every sum possible. There are O(n^2) possible sums. For each sum, we will keep track of all the segments [L, R] such that Sum[L, R] = x Then, for each sum x, we will find the maximum number of segments we can choose. We can do this greedily by choosing the first available segment at each point. Note that the segments are already sorted by right so we don't need to sort them again . ----- struct segment { int left, right; segment(){} segment(int L, int R) { left = L; right = R; } }; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = A[i] + prefix_sum[i - 1]; } map > sum_blocks; for(int r = 1; r <= no_of_elements; r++) { for(int l = 1; l <= r; l++) { int sum = prefix_sum[r] - prefix_sum[l - 1]; sum_blocks[sum].push_back(segment(l, r)); } } vector answer; for(auto it = sum_blocks.begin(); it != sum_blocks.end(); it++) { int sum = it->first; vector answer_here; int last_right = -1; ; for(int i = 0; i < sum_blocks[sum].size(); i++) { if(sum_blocks[sum][i].left > last_right) { answer_here.push_back(sum_blocks[sum][i]); last_right = sum_blocks[sum][i].right; } } if(answer_here.size() > answer.size()) { answer = answer_here; } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i].left << " " << answer[i].right << "\n"; } return 0; } ================================================ FILE: Contests/Div 3 547/Explanations/Superhero Battle Explanation.txt ================================================ First, let us check if it is possible in less than 1 round. Then, we will check that the sum of the entire array is not non negative. If it is, then we will never find an answer. Suppose it isn't, we will always find an answer. The answer will consist of some number of full cycles followed by a partial cycle. Now, it might be an error if we try to write H as H = q.P[n] + r 1000 6 -100 -200 -300 125 77 -4 Is the test case for this. If we calculate the number of total cycles as 1000/Sum, it gives us 2 cycles and then 2 more elements leading to 14 steps. But, there is actually an answer in 9 steps. To capture such answers, we have to do something slightly different. We will iterate over each i from 1 to N, and calculate the number of cycles required for the game to end at this i, Find the x, so that H + x.P[n] + P[i] ≤ 0 For finding x, we have to divide (H + P[i])/x and take the ceil of it ----- #include #include using namespace std; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } int main() { long long H, no_of_elements; cin >> H >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = A[i] + prefix_sum[i - 1]; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { if(H + prefix_sum[i] <= 0) { answer = i; break; } } long long sum = abs(prefix_sum[no_of_elements]); if(answer != 0) { cout << answer << "\n"; return 0; } else if(prefix_sum[no_of_elements] >= 0) { cout << "-1\n"; return 0; } answer = 2e18; for(int i = 1; i <= no_of_elements; i++) { //H + x.P[n] + P[i] = 0 long long rounds_required = ceil(H + prefix_sum[i], sum); answer = min(answer, rounds_required*no_of_elements + i); } cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Colored Boots.cpp ================================================ #include #include #include using namespace std; const int MAX_SIZE = 200; vector A_indices[MAX_SIZE], B_indices[MAX_SIZE]; vector > answer; void match(char a, char b) { int common_elements = min(A_indices[a].size(), B_indices[b].size()); while(common_elements > 0) { pair current_pair = make_pair(A_indices[a].back(), B_indices[b].back()); answer.push_back(current_pair); A_indices[a].pop_back(); B_indices[b].pop_back(); common_elements--; } } int main() { int length; string A, B; cin >> length >> A >> B; for(int i = 0; i < length; i++) { A_indices[A[i]].push_back(i); B_indices[B[i]].push_back(i); } for(char ch = 'a'; ch <= 'z'; ch++) match(ch, ch); for(char ch = 'a'; ch <= 'z'; ch++) match('?', ch); for(char ch = 'a'; ch <= 'z'; ch++) match(ch, '?'); match('?', '?'); cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i].first + 1 << " " << answer[i].second + 1 << "\n"; } return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Game 23.cpp ================================================ #include using namespace std; typedef unsigned long long ULL; int exponent(ULL n, ULL divisor) { int exp = 0; while(n%divisor == 0) { n /= divisor; exp++; } return exp; } int main() { ULL target, source; cin >> source >> target; int target_power_of_2 = exponent(target, 2); int target_power_of_3 = exponent(target, 3); int source_power_of_2 = exponent(source, 2); int source_power_of_3 = exponent(source, 3); int no_of_moves = 0; for(int i = source_power_of_2 + 1; i <= target_power_of_2; i++) { if(source <= target/2) { source *= 2; no_of_moves++; } } for(int i = source_power_of_3 + 1; i <= target_power_of_3; i++) { if(source <= target/3) { source *= 3; no_of_moves++; } } const int IMPOSSIBLE = -1; cout << (source == target ? no_of_moves : IMPOSSIBLE); return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Maximal Continuous Rest.cpp ================================================ #include #include using namespace std; int main() { int length; cin >> length; vector A(length + 1); for(int i = 1; i <= length; i++) cin >> A[i]; int maximum_1s_till_here = 0, maximum_1s = 0; for(int i = 1; i <= length; i++) { maximum_1s_till_here = (A[i] == 1 ? maximum_1s_till_here + 1 : 0); maximum_1s = max(maximum_1s, maximum_1s_till_here); } int prefix = 0; for(int i = 1; i <= length; i++) { if(A[i] != 1) break; prefix++; } int suffix = 0; for(int i = length; i >= 1; i--) { if(A[i] != 1) break; suffix++; } maximum_1s = max(maximum_1s, prefix + suffix); maximum_1s = min(maximum_1s, length); cout << maximum_1s; return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Polycarp Restores Permutation.cpp ================================================ #include #include #include using namespace std; int main() { int length; cin >> length; vector difference(length); for(int i = 1; i <= length - 1; i++) cin >> difference[i]; vector permutation(length + 1); permutation[1] = 1; int minimum = 1, maximum = 1; for(int i = 2; i <= length; i++) { permutation[i] = permutation[i - 1] + difference[i - 1]; minimum = min(minimum, permutation[i]); maximum = max(maximum, permutation[i]); } if(minimum < 1) { for(int i = 1; i <= length; i++) permutation[i] += abs(minimum) + 1; } if(maximum > length) { for(int i = 1; i <= length; i++) permutation[i] -= (maximum - length); } int is_permutation = true; vector frequency(length + 1, 0); for(int i = 1; i <= length; i++) { if(permutation[i] < 1 || permutation[i] > length) { is_permutation = false; continue; } frequency[permutation[i]]++; } for(int i = 1; i <= length; i++) { if(frequency[i] != 1) is_permutation = false; } if(!is_permutation) { cout << "-1\n"; return 0; } for(int i = 1; i <= length; i++) cout << permutation[i] << " "; return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Privatization of Roads in Berland.cpp ================================================ #include #include using namespace std; const int MAX_N = 2e5 + 5; int no_of_colours = 0; vector < pair > tree[MAX_N]; vector colour(MAX_N, 0); void dfs(int v, int parent_v, int last_colour) { int next_colour = (last_colour + 1)%no_of_colours; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i].first; if(child_v == parent_v) { continue; } colour[tree[v][i].second] = next_colour; dfs(child_v, v, next_colour); next_colour = (next_colour + 1)%no_of_colours; } } int main() { int no_of_vertices, k; cin >> no_of_vertices >> k; vector degree(no_of_vertices + 1, 0); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges; i++) { int u, v; cin >> u >> v; tree[u].push_back(make_pair(v, i)); tree[v].push_back(make_pair(u, i)); degree[u]++; degree[v]++; } vector frequency(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) { frequency[degree[i]]++; } vector suffix_sum(no_of_vertices + 5, 0); for(int i = no_of_vertices; i >= 1; i--) { suffix_sum[i] = suffix_sum[i + 1] + frequency[i]; } for(int i = no_of_vertices; i >= 1; i--) { if(suffix_sum[i] > k) { no_of_colours = i; break; } } dfs(1, 0, -1); cout << no_of_colours << "\n"; for(int i = 1; i <= no_of_edges; i++) { cout << colour[i] + 1 << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Same Sum Blocks.cpp ================================================ #include #include #include using namespace std; struct segment { int left, right; segment(){} segment(int L, int R) { left = L; right = R; } }; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = A[i] + prefix_sum[i - 1]; } map > sum_blocks; for(int r = 1; r <= no_of_elements; r++) { for(int l = 1; l <= r; l++) { int sum = prefix_sum[r] - prefix_sum[l - 1]; sum_blocks[sum].push_back(segment(l, r)); } } vector answer; for(auto it = sum_blocks.begin(); it != sum_blocks.end(); it++) { int sum = it->first; vector answer_here; int last_right = -1; ; for(int i = 0; i < sum_blocks[sum].size(); i++) { if(sum_blocks[sum][i].left > last_right) { answer_here.push_back(sum_blocks[sum][i]); last_right = sum_blocks[sum][i].right; } } if(answer_here.size() > answer.size()) { answer = answer_here; } } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) { cout << answer[i].left << " " << answer[i].right << "\n"; } return 0; } ================================================ FILE: Contests/Div 3 547/Programs/Superhero Battle.cpp ================================================ #include #include using namespace std; long long ceil(long long n, long long d) { return (n/d) + (n%d != 0); } int main() { long long H, no_of_elements; cin >> H >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } vector prefix_sum(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { prefix_sum[i] = A[i] + prefix_sum[i - 1]; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { if(H + prefix_sum[i] <= 0) { answer = i; break; } } long long sum = abs(prefix_sum[no_of_elements]); if(answer != 0) { cout << answer << "\n"; return 0; } else if(prefix_sum[no_of_elements] >= 0) { cout << "-1\n"; return 0; } answer = 2e18; for(int i = 1; i <= no_of_elements; i++) { //H + x.P[n] + P[i] = 0 long long rounds_required = ceil(H + prefix_sum[i], sum); answer = min(answer, rounds_required*no_of_elements + i); } cout << answer << "\n"; return 0; } ================================================ FILE: Contests/Div 3 590/Explanations/Special Permutations Explanation.txt ================================================ We can interpret the array X as a set of segments on the permutation. We can calculate answer[1] naively. After that we can use answer[1] to build answer[i] for all 2 <= i <= n Let us see how each of the segments are affected when we are calculating answer[i] 1. If X[j] and X[i=j + 1] contains the point i, then it reduces by 1 2. If X[j] = 1 or X[j + 1] = 1, then the answer reduces by a. -abs(X[j] - X[j + 1]) + abs(1 - X[j + 1]), if X[j + 1] > i 2. -abs(X[j] - X[j + 1]) + abs(1 - X[j + 1] - 1), if X[j + 1] < i ------ We need 2 pieces of information to update answer[i] 1. The number of segments covering i 2. The pairs adjacent to i ----- Let us see how we will calculate the number of segments covering i We will put a +1 when a segment starts and a -1 when a segment ends. A segment [L, R] covers all the points [L + 1, R - 1] and we will exclude the borders The reason is we are handling the case when i is a border separately ----- vector segments_starting_at(n + 1, 0); vector segments_ending_at(n + 1, 0); for(int i = 1; i < no_of_elements; i++) { if(abs(X[i] - X[i + 1]) >= 2) { segments_starting_at[min(X[i], X[i + 1]) + 1]++; segments_ending_at[max(X[i], X[i + 1]) - 1]++; } } vector segments_covering(n + 1, 0); for(int i = 1; i <= n; i++) { segments_covering[i] = segments_covering[i - 1] + segments_starting_at[i] - segments_ending_at[i - 1]; } ----- We will collect all pairs like this - ----- vector > pairs(n + 1); for(int i = 1; i < no_of_elements; i++) { pairs[X[i]].push_back(X[i + 1]); pairs[X[i + 1]].push_back(X[i]); } ----- After that, we will calculate the contribution to each pair like this Every element in [1, i - 1] would have shifted 1 position to the right and every element in [i + 1, N] would have shifted 1 position to the left Of course (i - i) = 0 so we do not need to change it ----- for(int i = 2; i <= n; i++) { answer[i] = answer[1] - segments_covering[i]; for(int j = 0; j < pairs[i].size(); j++) { int d = pairs[i][j]; if(d == i) { continue; } if(d < i) { answer[i] += abs(d + 1 - 1) - abs(d - i); } if(d > i) { answer[i] += abs(d - 1) - abs(d - i); } } } ================================================ FILE: Contests/Div 3 590/Explanations/Yet Another Substring Reverse Explanation.txt ================================================ The act of reversing a substring means we can bring any 2 substrings together. We will represent every substring of distinct characters by a mask of length 20. The i-th bit is set if it contains the i-th alphabet and 0 otherwise. We will maintain a bitmask for every substring and will see which 2 bitmasks produce the most 1s when combined. We can't do it in O(m^2) time, where m is the maximum mask. Instead we will maintain f(m) where f(m) is true if it is possible to reach at most m. So, f(m) = max(f(m')), where m' is a mask obtained by unsetting exactly 1 set bit in m ----- #include #include using namespace std; int no_of_bits(long long n) { int bits = 0; while(n) { bits += n%2; n /= 2; } return bits; } long long set_bit(long long n, int bit) { n |= (1LL << bit); return n; } int is_bit_set(long long n, int bit) { return ( (n&(1LL <> S; const int NO_OF_LETTERS = 20; int length = S.size(); long long max_mask = (1LL << NO_OF_LETTERS); vector max_distinct(max_mask, 0); for(int i = 0; i < S.size(); i++) { int current_mask = 0; for(int j = i; j < S.size(); j++) { if(is_bit_set(current_mask, S[j] - 'a')) { break; } current_mask = set_bit(current_mask, S[j] - 'a'); max_distinct[current_mask] = j - (i - 1); //cout << "Max Distinct " << current_mask << " = " << max_distinct[current_mask] << "\n"; } } for(int mask = 0; mask < max_mask; mask++) { for(int bit = 0; bit < NO_OF_LETTERS; bit++) { if(is_bit_set(mask, bit)) { max_distinct[mask] = max(max_distinct[mask], max_distinct[mask^(1LL << bit)]); } } } long long answer = 0; for(int mask = 0; mask < max_mask; mask++) { if(max_distinct[mask] != no_of_bits(mask)) { continue; } int complement = (max_mask - 1)^mask; answer = max(answer, max_distinct[mask] + max_distinct[complement]); } cout << answer; return 0; } ================================================ FILE: Contests/Div 3 590/Programs/Special Permutations.cpp ================================================ #include #include using namespace std; int main() { int n, no_of_elements; cin >> n >> no_of_elements; vector X(no_of_elements + 1); vector position(n + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> X[i]; position[X[i]] = X[i]; } vector > pairs(n + 1); vector segments_starting_at(n + 1, 0); vector segments_ending_at(n + 1, 0); for(int i = 1; i < no_of_elements; i++) { if(abs(X[i] - X[i + 1]) >= 2) { segments_starting_at[min(X[i], X[i + 1]) + 1]++; segments_ending_at[max(X[i], X[i + 1]) - 1]++; } pairs[X[i]].push_back(X[i + 1]); pairs[X[i + 1]].push_back(X[i]); } vector segments_covering(n + 1, 0); for(int i = 1; i <= n; i++) { segments_covering[i] = segments_covering[i - 1] + segments_starting_at[i] - segments_ending_at[i - 1]; } vector answer(n + 1, 0); for(int i = 1; i < no_of_elements; i++) { answer[1] += abs(X[i] - X[i + 1]); } for(int i = 2; i <= n; i++) { answer[i] = answer[1] - segments_covering[i]; for(int j = 0; j < pairs[i].size(); j++) { int d = pairs[i][j]; if(d == i) { continue; } if(d < i) { answer[i] += abs(d + 1 - 1) - abs(d - i); } if(d > i) { answer[i] += abs(d - 1) - abs(d - i); } } } for(int i = 1; i <= n; i++) { cout << answer[i] << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 590/Programs/Yet Another Substring Reverse.cpp ================================================ #include #include using namespace std; int no_of_bits(long long n) { int bits = 0; while(n) { bits += n%2; n /= 2; } return bits; } long long set_bit(long long n, int bit) { n |= (1LL << bit); return n; } int is_bit_set(long long n, int bit) { return ( (n&(1LL <> S; const int NO_OF_LETTERS = 20; int length = S.size(); long long max_mask = (1LL << NO_OF_LETTERS); vector max_distinct(max_mask, 0); for(int i = 0; i < S.size(); i++) { int current_mask = 0; for(int j = i; j < S.size(); j++) { if(is_bit_set(current_mask, S[j] - 'a')) { break; } current_mask = set_bit(current_mask, S[j] - 'a'); max_distinct[current_mask] = j - (i - 1); //cout << "Max Distinct " << current_mask << " = " << max_distinct[current_mask] << "\n"; } } for(int mask = 0; mask < max_mask; mask++) { for(int bit = 0; bit < NO_OF_LETTERS; bit++) { if(is_bit_set(mask, bit)) { max_distinct[mask] = max(max_distinct[mask], max_distinct[mask^(1LL << bit)]); } } } long long answer = 0; for(int mask = 0; mask < max_mask; mask++) { if(max_distinct[mask] != no_of_bits(mask)) { continue; } int complement = (max_mask - 1)^mask; answer = max(answer, max_distinct[mask] + max_distinct[complement]); } cout << answer; return 0; } ================================================ FILE: Contests/Div 3 593/Explanations/Books Exchange Explanation.txt ================================================ Let us draw a graph and create an edge between vertice (i, P[i]). For each i, we want to know the length of the cycle it is in. We can do this in a DFS. Note - Every vertex is visited only one time. So, the complexity is O(n) even though there are 2 for loops :) ------ void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } vector visited(no_of_elements + 1, false); vector cycle_length(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { if(visited[i]) { continue; } vector cycle; int v = i; while(!visited[v]) { visited[v] = true; cycle.push_back(v); v = P[v]; } for(int g = 0; g < cycle.size(); g++) { int v = cycle[g]; cycle_length[v] = cycle.size(); } } for(int i = 1; i <= no_of_elements; i++) { cout << cycle_length[i] << " "; } cout << "\n"; } ================================================ FILE: Contests/Div 3 593/Explanations/By Elevator or Stairs Explanation.txt ================================================ Let f(i, STAIRS) be the minimium time required to reach floor i using the stairs in the end. Let f(i, ELEVATOR) be the minimum time required to reach floor i using the elevator in the end. Now, let us calculate the transitions. The base case is f(1, STARIS) = 0, f(1, ELEVATOR) = overhead ----- f(i, STAIRS) = stairs[i - 1] + min{f(i - 1, STAIRS), f(i - 1, ELEVATOR)} f(i, ELEVATOR) = elevator[i - 1] + min{f(i - 1, ELEVATOR), f(i - 1, STAIRS) + overhead} --- int main() { int no_of_floors, overhead; cin >> no_of_floors >> overhead; vector stairs(no_of_floors + 1, 0); for(int i = 1; i < no_of_floors; i++) { cin >> stairs[i]; } vector elevator(no_of_floors + 1, 0); for(int i = 1; i < no_of_floors; i++) { cin >> elevator[i]; } const int STAIRS = 0, ELEVATOR = 1; vector > minimum_time(no_of_floors + 1, vector (2, 0)); minimum_time[1][STAIRS] = 0, minimum_time[1][ELEVATOR] = overhead; for(int i = 2; i <= no_of_floors; i++) { minimum_time[i][STAIRS] = stairs[i - 1] + min(minimum_time[i - 1][STAIRS], minimum_time[i - 1][ELEVATOR]); minimum_time[i][ELEVATOR] = elevator[i - 1] + min(minimum_time[i - 1][ELEVATOR], minimum_time[i - 1][STAIRS] + overhead); } for(int i = 1; i <= no_of_floors; i++) { cout << min(minimum_time[i][STAIRS], minimum_time[i][ELEVATOR]) << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 593/Explanations/Good Numbers Explanation.txt ================================================ Let us write each number in ternary base. A few facts - 1. 1000 > 0222 This can be proved by summing the series 2.3^n + 2.3^{n - 1} + ... + 2.3^0 = 2 (3^{n + 1} - 1)/2 = 3^{n + 1} - 1 ---- If the number in ternary has only 1s and 0s, then it is a good number. Otherwise there is some 2. Suppose there is some 2 at position k. We want to make this 0. So, we will have to make (k)th position 0, we will have to make increase some other position to it's left. (To maintain the invairant m >= n). We cannot make any 1 a 2. So, we will make some 0 a 1. Once, we will a 0 to a 1, we will make all bits to it's right 0. For example, suppose the integer was 100012121002112, then we will make it 100012121002112 100100000000000 --- void solve() { unsigned long long n; cin >> n; unsigned long long temp_n = n; vector exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i >= 0; i--) { while(temp_n >= powers[i]) { temp_n -= powers[i]; exponent[i]++; } } int left_most_2 = powers.size(); for(int i = powers.size() - 1; i >= 0; i--) { if(exponent[i] == 2) { left_most_2 = i; break; } } if(left_most_2 == powers.size()) { cout << n << "\n"; return; } int next_zero = left_most_2; for(int i = left_most_2; i < powers.size(); i++) { if(exponent[i] == 0) { next_zero = i; break; } } vector answer_exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i > next_zero; i--) answer_exponent[i] = exponent[i]; answer_exponent[next_zero] = 1; for(int i = next_zero - 1; i >= 0; i--) { answer_exponent[i] = 0; } unsigned long long answer = 0; for(int i = 0; i < powers.size(); i++) { answer += answer_exponent[i]*powers[i]; } cout << answer << "\n"; } ================================================ FILE: Contests/Div 3 593/Explanations/Yet Another Dividing Into Teams Explanation.txt ================================================ If there are no consecutive integers, then we can have 1 team. Otherwise, we can have 1 team for the odd integers and 1 team for the even integers. ------ void solve() { int no_of_people; cin >> no_of_people; const int MAX = 105; vector present(MAX + 1, false); for(int i = 1; i <= no_of_people; i++) { int skill; cin >> skill; present[skill] = true; } int no_of_teams = 1; for(int i = 1; i < MAX; i++) { if(present[i] && present[i + 1]) { no_of_teams = 2; break; } } cout << no_of_teams << "\n"; } ================================================ FILE: Contests/Div 3 593/Programs/Books Exchange.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } vector visited(no_of_elements + 1, false); vector cycle_length(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { if(visited[i]) { continue; } vector cycle; int v = i; while(!visited[v]) { visited[v] = true; cycle.push_back(v); v = P[v]; } for(int g = 0; g < cycle.size(); g++) { int v = cycle[g]; cycle_length[v] = cycle.size(); } } for(int i = 1; i <= no_of_elements; i++) { cout << cycle_length[i] << " "; } cout << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 593/Programs/Elevator or Stairs.cpp ================================================ #include #include using namespace std; int main() { int no_of_floors, overhead; cin >> no_of_floors >> overhead; vector stairs(no_of_floors + 1, 0); for(int i = 1; i < no_of_floors; i++) { cin >> stairs[i]; } vector elevator(no_of_floors + 1, 0); for(int i = 1; i < no_of_floors; i++) { cin >> elevator[i]; } const int STAIRS = 0, ELEVATOR = 1; vector > minimum_time(no_of_floors + 1, vector (2, 0)); minimum_time[1][STAIRS] = 0, minimum_time[1][ELEVATOR] = overhead; for(int i = 2; i <= no_of_floors; i++) { minimum_time[i][STAIRS] = stairs[i - 1] + min(minimum_time[i - 1][STAIRS], minimum_time[i - 1][ELEVATOR]); minimum_time[i][ELEVATOR] = elevator[i - 1] + min(minimum_time[i - 1][ELEVATOR], minimum_time[i - 1][STAIRS] + overhead); } for(int i = 1; i <= no_of_floors; i++) { cout << min(minimum_time[i][STAIRS], minimum_time[i][ELEVATOR]) << " "; } cout << "\n"; return 0; } ================================================ FILE: Contests/Div 3 593/Programs/Good Numbers.cpp ================================================ #include #include #include using namespace std; const unsigned long long MAX_P = 55, oo = LLONG_MAX; unsigned long long max_good = 0; vector powers; void precompute() { powers.push_back(1); unsigned long long n = 1; while(n <= oo/3) { n = n*3ULL; powers.push_back(n); } } void display(unsigned long long n) { long long temp_n = n; vector exponent(powers.size(), 0); for(int i = powers.size() - 1; i >= 0; i--) { while(temp_n >= powers[i]) { temp_n -= powers[i]; exponent[i]++; } } for(int i = powers.size() - 1; i >= 0; i--) { cout << exponent[i]; } cout << "\n"; } void solve() { unsigned long long n; cin >> n; unsigned long long temp_n = n; vector exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i >= 0; i--) { while(temp_n >= powers[i]) { temp_n -= powers[i]; exponent[i]++; } } int left_most_2 = powers.size(); for(int i = powers.size() - 1; i >= 0; i--) { if(exponent[i] == 2) { left_most_2 = i; break; } } if(left_most_2 == powers.size()) { cout << n << "\n"; return; } int next_zero = left_most_2; for(int i = left_most_2; i < powers.size(); i++) { if(exponent[i] == 0) { next_zero = i; break; } } vector answer_exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i > next_zero; i--) answer_exponent[i] = exponent[i]; answer_exponent[next_zero] = 1; for(int i = next_zero - 1; i >= 0; i--) { answer_exponent[i] = 0; } unsigned long long answer = 0; for(int i = 0; i < powers.size(); i++) { answer += answer_exponent[i]*powers[i]; } cout << answer << "\n"; } int main() { precompute(); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 593/Programs/Yet Another Dividing Into Teams.cpp ================================================ #include #include using namespace std; void solve() { int no_of_people; cin >> no_of_people; const int MAX = 105; vector present(MAX + 1, false); for(int i = 1; i <= no_of_people; i++) { int skill; cin >> skill; present[skill] = true; } int no_of_teams = 1; for(int i = 1; i < MAX; i++) { if(present[i] && present[i + 1]) { no_of_teams = 2; break; } } cout << no_of_teams << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 595/Explanations/Books Exchange Explanation.txt ================================================ Let us draw a graph and create an edge between vertice (i, P[i]). For each i, we want to know the length of the cycle it is in. We can do this in a DFS. Note - Every vertex is visited only one time. So, the complexity is O(n) even though there are 2 for loops :) ------ void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } vector visited(no_of_elements + 1, false); vector cycle_length(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { if(visited[i]) { continue; } vector cycle; int v = i; while(!visited[v]) { visited[v] = true; cycle.push_back(v); v = P[v]; } for(int g = 0; g < cycle.size(); g++) { int v = cycle[g]; cycle_length[v] = cycle.size(); } } for(int i = 1; i <= no_of_elements; i++) { cout << cycle_length[i] << " "; } cout << "\n"; } ================================================ FILE: Contests/Div 3 595/Explanations/Good Numbers Explanation.txt ================================================ Let us write each number in ternary base. A few facts - 1. 1000 > 0222 This can be proved by summing the series 2.3^n + 2.3^{n - 1} + ... + 2.3^0 = 2 (3^{n + 1} - 1)/2 = 3^{n + 1} - 1 ---- If the number in ternary has only 1s and 0s, then it is a good number. Otherwise there is some 2. Suppose there is some 2 at position k. We want to make this 0. So, we will have to make (k)th position 0, we will have to make increase some other position to it's left. (To maintain the invairant m >= n). If we have to remove a 2 from position k, we need to add another 3^k to this integer. This makes the next position 3^{k + 1} and increases it from either 0 to 1 or from 1 to 2. We do not want to make any 1 a 2. So we will continue this till we find a 0 and make it a 1. We cannot increase any 1 to a 2. So, we will increase some 0 a 1. Among all 0s, we will choose the first 0 to the left of the 2. Once, we will a 0 to a 1, we will make all bits to it's right 0. ---- The reason is that 10000 > 02222 ---- For example, suppose the integer was 100012121002112, then we will make it 100012121002112 100100000000000 --- void solve() { unsigned long long n; cin >> n; unsigned long long temp_n = n; vector exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i >= 0; i--) { while(temp_n >= powers[i]) { temp_n -= powers[i]; exponent[i]++; } } int left_most_2 = powers.size(); for(int i = powers.size() - 1; i >= 0; i--) { if(exponent[i] == 2) { left_most_2 = i; break; } } if(left_most_2 == powers.size()) { cout << n << "\n"; return; } int next_zero = left_most_2; for(int i = left_most_2; i < powers.size(); i++) { if(exponent[i] == 0) { next_zero = i; break; } } vector answer_exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i > next_zero; i--) answer_exponent[i] = exponent[i]; answer_exponent[next_zero] = 1; for(int i = next_zero - 1; i >= 0; i--) { answer_exponent[i] = 0; } unsigned long long answer = 0; for(int i = 0; i < powers.size(); i++) { answer += answer_exponent[i]*powers[i]; } cout << answer << "\n"; } ================================================ FILE: Contests/Div 3 595/Explanations/Yet Another Dividing Into Teams Explanation.txt ================================================ If there are no consecutive integers, then we can have 1 team. Otherwise, we can have 1 team for the odd integers and 1 team for the even integers. ------ void solve() { int no_of_people; cin >> no_of_people; const int MAX = 105; vector present(MAX + 1, false); for(int i = 1; i <= no_of_people; i++) { int skill; cin >> skill; present[skill] = true; } int no_of_teams = 1; for(int i = 1; i < MAX; i++) { if(present[i] && present[i + 1]) { no_of_teams = 2; break; } } cout << no_of_teams << "\n"; } ================================================ FILE: Contests/Div 3 595/Programs/Books Exchange.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector P(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> P[i]; } vector visited(no_of_elements + 1, false); vector cycle_length(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { if(visited[i]) { continue; } vector cycle; int v = i; while(!visited[v]) { visited[v] = true; cycle.push_back(v); v = P[v]; } for(int g = 0; g < cycle.size(); g++) { int v = cycle[g]; cycle_length[v] = cycle.size(); } } for(int i = 1; i <= no_of_elements; i++) { cout << cycle_length[i] << " "; } cout << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 595/Programs/Good Numbers.cpp ================================================ #include #include #include using namespace std; const unsigned long long MAX_P = 55, oo = LLONG_MAX; unsigned long long max_good = 0; vector powers; void precompute() { powers.push_back(1); unsigned long long n = 1; while(n <= oo/3) { n = n*3ULL; powers.push_back(n); } } void display(unsigned long long n) { long long temp_n = n; vector exponent(powers.size(), 0); for(int i = powers.size() - 1; i >= 0; i--) { while(temp_n >= powers[i]) { temp_n -= powers[i]; exponent[i]++; } } for(int i = powers.size() - 1; i >= 0; i--) { cout << exponent[i]; } cout << "\n"; } void solve() { unsigned long long n; cin >> n; unsigned long long temp_n = n; vector exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i >= 0; i--) { while(temp_n >= powers[i]) { temp_n -= powers[i]; exponent[i]++; } } int left_most_2 = powers.size(); for(int i = powers.size() - 1; i >= 0; i--) { if(exponent[i] == 2) { left_most_2 = i; break; } } if(left_most_2 == powers.size()) { cout << n << "\n"; return; } int next_zero = left_most_2; for(int i = left_most_2; i < powers.size(); i++) { if(exponent[i] == 0) { next_zero = i; break; } } vector answer_exponent(powers.size() + 5, 0); for(int i = powers.size() - 1; i > next_zero; i--) answer_exponent[i] = exponent[i]; answer_exponent[next_zero] = 1; for(int i = next_zero - 1; i >= 0; i--) { answer_exponent[i] = 0; } unsigned long long answer = 0; for(int i = 0; i < powers.size(); i++) { answer += answer_exponent[i]*powers[i]; } cout << answer << "\n"; } int main() { precompute(); int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 595/Programs/Yet Another Dividing Into Teams.cpp ================================================ #include #include using namespace std; void solve() { int no_of_people; cin >> no_of_people; const int MAX = 105; vector present(MAX + 1, false); for(int i = 1; i <= no_of_people; i++) { int skill; cin >> skill; present[skill] = true; } int no_of_teams = 1; for(int i = 1; i < MAX; i++) { if(present[i] && present[i + 1]) { no_of_teams = 2; break; } } cout << no_of_teams << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Div 3 598/Explanations/Equalizing Two Strings Explanation.txt ================================================ https://qr.ae/TW4mma 1. If S and T do not all have the same letters, then we cannot make them equal. --- 2. Let us suppose S and T have the same letters and some letter occurs twice. S = A ... S .. S ... T = ......X ... Y ... (Let us assume that the letter S occurs twice). We will flip the segment of length such that [S, S] come together in S and do some arbitrary flip of the same length in T. After this, we will swap adjacent elements in T to make it equal to S, and always choose the segment [SS] in S. This makes sure that S does not change at any step and is the same as making T = S, given that we can swap adjacent elements in T and T has the same elements as S. --- 3. Now, let us suppose that each letter occurs only one time. They are both permutations. A very important quality of permutations is their parity. Let us observe what happens to permutations' inversions, when we flip their parity. (Inversions is the number of pairs (i, j) such that A[i] > A[j] and (i < j). In other words, the number of pairs that are 'out of order'.) --- Let us suppose that S' is a segment of S. There are 3 types of inversions in S. i. Both the characters lie in S ii. One Character lies in S and the other lies in S' iii. Both the characters lie in S' Type i and Type ii inversions are not affected by reversing S' Let us see how the Type iii inversions change. Suppose there were originally X inversions in the segment S'. Then, when we flip S', the number of inversions becomes C(|S'|,2) - X. Suppose C(|S'|, 2) is even, then the parity of the number of inversions remains the same. Suppose C(|S'|, 2) is odd, then it flips the parity of the number of inversions. Amazingly, the parity of the inversions depends only on the length of the segment we reverse and not at all on the permutation itself ! --- At each flip, either the parity of both S and T are the same or the parity of both S and T get flipped. This means that if their parities are initially not equal, they will remain so at each step. We can check the parity in O(n^2) time since the length of a distinct string (permutation) can be at most 26. --- Suppose the parities are equal, is it always possible to make S = T. We can keep swapping a pair of adjacent elements an even number of times to make sure 1 string is not changed and keep flipping some adjacent pair of the other string too ! --- int parity(string &P) { int inversions = 0; for(int i = 0; i < P.size(); i++) { for(int j = i + 1; j < P.size(); j++) { if(P[i] > P[j]) { inversions++; } } } return (inversions%2); } void solve() { int length; string S, T; cin >> length >> S >> T; const int NO_OF_ALPHABETS = 26; vector frequency_S(NO_OF_ALPHABETS, 0); for(int i = 0; i < S.size(); i++) { frequency_S[S[i] - 'a']++; } vector frequency_T(NO_OF_ALPHABETS, 0); for(int i = 0; i < T.size(); i++) { frequency_T[T[i] - 'a']++; } int same_characters = true; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency_S[i] != frequency_T[i]) { same_characters = false; } } int duplicates_present = false; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency_S[i] > 1) { duplicates_present = true; } } if(same_characters) { if(duplicates_present) { cout << "Yes\n"; } else { cout << (parity(S) == parity(T) ? "Yes\n" : "No\n"); } } else { cout << "No\n"; } } ================================================ FILE: Contests/Div 3 598/Explanations/Minimize the Permutation Explanation.txt ================================================ Let A[L, R] be the portion of the array we are allowed to do operaitions on. 1. Initially, we can do operations on A[1, N]. First, we will search for 1, we will put it either in the first position or put it as left as we can. Suppose 1 was originally at position - P. 2. Now, we can only do operations in A[P, N]. We will look for the minimum element in A[P, N] and put the smallest integer in position P or else use all our operations and push it as much towards the left as we can. --- This works because at each step, we are taking the minimum element and pushing it as much to the left as possible. In the first step, we will put 1 in the first position. Obviously, this is the best choice for the first position. If we put some element to the left of 1 (say X) at the first position, then we cannot bring 1 over till the first position. We can only put 1 at A[X] in the best case. It is better to have 1 at A[1] then at A[X]. Clearly, the first step is the best. We maintain the invariant that A[L, R] has not been touched. Now, when A[L, R] is the only segment we can touch, it is best to put the minimum element in A[L, R] at A[L]. Any other choice would lead to a larger string. Hence, this algorithm is correct. --- In general the algorithm is the following - 1. L = 1, R = N 2. Look for the minimum element in A[L, R] 3. Let it be at position P. 4. Use the swaps to bring A[P] to A[L]. 5. Set L = min{L + 1, P} and continue this process till either no operations are left or L = N --- void solve() { int n; cin >> n; vector permutation(n + 1); for(int i = 1; i <= n; i++) { cin >> permutation[i]; } int last_operated = 0; for(int no_of_operations = 0; no_of_operations <= n - 1 && last_operated < n - 1; ) { int minimum = n + 1; int p = last_operated + 1; for(int i = last_operated + 1; i <= n; i++) { if(permutation[i] < minimum) { minimum = permutation[i]; p = i; } } for(int i = p - 1; i > last_operated && no_of_operations <= n - 1; i--) { swap(permutation[i], permutation[i + 1]); no_of_operations++; } last_operated = max(last_operated + 1, p - 1); } for(int i = 1; i <= n; i++) { cout << permutation[i] << " "; } cout << "\n"; } ================================================ FILE: Contests/Div 3 598/Explanations/Payment Without Change Explanation.txt ================================================ My idea was to be greedy. 1. Use as many N's as you have or get as close as possible to the target T. If we use all our N's, we will have reached (aN) The closest we can get to T, is (T/N). We can reach here only if a >= (T/N). ---- So, we will reach min{aN, (T/N)N} ---- The remaining values will have to be made by 1's. So (T - nearest) >= b, for the construction to be possible. ---- void solve() { long long no_of_n, no_of_1, n, target; cin >> no_of_n >> no_of_1 >> n >> target; //Nx + y = B long long nearest = min((target/n)*n, no_of_n*n); cout << ((target - nearest <= no_of_1) ? "Yes\n" : "No\n"); } ---- The editorial had a cleaner solution. First of all, we need as many 1's as {T (mod N)} Then, we just need to check if (aN + b >= T). If yes, we can always go till the nearest or last multiple of N and then use 1s. If we don't have the required number of 1s {T (mod N)}, then we can never reach T. ----- void solve() { long long no_of_n, no_of_1, n, target; cin >> no_of_n >> no_of_1 >> n >> target; //Nx + y = B long long nearest = min((target/n)*n, no_of_n*n); cout << (no_of_1 >= (target%n) && (no_of_n&n + no_of_1 >= target) ? "Yes\n" : "No\n"); } ================================================ FILE: Contests/Div 3 598/Programs/Binary String Minimizing.cpp ================================================ #include #include #include using namespace std; void solve() { long long length, moves; cin >> length >> moves; string S; cin >> S; long long current_distance = 0; for(int i = 0; i < length && moves > 0; i++) { if(S[i] == '1') { current_distance++; } else { int steps_taken = min(current_distance, moves); swap(S[i], S[i - steps_taken]); moves -= steps_taken; } } cout << S << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 3 598/Programs/Equalizing Two Strings.cpp ================================================ #include #include using namespace std; int parity(string &P) { int inversions = 0; for(int i = 0; i < P.size(); i++) { for(int j = i + 1; j < P.size(); j++) { if(P[i] > P[j]) { inversions++; } } } return (inversions%2); } void solve() { int length; string S, T; cin >> length >> S >> T; const int NO_OF_ALPHABETS = 26; vector frequency_S(NO_OF_ALPHABETS, 0); for(int i = 0; i < S.size(); i++) { frequency_S[S[i] - 'a']++; } vector frequency_T(NO_OF_ALPHABETS, 0); for(int i = 0; i < T.size(); i++) { frequency_T[T[i] - 'a']++; } int same_characters = true; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency_S[i] != frequency_T[i]) { same_characters = false; } } int duplicates_present = false; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency_S[i] > 1) { duplicates_present = true; } } if(same_characters) { if(duplicates_present) { cout << "Yes\n"; } else { cout << (parity(S) == parity(T) ? "Yes\n" : "No\n"); } } else { cout << "No\n"; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) { solve(); } return 0; } ================================================ FILE: Contests/Div 3 598/Programs/Minimize the Permutation.cpp ================================================ #include #include using namespace std; void solve() { int n; cin >> n; vector permutation(n + 1); for(int i = 1; i <= n; i++) { cin >> permutation[i]; } int last_operated = 0; for(int no_of_operations = 0; no_of_operations <= n - 1 && last_operated < n - 1; ) { int minimum = n + 1; int p = last_operated + 1; for(int i = last_operated + 1; i <= n; i++) { if(permutation[i] < minimum) { minimum = permutation[i]; p = i; } } for(int i = p - 1; i > last_operated && no_of_operations <= n - 1; i--) { swap(permutation[i], permutation[i + 1]); no_of_operations++; } last_operated = max(last_operated + 1, p - 1); } for(int i = 1; i <= n; i++) { cout << permutation[i] << " "; } cout << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Div 3 598/Programs/Payment Without Change.cpp ================================================ #include using namespace std; void solve() { long long no_of_n, no_of_1, n, target; cin >> no_of_n >> no_of_1 >> n >> target; //Nx + y = B long long nearest = min((target/n)*n, no_of_n*n); cout << ((target - nearest <= no_of_1) ? "Yes\n" : "No\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 11/Explanations/Co Prime Array Explanation.txt ================================================ You are given an array of n elements, you must make it a co-prime array in as few moves as possible. In each move you can insert any positive integral number you want not greater than 109 in any place in the array. An array is co-prime if any two adjacent numbers of it are co-prime. In the number theory, two integers a and b are said to be co-prime if the only positive integer that divides both of them is 1. ---------------------------------------------- This is similar to the question asking what is the smallest currency that cannot be expressed. If there is no 1, it is 1 and if 1 is there all can be expressed. Or is there an element in this array which divides every other element ? If it is yes, then it has to be the smallest element. Or what is the length of longest coprime sequence in array ? If any two elements are coprime, entire array is coprime. Here, the observation needed is that gcd(1, n) = 1. Insert all elements into the new vector, but just check if adjacent elements are coprime. If any two adjacent elements are not coprime. Insert a 1 in between. ----------------------------------------------------- int main() { int no_of_numbers; scanf("%d", &no_of_numbers); vector coprime_array; for(int i = 1; i <= no_of_numbers; i++) { int number_i; scanf("%d", &number_i); if(i == 1 || gcd(coprime_array.back(), number_i) == 1) { coprime_array.push_back(number_i); } else { coprime_array.push_back(1); coprime_array.push_back(number_i); } } int no_of_operations = coprime_array.size() - no_of_numbers; printf("%d\n", no_of_operations); for(unsigned int i = 0; i < coprime_array.size(); i++) printf("%d ", coprime_array[i]); return 0; } ================================================ FILE: Contests/Educational Round 11/Explanations/Hard Process Explanation.txt ================================================ Here's the trick. Maintain two pointers, [L, R]. We want the largest segment with at most k 0s. now, to do this fix L and let R go as far as possible till it has at most k 0s. Once there are more than K 0's, then Increment L till there are <= K 0's. Now, if R is at position X, when no of 0's = K + 1, There is no need to start checking all segments from [L + 1, L + 2], [L + 1, L + 3], .... [L + 1, X] and so on and so forth. We know that [L, X - 1] was a good segment. And all these segments are smaller than it. We only need to check larger segments. So for every possible left from [L, X- 1], we check only larger intervals, [L + 1, X + 1] and so on. If we know [L, X - 1] is a good segment, there is no need to check intervals smaller than that. --------------------------------------- int main() { int no_of_elements, max_zeroes; scanf("%d %d", &no_of_elements, &max_zeroes); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int no_of_0s = 0; int change_left = 0, change_right = 0, left = 1, right = 1, max_window_size = 0; while(right <= no_of_elements) { if(A[right] == 0) no_of_0s++; while(no_of_0s > max_zeroes) { if(A[left] == 0) no_of_0s--; left++; } int window_size = right - (left - 1); if(window_size > max_window_size) { max_window_size = window_size, change_left = left, change_right = right; } right++; } for(int i = change_left; i <= change_right; i++) A[i] = 1; printf("%d\n", max_window_size); for(int i = 1; i <= no_of_elements; i++) printf("%d ", A[i]); return 0; } ================================================ FILE: Contests/Educational Round 11/Explanations/Number of Parallelograms Explanation.txt ================================================ Now fact - diagonals of a parallelogram intersect each other. So iterate over every pair of points and keep track of the frequency of each mid-point. One implementation trick I learnt in this problem is that if you're using a map for a structure you need to overload the < operator so that the map knows how to order the elements ! If it can't distinguish between two points, it thinks it's the same. ----------------------------------- struct Point { int x, y; Point(int X, int Y) { x = X, y = Y; } //A binary search tree needs the elements to be ordered. int operator<(const Point &P) const //This needs to be overloaded for the map to work { return (x == P.x ? y < P.y : x < P.x); } }; long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { int no_of_points; cin >> no_of_points; vector P; for(int i = 1; i <= no_of_points; i++) { int x, y; cin >> x >> y; P.push_back(Point(x, y)); } map frequency; for(int i = 0; i < no_of_points; i++) { for(int j = i + 1; j < no_of_points; j++) { //Avoid floating point errors so store (x1 + x2), (y1 + y2) rather than dividing. Point mid_point = Point( (P[i].x + P[j].x), (P[i].y + P[j].y) ); frequency[mid_point]++; } } long long answer = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { answer += choose_2(it->second); } cout << answer; return 0; } ================================================ FILE: Contests/Educational Round 11/Programs/Co Prime Array.cpp ================================================ #include #include using namespace std; int gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } int main() { int no_of_numbers; scanf("%d", &no_of_numbers); vector coprime_array; for(int i = 1; i <= no_of_numbers; i++) { int number_i; scanf("%d", &number_i); if(i == 1 || gcd(coprime_array.back(), number_i) == 1) { coprime_array.push_back(number_i); } else { coprime_array.push_back(1); coprime_array.push_back(number_i); } } int no_of_operations = coprime_array.size() - no_of_numbers; printf("%d\n", no_of_operations); for(unsigned int i = 0; i < coprime_array.size(); i++) printf("%d ", coprime_array[i]); return 0; } ================================================ FILE: Contests/Educational Round 11/Programs/Hard Process.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements, max_zeroes; scanf("%d %d", &no_of_elements, &max_zeroes); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int no_of_0s = 0; int change_left = 0, change_right = 0, left = 1, right = 1, max_window_size = 0; while(right <= no_of_elements) { if(A[right] == 0) no_of_0s++; while(no_of_0s > max_zeroes) { if(A[left] == 0) no_of_0s--; left++; } int window_size = right - (left - 1); if(window_size > max_window_size) { max_window_size = window_size, change_left = left, change_right = right; } right++; } for(int i = change_left; i <= change_right; i++) A[i] = 1; printf("%d\n", max_window_size); for(int i = 1; i <= no_of_elements; i++) printf("%d ", A[i]); return 0; } ================================================ FILE: Contests/Educational Round 11/Programs/Number of Parallelograms.cpp ================================================ #include #include #include using namespace std; struct Point { int x, y; Point(int X, int Y) { x = X, y = Y; } //A binary search tree needs the elements to be ordered. int operator<(const Point &P) const //This needs to be overloaded for the map to work { return (x == P.x ? y < P.y : x < P.x); } }; long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { int no_of_points; cin >> no_of_points; vector P; for(int i = 1; i <= no_of_points; i++) { int x, y; cin >> x >> y; P.push_back(Point(x, y)); } map frequency; for(int i = 0; i < no_of_points; i++) { for(int j = i + 1; j < no_of_points; j++) { //Avoid floating point errors so store (x1 + x2), (y1 + y2) rather than dividing. Point mid_point = Point( (P[i].x + P[j].x), (P[i].y + P[j].y) ); frequency[mid_point]++; } } long long answer = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { answer += choose_2(it->second); } cout << answer; return 0; } ================================================ FILE: Contests/Educational Round 32/Explanations/Almost Identity Permutations Explanation.txt ================================================ Blog Link - http://qr.ae/TUprHm The key to note here is that k is very small. First we must choose k spots out of n. Now, we can fill these k spots in derangement(k) number of ways. How to find a recurrence for d(n) ? Consider we have n numbers .... Now, let us place n at position i. (There are (n - 1) choices for this.) There are two possibilities for i - Either it is at position n, or it is at some other position. Now if i is placed at position n, then the remaining (n - 2) numbers must be deranged ... given by d(n - 2). What if i is placed at some position other than n ? Then notice now that we have a situation where every element has exactly one spot it cannot fill. (1 cannot be in 1, 2 cannot be in 2, 3 cannot be in 3, . . i - 1 cannot be in i - 1 i cannot be in N i + 1 cannot be in i + 1 . . N - 1 cannot be in N - 1) We have i-1 elements and i - 1 positions to fill them, and each element cannot occupy one spot. Total answer = (n - 1)(d(n - 1) + d(n - 2)) (n - 1) choices to place n, and then accordingly d(n - 1) or d(n - 2) For convenience, when 0 elements are out of place, I want to add 1 to the answer for this question so define d(0) = 1 ------------------------------------------------------------------ long long choose(int n, int r) { if(r == 0 || r == n) return 1; if(r == 1 || r == n - 1) return n; return choose(n - 1, r) + choose(n - 1, r - 1); } long long derangements(int n) { if(n == 0) return 1; if(n == 1) return 0; if(n == 2) return 1; return (n - 1)*(derangements(n - 1) + derangements(n - 2)); } int main() { int n, k; scanf("%d %d", &n, &k); long long answer = 0; for(int i = 0; i <= k; i++) { answer += choose(n, i)*derangements(i); } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Educational Round 32/Explanations/Buggy Robot.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_instructions; string instructions; cin >> no_of_instructions >> instructions; int lefts = 0, rights = 0, ups = 0, downs = 0; for(int i = 0; i < no_of_instructions; i++) { lefts += (instructions[i] == 'L'); rights += (instructions[i] == 'R'); downs += (instructions[i] == 'D'); ups += (instructions[i] == 'U'); } int max_correct_instructions = 2*min(lefts, rights) + 2*min(ups, downs); cout << max_correct_instructions; return 0; } ================================================ FILE: Contests/Educational Round 32/Explanations/K-Dominant Character Explanation.txt ================================================ At first, I thought that if a string is K-dominant, it is also (K + 1)-dominant. If it is not K-dominant, it is not (K - 1)-dominant either. This suggests binary search, How to check if a string is x dominant ? Do 26 O(n) scans. For each alphabet, check if it occurs at least once in every substring of length x. Now, if there's at least one alphabet that satisfies this, the string is x-dominant. -------------------------------------------------------------- int is_possible(int k, int length) { for(int alphabet = 0; alphabet < NO_OF_LETTERS; alphabet++) { int alphabet_occurs_in_every_segment = true; for(int left = 1, right = k; right <= length; left++, right++) { int alphabet_frequency_here = frequency[alphabet][right] - frequency[alphabet][left - 1]; if(alphabet_frequency_here == 0) alphabet_occurs_in_every_segment = false; } if(alphabet_occurs_in_every_segment) return true; } return false; } --------------------------------------------------------------- Do binary search for this - int answer, start = 1, end = length; while(start <= end) { int mid = (start + end) >> 1; if(is_possible(mid, length)) { if(!is_possible(mid - 1, length)) { answer = mid; break; } else { end = mid - 1; } } else { start = mid; } } ------------------------------------------------------------------------------------ Problem is this might take about 20 x 26 O(n) scans. This is too much ! Here's how we reduce it. The idea of solving it seperately for each alphabet is correct, For a given alphabet i, how do we find the minimum length k, such that the string is k-dominant for character i. The minimum length is the maximum distance S, between any two consecutive occurences of i. If k > S, then by definition we will have an i on the segment S. If K < S, then there is at least one segment which does not have i. Now, we find the k for all alphabets, and the minimum k is our answer ! ------------------------------------------------------------------------------- int main() { string S; cin >> S; const int NO_OF_LETTERS = 26; int length = S.size(), answer = S.size(); for(int alphabet = 0; alphabet < NO_OF_LETTERS; alphabet++) { int last_occurence = -1, largest_gap_for_this_alphabet = 0; for(int i = 0; S[i] != '\0'; i++) { if(S[i] == 'a' + alphabet) { largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, i - last_occurence); last_occurence = i; } } largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, length - last_occurence); answer = min(answer, largest_gap_for_this_alphabet); } cout << answer; return 0; } ================================================ FILE: Contests/Educational Round 32/Explanations/Local Extrema Explanation.txt ================================================ Go from 2 to N - 1 and check in O(n). int is_extrema(int mid, int start, int end) { return ((start < mid && end < mid) || (mid < start && mid < end)); } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int local_extrema = 0; for(int i = 2; i < no_of_elements; i++) local_extrema += is_extrema(A[i], A[i - 1], A[i + 1]); printf("%d\n", local_extrema); return 0; } ================================================ FILE: Contests/Educational Round 32/Programs/Almost Identity Permutations.cpp ================================================ #include long long choose(int n, int r) { if(r == 0 || r == n) return 1; if(r == 1 || r == n - 1) return n; return choose(n - 1, r) + choose(n - 1, r - 1); } long long derangements(int n) { if(n == 0) return 1; if(n == 1) return 0; if(n == 2) return 1; return (n - 1)*(derangements(n - 1) + derangements(n - 2)); } int main() { int n, k; scanf("%d %d", &n, &k); long long answer = 0; for(int i = 0; i <= k; i++) { answer += choose(n, i)*derangements(i); } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Educational Round 32/Programs/Buggy Robot.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_instructions; string instructions; cin >> no_of_instructions >> instructions; int lefts = 0, rights = 0, ups = 0, downs = 0; for(int i = 0; i < no_of_instructions; i++) { lefts += (instructions[i] == 'L'); rights += (instructions[i] == 'R'); downs += (instructions[i] == 'D'); ups += (instructions[i] == 'U'); } int max_correct_instructions = 2*min(lefts, rights) + 2*min(ups, downs); cout << max_correct_instructions; return 0; } ================================================ FILE: Contests/Educational Round 32/Programs/K-Dominant Character.cpp ================================================ #include #include using namespace std; int main() { string S; cin >> S; const int NO_OF_LETTERS = 26; int length = S.size(), answer = S.size(); for(int alphabet = 0; alphabet < NO_OF_LETTERS; alphabet++) { int last_occurence = -1, largest_gap_for_this_alphabet = 0; for(int i = 0; S[i] != '\0'; i++) { if(S[i] == 'a' + alphabet) { largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, i - last_occurence); last_occurence = i; } } largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, length - last_occurence); answer = min(answer, largest_gap_for_this_alphabet); } cout << answer; return 0; } ================================================ FILE: Contests/Educational Round 32/Programs/Local Extrema.cpp ================================================ #include #include using namespace std; int is_extrema(int mid, int start, int end) { return ((start < mid && end < mid) || (mid < start && mid < end)); } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int local_extrema = 0; for(int i = 2; i < no_of_elements; i++) local_extrema += is_extrema(A[i], A[i - 1], A[i + 1]); printf("%d\n", local_extrema); return 0; } ================================================ FILE: Contests/Educational Round 37/Explanation/Connected Components Explanation.txt.txt ================================================ We have to count the number of components in the complement graph. We also need a way to query if two vertices are connected. Instead of using an adjacency vector, we will use adjacency sets. We will also maintain a set of all unvisited vertices. Pick up the first vertex in the unvisited set. Erase it Keep traversing the unvisited set till there is a vertex with which there is no edge and then repeat ----- Why does this work ? It looks like it should time out since we are going through the whole unvisited set for each vertex. Let us count the number of times we will pick a vertex from the unvisited set. We perform two operations 1. Pick up a vertex 2. Skip it and go to next element in the set There are N vertices in the set and each will be picked one time, after which it will be erased. How many times do we pick a vertex and skip it ? We will skip a vertex only if it has an edge with the current vertex. Since there are M edges, we can perform at most M skips. So the number of 'touches' we do to the unvisited set is O(N + M) We do N steps of Type 1 and at most M steps of Type 2 Each has a O(log N) factor ----- int dfs_component_size(int v) { unvisited.erase(v); int size_here = 1; for(set :: iterator it = unvisited.begin(); it != unvisited.end(); ) { //printf("here %d\n", *it); if(complement_graph[v].count(*it) == 0) { int child = *it; size_here += dfs_component_size(child); it = unvisited.lower_bound(child); } else { it++; } } return size_here; } int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_vertices; i++) unvisited.insert(i); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); complement_graph[u].insert(v); complement_graph[v].insert(u); } int no_of_components = 0; vector component_size; for(int i = 1; i <= no_of_vertices; i++) { if(unvisited.count(i) == 1) { no_of_components++; component_size.push_back(dfs_component_size(i)); } } sort(all(component_size)); printf("%d\n", no_of_components); for(int i = 0; i < no_of_components; i++) printf("%d ", component_size[i]); return 0; } ================================================ FILE: Contests/Educational Round 37/Explanation/List of Integer Explanation.txt ================================================ We need to change the question and try answering a different question. Finding the n-th integer coprime to P is quite difficult. Let's look at it differently. I give you a number L. How many numbers less than P are coprime to it ? Principle of inclusion and exclusion. Now, we know how to do that. The number we are looking for is the smallest integer D such that coprime_count(n, till D) == K and coprime_count(n, till D- 1) < K Coprime_count(n, Limit) is an increasing function. This allows us to use binary search ! Also, there's another twist. They don't just want k-th coprime number. They want k-th coprime number greater than x. So, to overcome this, We need to find the k' coprime number, where k' = k + coprime_count(n, x) The most elegant thing about this problem is that I learnt how to elegantly perform inclusion and exclusion division by modifying a sieve. It was very elegant indeed. --------------------------------------------------------------------------- vector inclusion_exclusion_factors[MAX_N]; void sieve() { for(int i = 1; i < MAX_N; i++) inclusion_exclusion_factors[i].push_back(1); for(int i = 2; i < MAX_N; i++) { if(inclusion_exclusion_factors[i].size() > 1) //Not prime continue; for(int multiple = i; multiple < MAX_N; multiple += i) { int original_size = inclusion_exclusion_factors[multiple].size(); for(int j = 0; j < original_size; j++) { int new_factor = (-1)*inclusion_exclusion_factors[multiple][j]*i; inclusion_exclusion_factors[multiple].push_back(new_factor); } } } } int no_of_coprime_integers_till(int n, int limit) { int answer = 0; for(int i = 0; i < inclusion_exclusion_factors[n].size(); i++) { answer += limit/inclusion_exclusion_factors[n][i]; } return answer; } void solve() { int n, x, target; scanf("%d %d %d", &x, &n, &target); target += no_of_coprime_integers_till(n, x); int left = 1, right = 1e9, answer; while(left <= right) //f(n, L) < target and f(n, R) >= target { int mid = (left + right) >> 1; if(no_of_coprime_integers_till(n, mid) < target) { if(no_of_coprime_integers_till(n, mid + 1) == target) { answer = mid + 1; break; } else { left = mid + 1; } } else if(no_of_coprime_integers_till(n, mid) >= target) { right = mid; } } printf("%d\n", answer); } int main() { sieve(); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 37/Explanation/Sum and Replace Explanation.txt ================================================ Now, it happens that d(n) is a function that converges rapidly. Every number will ultimately be reduced to 2. In the given range every number goes to 2 in at most 6 times. After that d(2) = 2 and d(1) = 1 How do we use this fact ? We can't use lazy propagation for a function like number of divisors. Here's what we do ... Use a segment tree for sum and another one for max. While performing an update check if the max of any node is <= 2. If it is, then we can ignore it as it won't change with the update. We can afford to go to every leaf node and avoid nodes who's max <= 2. In the worst case, we will do 6 O(n) scans ! Which is perfectly fine ! It's very reasonable. This is an important trick to note in functions which converge rapidly. We can afford to change each element one-by-one and ignore nodes which have already hit the converged point. We won't be doing too many updates ... That's the main thing to learn here. Again the idea of a segment tree is to break the query interval into intervals that either lie completely with an interval or ones that lie completely outside the interval. --------------------------------------------------------- void precompute_divisors() { vector largest_prime_factor(MAX_N, 0); no_of_divisors[1] = 1; for(int i = 2; i < MAX_N; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple < MAX_N; multiple += i) { largest_prime_factor[multiple] = i; } } int exponent = 0, reduced_i = i; while(reduced_i%largest_prime_factor[i] == 0) { reduced_i /= largest_prime_factor[i]; exponent++; } no_of_divisors[i] = (exponent + 1)*no_of_divisors[reduced_i]; } } void build(int n, int left, int right) { if(left == right) { max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } long long get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; long long left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); long long right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } void update(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || max_tree[n] <= 2) return; if(left == right) { A[left] = no_of_divisors[A[left]]; max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, query_left, query_right); update(RIGHT(n), mid + 1, right, query_left, query_right); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int main() { precompute_divisors(); int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); build(1, 1, no_of_elements); while(no_of_queries--) { const int SUM = 2, REPLACE = 1; int query_type, left, right; scanf("%d %d %d", &query_type, &left, &right); if(query_type == SUM) { long long sum = get_sum(1, 1, no_of_elements, left, right); printf("%I64d\n", sum); } else if(query_type == REPLACE) { update(1, 1, no_of_elements, left, right); } } return 0; } ================================================ FILE: Contests/Educational Round 37/Explanation/Swap Adjacent Elements Explanation.txt ================================================ Claim - It is possible to sort the permutation if and only if, for every i such that p(i) =/= i, there exists a series of consecutive 1s in between i and p(i) allowing the element p(i) to be swapped one-by-one and placed at position p(i) from position i. Proof - We can easily see that if i =/= p(i) and there is no stream of one's in between i and p(i), we can never get an array in order as there will always be some element p(i) that can never travel to position p(i). For example, Consider this 1 2 7 4 5 6 3 0 0 1 1 0 1 Since 7 is not in it's place and there is no continuous stream of 1s from 3 to 7, it is impossible for 7 to travel all the way to 3. ---------------------------------------------------- Now, to prove the other way around - i.e. it is always possible to sort an array if there exists a stream of 1s in between every i and p(i) where i =/= p(i) I will prove that if the condition of stream of 1s in between every i and p(i) is satisfied, then it is always possible to place the SMALLEST out of order element in it's right place. Choose the smallest element x, such that for all y < x, p(y) = y. In other words, pick the smallest element that is not in it's right position. {This means that the array is sorted from A[1, 2, .... x - 1]} Let x be located at position i. (P(x) = i). Now, we can conclude that x < i. Because all y < x, P(y) = y, so P(x) can't be < x. It has to be > x. Based on the condition, it means there is a string of consecutive 1s from x to (i - 1), allowing the travel. Since it is already established that there is a stream of 1s in between x and (i - 1). We perform the swaps one by one, till x moves all the way from position i to position x A[1, 2, ... x] The unsorted array is from A[x + 1, ... n]. Now, the smallest element that is out of order either lies in between x and i or it doesn't. Either way, the condition of it having a string of 1s in between it's current and true position remains invariant. Because if it lies outside [x, i), then it was never disturbed. If it did, then it still remains somewhere in the stream of 1s in between x and i. If it had a string of 1s in the beginning, it still does now, because it is still connected So, we keep placing the minimum element out-of-order in it's right place till the entire array is sorted. --------------------------------------------------------------- Here's what I did - Maintain a prefix sum of the number of 1s till i. For every i, such that p(i) != i Right = Max{p(i), i} Left = Min{p(i), i} Now, there should be continuous 1s from Left to (Right - 1). The expected number of 1s = (Right - 1) - (Left - 1) The number of 1s present = Prefix(Right - 1) - Prefix(Left - 1) If these two numbers are not equal, then it means there is some element which can't go it's true position. If these two numbers are equal for all i, such that i =/= p(i), then it means that the array can always be sorted by placing the minimum out-of-order element in it's right place. ------------------------------------------------------------------------------ int main() { int n; scanf("%d", &n); vector permutation(n + 1, 0); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); vector ones_till(n + 1, 0); for(int i = 1; i <= n - 1; i++) { int digit; scanf("%1d", &digit); ones_till[i] = (digit == 1) + ones_till[i - 1]; } int is_sortable = true; for(int i = 1; i <= n; i++) { if(permutation[i] != i) { int right = max(i, permutation[i]); int left = min(i, permutation[i]); int distance = (right - 1) - (left - 1); if(ones_till[right - 1] - ones_till[left - 1] != distance) is_sortable = false; } } printf(is_sortable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Educational Round 37/Explanation/Tanks Explanation.txt.txt ================================================ If the sum of all the tanks is smaller than V, then it is not possible. Let us suppose the sum is >= V, is it possible ? Let us suppose there is some subset who's sum = v (mod K) Then, it is always possible. We can pour all the water of this subset into one tank. Then, we will keep filling in water from the other tanks in steps of size K till the volume = V If there is no subset who's sum = v (mod k), it means that we can never get the sum of any subset = V (mod K) so it is impossible. To see this, reduce each tank to it's modulo value with K Adding or removing K will not change the modulo. If we have some subset = V (mod K), put everything in one bottle and then keep adding K If we don't have any subset like that, adding or removing K from any of the bottles will not change that so it's not possible. ----- 1. There is a case when the empty set is a good set when v = 0 (mod k) In that case, empty any one tank and then pour water into that tank ----- int main() { long long no_of_elements, capacity, total_volume; cin >> no_of_elements >> capacity >> total_volume; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int sum = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; } vector < vector > reachable(no_of_elements + 1, vector (capacity + 1, false)); reachable[0][0] = true; for(int i = 1; i <= no_of_elements; i++) { reachable[i][A[i]%capacity] = true; for(int m = 0; m < capacity; m++) { int new_m = (m + A[i])%capacity; if(reachable[i - 1][m]) { reachable[i][new_m] = true; reachable[i][m] = true; } } } if(sum < total_volume || !reachable[no_of_elements][total_volume%capacity]) { cout << "NO\n"; return 0; } cout << "YES\n"; vector is_good(no_of_elements + 1, false); for(int i = no_of_elements, looking_for = total_volume%capacity; i >= 1; i--) { int remaining = (looking_for - A[i]%capacity + capacity)%capacity; if(reachable[i - 1][remaining]) { is_good[i] = true; //cout << "Remainder of " << looking_for << " is reachable with " << A[i] << " so it's good. Remaining = " << remaining << "\n"; looking_for = remaining; } if(looking_for == 0) { break; } } vector good_set, bad_set; for(int i = 1; i <= no_of_elements; i++) { if(is_good[i]) { good_set.push_back(i); } else { bad_set.push_back(i); } } for(int i = 1; i < good_set.size(); i++) { if(A[good_set[i]] == 0) { continue; } cout << ceil(A[good_set[i]], capacity) << " " << good_set[i] << " " << good_set[0] << "\n"; //cout << "Ceil(" << good_set[i] << "," << capacity << ") is " << ceil(good_set[i], capacity) << "\n"; A[good_set[0]] += A[good_set[i]]; A[good_set[i]] = 0; } if(good_set.size() > 0 && A[good_set[0]] > total_volume) { int other; if(good_set.size() >= 2) { other = good_set[1]; } else { other = bad_set[0]; } cout << (A[good_set[0]] - total_volume)/capacity << " " << good_set[0] << " " << other << "\n"; A[other] += (A[good_set[0]] - total_volume)/capacity; A[good_set[0]] = total_volume; } for(int i = 1; i < bad_set.size(); i++) { if(A[bad_set[i]] == 0) { continue; } cout << ceil(A[bad_set[i]], capacity) << " " << bad_set[i] << " " << bad_set[0] << "\n"; A[bad_set[0]] += A[bad_set[i]]; A[bad_set[i]] = 0; if(total_volume%capacity == 0) { good_set.push_back(bad_set[i]); } } if(A[good_set[0]] < total_volume) { int extra = total_volume - A[good_set[0]]; cout << ceil(extra,capacity) << " " << bad_set[0] << " " << good_set[0] << "\n"; A[good_set[0]] += extra; A[bad_set[0]] -= extra; } return 0; } ================================================ FILE: Contests/Educational Round 37/Explanation/Tea Queue Explanation.txt ================================================ This problem is made a lot easier, because the inputs are sorted in terms of their l_i's Otherwise, we'd need to use structures and call a custom sort. Here's what we do, First initial time = left[1] For each person that arrives, set current time to max{current time, left[i]} [If current time < left[i], then the current customer will be served. He'll just have to wait till left[i]. So, directly set the current time to left[i]. If current time > left[i], let it be.] (check if current time <= right[i]) if it is, then service time[i] = current time, current time++ Note - I made the mistake of increasing service time regardless of whether the person was served. That was a mistake. Incrememnt time only if he has been served. For example, 1 4 1 1 The first person is served at moment 1. Now, the time is 2. The second person is not served. This means that he has left the queue. the time REMAINS 2 for the third customer It does NOT increase to 3 even if he didn't take the tea. Only the serviced customers increment the current time. --------------------------------------------------------------------- void solve() { int number_of_students; scanf("%d", &number_of_students); vector left(number_of_students + 1); vector right(number_of_students + 1); for(int i = 1; i <= number_of_students; i++) scanf("%d %d", &left[i], &right[i]); vector served_time(number_of_students + 1, 0); for(int current_time = left[1], student = 1; student <= number_of_students; student++) { current_time = max(current_time, left[student]); if(current_time <= right[student]) { served_time[student] = current_time++; } } for(int i = 1; i <= number_of_students; i++) printf("%d ", served_time[i]); printf("\n"); } ================================================ FILE: Contests/Educational Round 37/Explanation/Water the Gardens Explanation.txt ================================================ Now, the time taken to water the patch of grass in between 1 and tap[1] is tap[1] - 1 = tap[1]. The time taken to water the patch of grass from the last tap to the end is = N - (tap.back() - 1); The time taken to water the patch of grass in between tap[i] and tap[i + 1] is ceil[distance/2], where distance = tap[i + 1] - (tap[i] - 1) This is because the number of unwatered patches of grass in between tap[i] and tap[i + 1] reduces by 2 each second. So, the distance shrinks by 2 each second. If this number is odd, add one more second. The time taken = max{First patch, all middle patches, Last patch} (It's already sorted) --------------------------------------------------------------------- void solve() { int number_of_taps, number_of_beds; scanf("%d %d", &number_of_beds, &number_of_taps); vector tap(number_of_taps + 1, 0); for(int i = 1; i <= number_of_taps; i++) scanf("%d", &tap[i]); int time = tap[1]; for(int i = 1; i < number_of_taps; i++) { int distance = tap[i + 1] - tap[i] + 1; int time_for_this_patch = distance/2 + distance%2 ; time = max(time, time_for_this_patch); } time = max(time, number_of_beds - tap.back() + 1); printf("%d\n", time); } ================================================ FILE: Contests/Educational Round 37/Programs/Connected Components.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; const int MAX_N = 2e5 + 15; int visited[MAX_N]; set complement_graph[MAX_N], unvisited; int dfs_component_size(int v) { unvisited.erase(v); int size_here = 1; for(set :: iterator it = unvisited.begin(); it != unvisited.end(); ) { if(complement_graph[v].count(*it) == 0) { int child = *it; size_here += dfs_component_size(child); it = unvisited.lower_bound(child); } else { it++; } } return size_here; } int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_vertices; i++) unvisited.insert(i); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); complement_graph[u].insert(v); complement_graph[v].insert(u); } int no_of_components = 0; vector component_size; for(int i = 1; i <= no_of_vertices; i++) { if(unvisited.count(i) == 1) { no_of_components++; component_size.push_back(dfs_component_size(i)); } } sort(all(component_size)); printf("%d\n", no_of_components); for(int i = 0; i < no_of_components; i++) printf("%d ", component_size[i]); return 0; } ================================================ FILE: Contests/Educational Round 37/Programs/List of Integers.cpp ================================================ #include #include using namespace std; const int MAX_N = 1e6 + 15; vector inclusion_exclusion_factors[MAX_N]; void sieve() { for(int i = 1; i < MAX_N; i++) inclusion_exclusion_factors[i].push_back(1); for(int i = 2; i < MAX_N; i++) { if(inclusion_exclusion_factors[i].size() > 1) //Not prime continue; for(int multiple = i; multiple < MAX_N; multiple += i) { int original_size = inclusion_exclusion_factors[multiple].size(); for(int j = 0; j < original_size; j++) { int new_factor = (-1)*inclusion_exclusion_factors[multiple][j]*i; inclusion_exclusion_factors[multiple].push_back(new_factor); } } } } int no_of_coprime_integers_till(int n, int limit) { int answer = 0; for(int i = 0; i < inclusion_exclusion_factors[n].size(); i++) { answer += limit/inclusion_exclusion_factors[n][i]; } return answer; } void solve() { int n, x, target; scanf("%d %d %d", &x, &n, &target); target += no_of_coprime_integers_till(n, x); int left = 1, right = 1e9, answer; while(left <= right) //f(n, L) < target and f(n, R) >= target { int mid = (left + right) >> 1; if(no_of_coprime_integers_till(n, mid) < target) { if(no_of_coprime_integers_till(n, mid + 1) == target) { answer = mid + 1; break; } else { left = mid + 1; } } else if(no_of_coprime_integers_till(n, mid) >= target) { right = mid; } } printf("%d\n", answer); } int main() { sieve(); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 37/Programs/Sum and Replace.cpp ================================================ #include #include #define LEFT(n) ( (n << 1) ) #define RIGHT(n) ( (n << 1)|1 ) using namespace std; const int MAX_N = 1e6 + 10, MAX_ELEMENTS = 5e5 + 6; vector no_of_divisors(MAX_N, 0); int max_tree[3*MAX_ELEMENTS]; long long sum_tree[3*MAX_ELEMENTS]; int A[MAX_ELEMENTS]; void precompute_divisors() { vector largest_prime_factor(MAX_N, 0); no_of_divisors[1] = 1; for(int i = 2; i < MAX_N; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple < MAX_N; multiple += i) { largest_prime_factor[multiple] = i; } } int exponent = 0, reduced_i = i; while(reduced_i%largest_prime_factor[i] == 0) { reduced_i /= largest_prime_factor[i]; exponent++; } no_of_divisors[i] = (exponent + 1)*no_of_divisors[reduced_i]; } } void build(int n, int left, int right) { if(left == right) { max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } long long get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; long long left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); long long right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } void update(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || max_tree[n] <= 2) return; if(left == right) { A[left] = no_of_divisors[A[left]]; max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, query_left, query_right); update(RIGHT(n), mid + 1, right, query_left, query_right); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int main() { precompute_divisors(); int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); build(1, 1, no_of_elements); while(no_of_queries--) { const int SUM = 2, REPLACE = 1; int query_type, left, right; scanf("%d %d %d", &query_type, &left, &right); if(query_type == SUM) { long long sum = get_sum(1, 1, no_of_elements, left, right); printf("%I64d\n", sum); } else if(query_type == REPLACE) { update(1, 1, no_of_elements, left, right); } } return 0; } ================================================ FILE: Contests/Educational Round 37/Programs/Swap Adjacent Elements.cpp ================================================ #include #include using namespace std; int main() { int n; scanf("%d", &n); vector permutation(n + 1, 0); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); vector ones_till(n + 1, 0); for(int i = 1; i <= n - 1; i++) { int digit; scanf("%1d", &digit); ones_till[i] = (digit == 1) + ones_till[i - 1]; } int is_sortable = true; for(int i = 1; i <= n; i++) { if(permutation[i] != i) { int right = max(i, permutation[i]); int left = min(i, permutation[i]); int distance = (right - 1) - (left - 1); if(ones_till[right - 1] - ones_till[left - 1] != distance) is_sortable = false; } } printf(is_sortable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Educational Round 37/Programs/Tanks.cpp ================================================ #include #include using namespace std; long long ceil(long long n, long long r) { return (n/r) + (n%r != 0); } int main() { long long no_of_elements, capacity, total_volume; cin >> no_of_elements >> capacity >> total_volume; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; } int sum = 0; for(int i = 1; i <= no_of_elements; i++) { sum += A[i]; } vector < vector > reachable(no_of_elements + 1, vector (capacity + 1, false)); reachable[0][0] = true; for(int i = 1; i <= no_of_elements; i++) { reachable[i][A[i]%capacity] = true; for(int m = 0; m < capacity; m++) { int new_m = (m + A[i])%capacity; if(reachable[i - 1][m]) { reachable[i][new_m] = true; reachable[i][m] = true; } } } if(sum < total_volume || !reachable[no_of_elements][total_volume%capacity]) { cout << "NO\n"; return 0; } cout << "YES\n"; vector is_good(no_of_elements + 1, false); for(int i = no_of_elements, looking_for = total_volume%capacity; i >= 1; i--) { int remaining = (looking_for - A[i]%capacity + capacity)%capacity; if(reachable[i - 1][remaining]) { is_good[i] = true; looking_for = remaining; } if(looking_for == 0) { break; } } vector good_set, bad_set; for(int i = 1; i <= no_of_elements; i++) { if(is_good[i]) { good_set.push_back(i); } else { bad_set.push_back(i); } } for(int i = 1; i < good_set.size(); i++) { if(A[good_set[i]] == 0) { continue; } cout << ceil(A[good_set[i]], capacity) << " " << good_set[i] << " " << good_set[0] << "\n"; A[good_set[0]] += A[good_set[i]]; A[good_set[i]] = 0; } if(good_set.size() > 0 && A[good_set[0]] > total_volume) { int other; if(good_set.size() >= 2) { other = good_set[1]; } else { other = bad_set[0]; } cout << (A[good_set[0]] - total_volume)/capacity << " " << good_set[0] << " " << other << "\n"; A[other] += (A[good_set[0]] - total_volume)/capacity; A[good_set[0]] = total_volume; } for(int i = 1; i < bad_set.size(); i++) { if(A[bad_set[i]] == 0) { continue; } cout << ceil(A[bad_set[i]], capacity) << " " << bad_set[i] << " " << bad_set[0] << "\n"; A[bad_set[0]] += A[bad_set[i]]; A[bad_set[i]] = 0; if(total_volume%capacity == 0) { good_set.push_back(bad_set[i]); } } if(A[good_set[0]] < total_volume) { int extra = total_volume - A[good_set[0]]; cout << ceil(extra,capacity) << " " << bad_set[0] << " " << good_set[0] << "\n"; A[good_set[0]] += extra; A[bad_set[0]] -= extra; } return 0; } ================================================ FILE: Contests/Educational Round 37/Programs/Tea Queue.cpp ================================================ #include #include using namespace std; void solve() { int number_of_students; scanf("%d", &number_of_students); vector left(number_of_students + 1); vector right(number_of_students + 1); for(int i = 1; i <= number_of_students; i++) scanf("%d %d", &left[i], &right[i]); vector served_time(number_of_students + 1, 0); for(int current_time = left[1], student = 1; student <= number_of_students; student++) { current_time = max(current_time, left[student]); if(current_time <= right[student]) { served_time[student] = current_time++; } } for(int i = 1; i <= number_of_students; i++) printf("%d ", served_time[i]); printf("\n"); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 37/Programs/Water the Gardens.cpp ================================================ #include #include using namespace std; void solve() { int number_of_taps, number_of_beds; scanf("%d %d", &number_of_beds, &number_of_taps); vector tap(number_of_taps + 1, 0); for(int i = 1; i <= number_of_taps; i++) scanf("%d", &tap[i]); int time = tap[1]; for(int i = 1; i < number_of_taps; i++) { int distance = tap[i + 1] - tap[i] + 1; int time_for_this_patch = distance/2 + distance%2 ; time = max(time, time_for_this_patch); } time = max(time, number_of_beds - tap.back() + 1); printf("%d\n", time); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 44/Explanations/Chess Placing Explanation.txt ================================================ There are only two possibilities. At the end, either all the squares are on black squares or they're all on white squares. Calculate the number of moves if all pieces are on black squares, and if all the pieces are on white squares and the answer is the minimum of these two. To calculate the minimum number of moves to put all pieces on squares of the same colour, it is always best to put on square i, the piece closest to it. So Ans = |P[i] - 2i|, to put all pieces on even squares. Of course, the pieces must be sorted before this. The proof is that if P[i] is the closest to 2i, if we replace P[i] by any piece > P[i], then we increase the number of moves. ----------------------------------- int main() { int n; cin >> n; vector A(n/2 + 1); for(int i = 1; 2*i <= n; i++) cin >> A[i]; sort(all(A)); int black_moves = 0; for(int i = 1; 2*i <= n; i++) black_moves += abs(A[i] - (2*i - 1)); int white_moves = 0; for(int i = 1; 2*i <= n; i++) white_moves += abs(A[i] - 2*i); int minimum_moves = min(black_moves, white_moves); cout << minimum_moves; return 0; } ================================================ FILE: Contests/Educational Round 44/Explanations/Switches and Lamps Explanation.txt ================================================ Count the number of switches that each lamp is connected to. (In other words, find the sum of each column.) The go through all switches and check if there is any switch that can be ignored. A switch can be ignored, if each of it's connected lamp has another switch connected to it. i.e. If Switch[i][j] = 1, and lamp[j] > 1, then the i-th switch can be ignored. ---------------------------------------------------- int main() { int no_of_switches, no_of_lamps; cin >> no_of_switches >> no_of_lamps; vector switches(no_of_switches); for(int i = 0; i < no_of_switches; i++) cin >> switches[i]; vector no_of_switches_for(no_of_lamps, 0); for(int i = 0; i < no_of_switches; i++) for(int lamp = 0; lamp < no_of_lamps; lamp++) no_of_switches_for[lamp] += (switches[i][lamp] == '1'); int one_ignorable = false; for(int i = 0; i < no_of_switches; i++) { int can_ignore_this_one = true; for(int lamp = 0; lamp < no_of_lamps; lamp++) { if(switches[i][lamp] == '1' && no_of_switches_for[lamp] == 1) can_ignore_this_one = false; } if(can_ignore_this_one) one_ignorable = true; } cout << (one_ignorable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Educational Round 44/Programs/Chess Placing.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int n; cin >> n; vector A(n/2 + 1); for(int i = 1; 2*i <= n; i++) cin >> A[i]; sort(all(A)); int black_moves = 0; for(int i = 1; 2*i <= n; i++) black_moves += abs(A[i] - (2*i - 1)); int white_moves = 0; for(int i = 1; 2*i <= n; i++) white_moves += abs(A[i] - 2*i); int minimum_moves = min(black_moves, white_moves); cout << minimum_moves; return 0; } ================================================ FILE: Contests/Educational Round 44/Programs/Switches and Lamps.cpp ================================================ #include #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_switches, no_of_lamps; cin >> no_of_switches >> no_of_lamps; vector switches(no_of_switches); for(int i = 0; i < no_of_switches; i++) cin >> switches[i]; vector no_of_switches_for(no_of_lamps, 0); for(int i = 0; i < no_of_switches; i++) for(int lamp = 0; lamp < no_of_lamps; lamp++) no_of_switches_for[lamp] += (switches[i][lamp] == '1'); int one_ignorable = false; for(int i = 0; i < no_of_switches; i++) { int can_ignore_this_one = true; for(int lamp = 0; lamp < no_of_lamps; lamp++) { if(switches[i][lamp] == '1' && no_of_switches_for[lamp] == 1) can_ignore_this_one = false; } if(can_ignore_this_one) one_ignorable = true; } cout << (one_ignorable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Educational Round 46/Explanations/CodeHorses T Shirts Explanation.txt ================================================ If something is common in both lists, then neglect it. Now all the differences take exactly one change each. ----------------------------------- int main() { int no_of_shirts; cin >> no_of_shirts; map size_frequency; for(int i = 1; i <= no_of_shirts; i++) { string shirt_size; cin >> shirt_size; size_frequency[shirt_size]++; } int no_of_changes = 0; for(int i = 1; i <= no_of_shirts; i++) { string shirt_size; cin >> shirt_size; if(size_frequency[shirt_size] > 0) size_frequency[shirt_size]--; else no_of_changes++; } cout << no_of_changes; return 0; } ================================================ FILE: Contests/Educational Round 46/Explanations/Covered Points Count Explanation.txt ================================================ Keep track of the begginng and end of each segment and then sort them. Then go through them. The number of lines that are presently covered can be found out by going through the lines and changing accordingly whether we are at a beginning or an end. The amount that is covered can be found out by taking the difference of the last two points. ------------- int main() { int no_of_segments; scanf("%d", &no_of_segments); vector edge(2*no_of_segments + 1); edge[0] = info(0, 0); for(int i = 1; i <= no_of_segments; i++) { LL left, right; scanf("%I64d %I64d", &left, &right); edge[2*i - 1] = info(left, 1); edge[2*i] = info(right + 1, -1); } sort(all(edge)); vector points_covered_by(no_of_segments + 1, 0); int no_of_covering_lines = 0; for(int i = 1; i <= 2*no_of_segments; i++) { points_covered_by[no_of_covering_lines] += edge[i].location - edge[i - 1].location; no_of_covering_lines += edge[i].new_segments; } for(int i = 1; i <= no_of_segments; i++) printf("%I64d ", points_covered_by[i]); return 0; } ================================================ FILE: Contests/Educational Round 46/Explanations/Yet Another Problem on Subsequence Explanation.txt ================================================ Let f(i) denote the number of sequences if A[i] is the first element. If A[i] <= 0, then f(i) = 0 Otherwise, we have to count the number of ways of choosing A[i] elements from [i + 1, ... , j] x f(j). Ultimately, we have to sum f(i) for all i. ----------------- int main() { precompute(); int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector answer_from(no_of_elements + 2, 0); answer_from[no_of_elements + 1] = 1; for(int i = no_of_elements; i >= 1; i--) { if(A[i] <= 0) { answer_from[i] = 0; continue; } for(int j = i + A[i]; j <= no_of_elements; j++) { answer_from[i] += (choose[j - i][A[i]]*answer_from[j + 1])%MOD; } answer_from[i] %= MOD; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) answer += answer_from[i]; printf("%I64d\n", answer%MOD); return 0; } ================================================ FILE: Contests/Educational Round 46/Programs/CodeHorses T Shirts.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_shirts; cin >> no_of_shirts; map size_frequency; for(int i = 1; i <= no_of_shirts; i++) { string shirt_size; cin >> shirt_size; size_frequency[shirt_size]++; } int no_of_changes = 0; for(int i = 1; i <= no_of_shirts; i++) { string shirt_size; cin >> shirt_size; if(size_frequency[shirt_size] > 0) size_frequency[shirt_size]--; else no_of_changes++; } cout << no_of_changes; return 0; } ================================================ FILE: Contests/Educational Round 46/Programs/Covered Points Count.cpp ================================================ #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; typedef long long LL; struct info { LL location; int new_segments; info(LL loc = 0, int new_seg = 0) { location = loc; new_segments = new_seg; } const operator <(info &A) { return (location < A.location); } }; int main() { int no_of_segments; scanf("%d", &no_of_segments); vector edge(2*no_of_segments + 1); edge[0] = info(0, 0); for(int i = 1; i <= no_of_segments; i++) { LL left, right; scanf("%I64d %I64d", &left, &right); edge[2*i - 1] = info(left, 1); edge[2*i] = info(right + 1, -1); } sort(all(edge)); vector points_covered_by(no_of_segments + 1, 0); int no_of_covering_lines = 0; for(int i = 1; i <= 2*no_of_segments; i++) { points_covered_by[no_of_covering_lines] += edge[i].location - edge[i - 1].location; no_of_covering_lines += edge[i].new_segments; } for(int i = 1; i <= no_of_segments; i++) printf("%I64d ", points_covered_by[i]); return 0; } ================================================ FILE: Contests/Educational Round 46/Programs/Yet Another Problem on Subsequence.cpp ================================================ #include #include using namespace std; const int MAX = 1e3 + 5, MOD = 998244353; long long choose[MAX][MAX]; void precompute() { for(int n = 0; n < MAX; n++) { for(int r = 0; r <= n; r++) { if(r == 0 || r == n) choose[n][r] = 1; else choose[n][r] = (choose[n - 1][r] + choose[n - 1][r - 1])%MOD; } } } int main() { precompute(); int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector answer_from(no_of_elements + 2, 0); answer_from[no_of_elements + 1] = 1; for(int i = no_of_elements; i >= 1; i--) { if(A[i] <= 0) { answer_from[i] = 0; continue; } for(int j = i + A[i]; j <= no_of_elements; j++) { answer_from[i] += (choose[j - i][A[i]]*answer_from[j + 1])%MOD; } answer_from[i] %= MOD; } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) answer += answer_from[i]; printf("%I64d\n", answer%MOD); return 0; } ================================================ FILE: Contests/Educational Round 51/Explanation/Bicolourings Explanation.txt ================================================ A common idea to solve questions involving tiling is bitmasks. Let us represent black with 0 and white with 1. Suppose our last column is 0 1 ---------------------------------- How many NEW components do we get by adding another column ? Let's go case by case. Case 1 : 0 0 1 0 The number of components remains the same. Case 2 : 0 0 1 1 Number of components remains the same. Case 3 : 0 1 1 0 We have created two new components. Case 4 : 0 1 1 1 The number of components remains the same. --------------------------------------------------- Let us analyse all the 16 cases. int additional_components(int second_last, int last) { switch(second_last) { case BB : switch(last) { case BB : return 0; case BW : return 1; case WB : return 1; case WW : return 1; } case BW : switch(last) { case BB : return 0; case BW : return 0; case WB : return 2; case WW : return 0; } case WB : switch(last) { case BB : return 0; case BW : return 2; case WB : return 0; case WW : return 0; } case WW : switch(last) { case BB : return 1; case BW : return 1; case WB : return 1; case WW : return 0; } } } ---------------------------------------------------- Now, let f(n, k, xx) denote the number of ways of having - n columns - k components - xx last column Suppose we have inserted a new column xy Now, (xx, xy) will fall in one of the 16 cases mentioned above. Let the number of components be k' now. Accordingly, f(n + 1, k', xy) += f(n, k, xx) ---------------------------------------------- So, this is how we define the recurrence - For every possible last column we can have, we iterate over every possible second last column and add it to the answer with the corresponding number of components. f(n + 1, k', xy) = sum(f(n, k, xx)) for all (k, xx) such that inserting the column xy after xx results in k' components from k components. The code may make it clearer. -------------------------------------------- for(int column = 2; column <= no_of_columns; column++) { for(int components = 1; components <= 2*no_of_columns; components++) { for(int last = 0; last < NO_OF_COLUMN_ARRANGEMENTS; last++) { for(int second_last = 0; second_last < NO_OF_COLUMN_ARRANGEMENTS; second_last++) { int new_components = components + additional_components(second_last, last); no_of_ways[column][new_components][last] += no_of_ways[column - 1][components][second_last]; no_of_ways[column][new_components][last] %= MOD; } } } } ------------------------------ What is the base case ? f(1, 1, BB) = f(1, 1, WW) = 1 f(1, 2, BW) = f(1, 2, WB) = 1 All other f(1, _ , __) = 0 ----------------------------------------------- Now, the answer = f(n, k, BB) + f(n, k, BW) + f(n, k, WB) + f(n, k, WW) LL answer = 0; for(int last = 0; last < NO_OF_COLUMN_ARRANGEMENTS; last++) { answer += no_of_ways[no_of_columns][no_of_components][last]; answer %= MOD; } ================================================ FILE: Contests/Educational Round 51/Explanation/Relatively Prime Pairs Explanation.txt ================================================ gcd(n, n + 1) = 1 Print pairs of consecutive integers. ------------------------------------ int main() { long long left, right; scanf("%I64d %I64d", &left, &right); printf("YES\n"); for(long long i = left; i <= right; i += 2) printf("%I64d %I64d\n", i, i + 1); return 0; } ================================================ FILE: Contests/Educational Round 51/Explanation/Vasya and Multisets Explanation.txt ================================================ Observation - If an element occurs two times, then it does not affect the difference in the number of nice elements in the multisets. Proof - If we place them in same multiset, then the number of nice elements in both subsets remain the same and does not increase. If we place them in different multisets, then the number of nice elements in both subsets increases by one. --------------------------------------------------- Case 1 - There are an even number of elements which occcur one time. Then we place half of them in either multiset. And place all the remaining elements in A. -------------------------------------------- Case 2 - There are an odd number of elements which occur one time. Case 2a - There is at least one element who's frequency is greater than 2. If there are (2n + 1) elements which occur one time, then place n of them in A, (n + 1) of them in B. Then place exactly one occurence of the element who's frequency > 2 in A, and place the others in B. Now, A and B both have exactly (n + 1) nice elements. We know place the remaining elements in A. --------------------------------------------- Case 2b - There is no element who's frequency > 2 Since there are an odd number of elements who's frequency is 1, there must be one multiset which has more nice elements than the other. As per our observation, elements who's frequency is 2, will not make the difference of nice elements in A and B 0 from 1. So, it is never possible in this case. ---------------------------------------------- How do we implement this ? We keep track of where we placed the last nice element (A or B). Whenever we come across any other nice element, place it in the OPPOSITE side. If an element comes who's frequency is greater than 1, then just dump it in A. This suffices for Case 1. What to do about the Case 2b ? In that case, the first time we encounter an element who's frequency is greater than 2, we mark it as a special character and then place it on either side. Whenever we come across it's next occurences, we will place it on the opposite side than the first side. Something like this - if(frequency[A[i]] > 2 && special == NOT_USED) { split += opposite(last); special_place = opposite(last); last = opposite(last); special_char = A[i]; special = USED; } else if(A[i] == special_char) { split += opposite(special_place); } ----------------------------------- The below code will make it clearer. const int USED = 0, NOT_USED = 1; int special = (frequency_1_elements%2 == 0 ? USED : NOT_USED), special_char = -1; char last = 'B', special_place; for(int i = 0; i < no_of_numbers; i++) { if(frequency[A[i]] == 1) { split += opposite(last); last = opposite(last); } else if(frequency[A[i]] > 2 && special == NOT_USED) { split += opposite(last); special_place = opposite(last); last = opposite(last); special_char = A[i]; special = USED; } else if(A[i] == special_char) { split += opposite(special_place); } else { split += 'A'; } } ================================================ FILE: Contests/Educational Round 51/Explanation/Vasya and Password Explanation.txt ================================================ First, we'll check if S is valid. int is_proper(string S) { int upper_case = 0, lower_case = 0, digits = 0; for(int i = 0; i < S.size(); i++) { if('a' <= S[i] && S[i] <= 'z') lower_case++; if('A' <= S[i] && S[i] <= 'Z') upper_case++; if('0' <= S[i] && S[i] <= '9') digits++; } return (upper_case > 0 && lower_case > 0 && digits > 0); } ------------------------------- If S is already valid, don't do anything. if(upper_case > 0 && lower_case > 0 && digits > 0) { cout << S << "\n"; return; } ---------------------------------- If S has only digits, but lacks upper case and lower case, then we can change the first two digits. if(upper_case == 0 && lower_case == 0 && digits > 0) { S[0] = 'A'; S[1] = 'a'; cout << S << "\n"; return; } else if(upper_case == 0 && lower_case > 0 && digits == 0) { S[0] = 'A'; S[1] = '0'; cout << S << "\n"; return; } else if(upper_case > 0 && lower_case == 0 && digits == 0) { S[0] = 'a'; S[1] = '0'; cout << S << "\n"; return; } --------------------------------------- If S has two properties but lacks the third, then keep changing one of the characters till you get a valid string. There will be atmost 2 checks like this. for(int i = 0; i < S.size(); i++)//Runs at most 2 times. { char original = S[i]; S[i] = '0'; if(is_proper(S)){cout << S << "\n"; return;} S[i] = 'a'; if(is_proper(S)){cout << S << "\n"; return;} S[i] = 'A'; if(is_proper(S)){cout << S << "\n"; return;} S[i] = original; } ================================================ FILE: Contests/Educational Round 51/Programs/Bicolourings.cpp ================================================ #include #include const int NO_OF_COLUMN_ARRANGEMENTS = 4, MAX_N = 1005; const int MOD = 998244353; const int BB = 0, BW = 1, WB = 2, WW = 3; typedef long long LL; LL no_of_ways[MAX_N][2*MAX_N][NO_OF_COLUMN_ARRANGEMENTS]; int additional_components(int second_last, int last) { switch(second_last) { case BB : switch(last) { case BB : return 0; case BW : return 1; case WB : return 1; case WW : return 1; } case BW : switch(last) { case BB : return 0; case BW : return 0; case WB : return 2; case WW : return 0; } case WB : switch(last) { case BB : return 0; case BW : return 2; case WB : return 0; case WW : return 0; } case WW : switch(last) { case BB : return 1; case BW : return 1; case WB : return 1; case WW : return 0; } } } int main() { int no_of_columns, no_of_components; scanf("%d %d", &no_of_columns, &no_of_components); memset(no_of_ways, 0, sizeof(no_of_ways)); no_of_ways[1][1][BB] = no_of_ways[1][1][WW] = 1; no_of_ways[1][2][BW] = no_of_ways[1][2][WB] = 1; for(int column = 2; column <= no_of_columns; column++) { for(int components = 1; components <= 2*no_of_columns; components++) { for(int last = 0; last < NO_OF_COLUMN_ARRANGEMENTS; last++) { for(int second_last = 0; second_last < NO_OF_COLUMN_ARRANGEMENTS; second_last++) { int new_components = components + additional_components(second_last, last); no_of_ways[column][new_components][last] += no_of_ways[column - 1][components][second_last]; no_of_ways[column][new_components][last] %= MOD; } } } } LL answer = 0; for(int last = 0; last < NO_OF_COLUMN_ARRANGEMENTS; last++) { answer += no_of_ways[no_of_columns][no_of_components][last]; answer %= MOD; } printf("%I64d\n", answer); return 0; } ================================================ FILE: Contests/Educational Round 51/Programs/Relatively Prime Pairs.cpp ================================================ #include int main() { long long left, right; scanf("%I64d %I64d", &left, &right); printf("YES\n"); for(long long i = left; i <= right; i += 2) printf("%I64d %I64d\n", i, i + 1); return 0; } ================================================ FILE: Contests/Educational Round 51/Programs/Vasya and Multisets.cpp ================================================ #include #include using namespace std; char opposite(char ch) { return (ch == 'A' ? 'B' : 'A'); } int main() { int no_of_numbers; cin >> no_of_numbers; vector A(no_of_numbers); for(int i = 0; i < no_of_numbers; i++) cin >> A[i]; const int MAX = 105; vector frequency(MAX, 0); for(int i = 0; i < no_of_numbers; i++) frequency[A[i]]++; int frequency_1_elements = 0, frequency_more_than_2_elements = 0; for(int i = 0; i < MAX; i++) { if(frequency[i] == 1) frequency_1_elements++; if(frequency[i] > 2) frequency_more_than_2_elements++; } if(frequency_1_elements%2 == 1 && frequency_more_than_2_elements == 0) { cout << "NO\n"; return 0; } cout << "YES\n"; string split; const int USED = 0, NOT_USED = 1; int special = (frequency_1_elements%2 == 0 ? USED : NOT_USED), special_char = -1; char last = 'B', special_place; for(int i = 0; i < no_of_numbers; i++) { if(frequency[A[i]] == 1) { split += opposite(last); last = opposite(last); } else if(frequency[A[i]] > 2 && special == NOT_USED) { split += opposite(last); special_place = opposite(last); last = opposite(last); special_char = A[i]; special = USED; } else if(A[i] == special_char) { split += opposite(special_place); } else { split += 'A'; } } cout << split; return 0; } ================================================ FILE: Contests/Educational Round 51/Programs/Vasya and Password.cpp ================================================ #include using namespace std; int is_proper(string S) { int upper_case = 0, lower_case = 0, digits = 0; for(int i = 0; i < S.size(); i++) { if('a' <= S[i] && S[i] <= 'z') lower_case++; if('A' <= S[i] && S[i] <= 'Z') upper_case++; if('0' <= S[i] && S[i] <= '9') digits++; } return (upper_case > 0 && lower_case > 0 && digits > 0); } void solve() { string S; cin >> S; int upper_case = 0, lower_case = 0, digits = 0; for(int i = 0; i < S.size(); i++) { if('a' <= S[i] && S[i] <= 'z') lower_case++; if('A' <= S[i] && S[i] <= 'Z') upper_case++; if('0' <= S[i] && S[i] <= '9') digits++; } if(upper_case > 0 && lower_case > 0 && digits > 0) { cout << S << "\n"; return; } else if(upper_case == 0 && lower_case == 0 && digits > 0) { S[0] = 'A'; S[1] = 'a'; cout << S << "\n"; return; } else if(upper_case == 0 && lower_case > 0 && digits == 0) { S[0] = 'A'; S[1] = '0'; cout << S << "\n"; return; } else if(upper_case > 0 && lower_case == 0 && digits == 0) { S[0] = 'a'; S[1] = '0'; cout << S << "\n"; return; } for(int i = 0; i < S.size(); i++)//Runs at most 2 times. { char original = S[i]; S[i] = '0'; if(is_proper(S)){cout << S << "\n"; return;} S[i] = 'a'; if(is_proper(S)){cout << S << "\n"; return;} S[i] = 'A'; if(is_proper(S)){cout << S << "\n"; return;} S[i] = original; } } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 52/Explanations/Vasya and Chocolates Explanation.txt ================================================ The maximum amount of money that can be spent = Money/c These many candies are paid for. For every 'a' free candies, 'b' free candies are gotten. ------------------- void solve() { long long money, a, b, cost; cin >> money >> a >> b >> cost; long long paid_candies = (money/cost); long long free_candies = (paid_candies/a)*b; long long total_candies = paid_candies + free_candies; cout << total_candies << "\n"; } ================================================ FILE: Contests/Educational Round 52/Explanations/Vasya and Isolated Vertices Explanation.txt ================================================ Now, let us try to minimise the number of isolated vertices. We will connect 2 new vertices with each edge. We need V/2 number of edges. If we have less ... Then isolated = V - 2E What if we try to maximise it ? Let us have a fully connected component of as small size as possible. A fully connected component of size k requires C(k, 2) edges. Use up edges greedily like this and see how many are remaining. ------------------------------------- int main() { long long vertices, edges; cin >> vertices >> edges; int minimum_isolated_vertices = max(0, vertices - 2*edges); long long i = 0; while(edges > 0 && choose_2(i) <= edges) i++; int fully_connected_component = (choose_2(i - 1) == edges ? i - 1 : i); int maximum_isolated_vertices = vertices - fully_connected_component; cout << minimum_isolated_vertices << " " << maximum_isolated_vertices << "\n"; return 0; } ================================================ FILE: Contests/Educational Round 52/Programs/Vasya and Chocolates.cpp ================================================ #include using namespace std; void solve() { long long money, a, b, cost; cin >> money >> a >> b >> cost; long long paid_candies = (money/cost); long long free_candies = (paid_candies/a)*b; long long total_candies = paid_candies + free_candies; cout << total_candies << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 52/Programs/Vasya and Isolated Vertices.cpp ================================================ #include #define max(a, b) (a > b ? a : b) using namespace std; long long choose_2(long long n) { return (n*(n - 1))/2; } int main() { long long vertices, edges; cin >> vertices >> edges; int minimum_isolated_vertices = max(0, vertices - 2*edges); long long i = 0; while(choose_2(i) <= edges) i++; int fully_connected_component = (choose_2(i - 1) == edges ? i - 1 : i); int maximum_isolated_vertices = vertices - fully_connected_component; cout << minimum_isolated_vertices << " " << maximum_isolated_vertices << "\n"; return 0; } ================================================ FILE: Contests/Educational Round 54/Explanation/Divisor Subtraction Explanation.txt ================================================ Case 1 - n is even The smallest divisor is 2. We subtract 2 and the smallest divisor is always 2. So the answer is simply n/2. Case 2 - n is odd, Then we subtract the smallest odd divisor from n. This makes n even and the problem is reduced the Case 1 Answer = 1 + (n - p)/2, where p is the smallest prime factor of n ----------- int main() { long long n; cin >> n; const long long NOT_FOUND = 0; long long smallest_odd_prime_factor = NOT_FOUND; if(n%2 == 1) { for(long long i = 3; i*i <= n; i++) { if(n%i == 0) { smallest_odd_prime_factor = i; break; } } if(smallest_odd_prime_factor == NOT_FOUND) smallest_odd_prime_factor = n; } long long even_operations = (n - smallest_odd_prime_factor)/2; long long no_of_operations = (n%2 == 1) + even_operations; cout << no_of_operations; return 0; } ================================================ FILE: Contests/Educational Round 54/Explanation/Meme Problem Explanation.txt ================================================ Now, we have two equations to solve - a + b = d ab = d Now, we simply reduce it to one variable b(d - b) = d bd - b^2 = d b^2 - bd + d = 0 --------------- We solve this quadratic equation and print 10 decimal places. There is not solution only when d = 1. ----- void solve() { int d; scanf("%d", &d); if(d == 0) { printf("Y 0.000000 0.000000\n"); } else if(d*d - 4*d < 0) { printf("N\n"); } else { double b = (d + sqrt(d*d - 4*d))/2; double a = b/(b - 1); printf("Y %.10f %.10f\n", a, b); } } ================================================ FILE: Contests/Educational Round 54/Explanation/Minimizing the String Explanation.txt ================================================ Let us have two strings - A1 A2 A3 ... An B1 B2 B3 ... Bn Now, A < B, if the first unequal character in A is smaller than in B. Let j be the first position such that A(j) =/= B(j) Then A < B if A(j) < B(j) ------------------ Now we go through the string given to us and remove the first character i such that S(i) > S(i + 1). Now, let us prove that such a string S' will be smaller than all other strings obtained by removing one character from S. --- Case 1 - We have removed some character after i Then both strings have the same first (i - 1) characters. Then the other strings will have S(i) and S' will have S(i + 1) at the i-th position. So, S' < S --- Case 2 - We remove some character before i Then suppose we have removed j-th character. Both strings have same first j - 1 characters. S' has A(j) and the other other string has A(j + 1) By definition i is the first position where S(i + 1) < S(i) This means A(j + 1) >= A(j) So this proves that the other string cannot be smaller than S'. -------- This completes our proof that we obtain the minimum such string by removing the first character where S(i + 1) < S(i) ----- int main() { int length; string S; cin >> length >> S; vector is_ignored(length, false); for(int i = 0; i < length; i++) { if(i + 1 == length || S[i] > S[i + 1]) { is_ignored[i] = true; break; } } for(int i = 0; i < length; i++) if(!is_ignored[i]) cout << S[i]; return 0; } ================================================ FILE: Contests/Educational Round 54/Programs/Divisor Subtraction.cpp ================================================ #include using namespace std; int main() { long long n; cin >> n; const long long NOT_FOUND = 0; long long smallest_odd_prime_factor = NOT_FOUND; if(n%2 == 1) { for(long long i = 3; i*i <= n; i++) { if(n%i == 0) { smallest_odd_prime_factor = i; break; } } if(smallest_odd_prime_factor == NOT_FOUND) smallest_odd_prime_factor = n; } long long even_operations = (n - smallest_odd_prime_factor)/2; long long no_of_operations = (n%2 == 1) + even_operations; cout << no_of_operations; return 0; } ================================================ FILE: Contests/Educational Round 54/Programs/Meme Problem.cpp ================================================ #include #include /* b + b/(b - 1) = d b^2 - b + b = db - d b^2 -db + d = 0 d + root(d^2 - 4d)/2 */ void solve() { int d; scanf("%d", &d); if(d == 0) { printf("Y 0.000000 0.000000\n"); } else if(d*d - 4*d < 0) { printf("N\n"); } else { double b = (d + sqrt(d*d - 4*d))/2; double a = b/(b - 1); printf("Y %.10f %.10f\n", a, b); } } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 54/Programs/Minimizing the String.cpp ================================================ #include #include using namespace std; int main() { int length; string S; cin >> length >> S; vector is_ignored(length, false); for(int i = 0; i < length; i++) { if(i + 1 == length || S[i] > S[i + 1]) { is_ignored[i] = true; break; } } for(int i = 0; i < length; i++) if(!is_ignored[i]) cout << S[i]; return 0; } ================================================ FILE: Contests/Educational Round 55/Explanation/Increasing Frequency Explanation.txt ================================================ Quora Blog Link - https://qr.ae/TUtpPB ------------------------- int main() { int no_of_elements, target; cin >> no_of_elements >> target; vector A(no_of_elements + 1); vector sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; position[A[i]].push_back(i); sum[i] = sum[i - 1] + (A[i] == target); } int maximum_changes = 0; for(int i = 0; i < MAX_N; i++) { if(i == target) continue; int max_ending_here = 0; for(int j = 0; j < position[i].size(); j++) { int p = position[i][j], q = (j == 0 ? 0 : position[i][j - 1]); int no_of_minus_ones = sum[p] - sum[q]; max_ending_here = max(max_ending_here - no_of_minus_ones + 1, 1); maximum_changes = max(maximum_changes, max_ending_here); } } int target_frequency = position[target].size(); int maximum_occurences = maximum_changes + target_frequency; cout << maximum_occurences; return 0; } ================================================ FILE: Contests/Educational Round 55/Programs/Increasing Frequency.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 5e5 + 5, oo = 1e9; vector position[MAX_N]; int main() { int no_of_elements, target; cin >> no_of_elements >> target; vector A(no_of_elements + 1); vector sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> A[i]; position[A[i]].push_back(i); sum[i] = sum[i - 1] + (A[i] == target); } int maximum_changes = 0; for(int i = 0; i < MAX_N; i++) { if(i == target) continue; int max_ending_here = 0; for(int j = 0; j < position[i].size(); j++) { int p = position[i][j], q = (j == 0 ? 0 : position[i][j - 1]); int no_of_minus_ones = sum[p] - sum[q]; max_ending_here = max(max_ending_here - no_of_minus_ones + 1, 1); maximum_changes = max(maximum_changes, max_ending_here); } } int target_frequency = position[target].size(); int maximum_occurences = maximum_changes + target_frequency; cout << maximum_occurences; return 0; } ================================================ FILE: Contests/Educational Round 56/Explanations/Beautiful Graph Explanation.txt ================================================ 1. For a moment, let us forget about the numbers 1, 2 and 3 and just focus on parity. For two vertices to have an odd sum, they must be of different parity. 2. For each vertex, we must connect a vertex of a different parity to it. 3. There are two ways of choosing the odd parity and one way of choosing an even number. 4. When we are given a graph, we must check if it is possible to treat this graph as a bipartite graph. In that case, each group will have one parity. Note - If a graph is not bipartite, it will have a cycle of odd length. 5. If the component sizes are C1 and C2, then we can make the C1 component odd in 2^C1 ways and the C2 component odd in 2^C2 ways. Answer = 2^C1 + 2^C2 ---------------- A few points I missed - 1. The graph is not necessarily connected. In that case, the above algorithm must be repeated for each connected component. 2. For each test case, don't clean all MAX_N points ... as that will time out, clean only n. 3. To check if a graph is bipartite, do BFS. Paint a graph as red, and all of it's unpainted children as blue and all the blue's unpainted children red and so on. If there comes a point when a vertex and it's child have the same colour, the graph is not bipartite. ------- long long get_component_answer_bfs(int source) { queue Q; Q.push(source); colour[source] = 1; vector component(2, 0); component[colour[source]]++; long long this_component_answer = 1; while(!Q.empty()) { int current_v = Q.front(); Q.pop(); for(int i = 0; i < graph[current_v].size(); i++) { int child_v = graph[current_v][i]; if(colour[child_v] == NOT_KNOWN) { colour[child_v] = get_complement(colour[current_v]); component[colour[child_v]]++; Q.push(child_v); } else if(colour[child_v] == colour[current_v]) //It's not bipartite { return 0; } } } this_component_answer = (power_mod(2, component[0]) + power_mod(2, component[1]))%MOD; return this_component_answer; } void solve() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } long long answer = 1; for(int i = 1; i <= no_of_vertices; i++) { if(colour[i] == NOT_KNOWN) answer = (answer*get_component_answer_bfs(i))%MOD; } printf("%I64d\n", answer); clean_for_next_query(no_of_vertices); } ================================================ FILE: Contests/Educational Round 56/Explanations/Dice Rolling Explanation.txt ================================================ Obviously, there are many answers to this question. The simplest is ceil(n/7). --------------- void solve() { int target_score; cin >> target_score; int no_of_rolls = ceil(target_score, 7); cout << no_of_rolls << "\n"; } ================================================ FILE: Contests/Educational Round 56/Explanations/Letters Rearranging Explanation.txt ================================================ Now, the only time when it is impossible to re-arrange a string to get a non-palindrome is when all characters are the same ! If all characters are the same, then don't do anything. Else, print any valid non-palindrome. Now, there are many ways to do this. But, here was my elegant solution. 1. Sort the string. 2. If the first and character are the same, it means all the characters are the same. 3. If they aren't then simply print the string in sorted order. -------- void solve() { string S; cin >> S; sort(all(S)); cout << (S[0] == S[S.size() - 1] ? "-1" : S) << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 56/Explanations/Mishka and Last Exam Explanation.txt ================================================ We will be greedy. For each B[i], 1. Try to make A[i] as small as possible. The smallest possible value that A[i] can take on is A[i - 1]. If A[i] = A[i - 1], then A[n - i + 1] = B[i] - A[i - 1] It is important to check if (B[i] - A[i - 1]) <= A[n - i + 1 + 1] If it is, then we are done A[i] = A[i - 1], A[n - i + 1] = B[i] - A[i] 2. If not, then we will make A[n - i + 1] as large as possible and then find A[i] A[n - i + 1] = A[n - i + 1 + 1] A[i] = B[i] - A[n - i + 1] 3. We need not worry that both these situations won't occur as the question guarantees us this. ----------------------------- We are given that there is always an answer so we need not worry. This greedy algorithm ensures that A[i - 1] <= A[i] and A[i] <= A[i + 1]. We have maintained this invariant in building it. If the answer weren't possible, then we would be getting negative integers at some point. -------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector B(no_of_elements/2 + 1); for(int i = 1; i <= no_of_elements/2; i++) scanf("%I64d", &B[i]); vector A(no_of_elements + 2, 0); int front = 0, back = no_of_elements + 1; const long long oo = 2e18; A[back] = oo; for(int i = 1; i <= no_of_elements/2; i++) { if(B[i] - A[front] > A[back]) { A[back - 1] = A[back]; back--; A[front + 1] = B[i] - A[back]; front++; } else { A[front + 1] = A[front]; front++; A[back - 1] = B[i] - A[front]; back--; } } for(int i = 1; i <= no_of_elements; i++) printf("%I64d ", A[i]); return 0; } ================================================ FILE: Contests/Educational Round 56/Programs/Beautiful Graph.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 3e5 + 5, NOT_KNOWN = -1, MOD = 998244353; vector graph[MAX_N]; vector colour(MAX_N, NOT_KNOWN); long long power_mod(long long base, long long power) { long long result = 1; while(power) { if(power%2 == 1) result = (result*base)%MOD; base = (base*base)%MOD; power = power >> 1; } return result; } void clean_for_next_query(int limit) { for(int i = 0; i <= limit; i++) { graph[i].clear(); colour[i] = NOT_KNOWN; } } int get_complement(int x) //Return 1 if 0 and 0 if 1 { return (1 - x); } long long get_component_answer_bfs(int source) { queue Q; Q.push(source); colour[source] = 1; vector component(2, 0); component[colour[source]]++; long long this_component_answer = 1; while(!Q.empty()) { int current_v = Q.front(); Q.pop(); for(int i = 0; i < graph[current_v].size(); i++) { int child_v = graph[current_v][i]; if(colour[child_v] == NOT_KNOWN) { colour[child_v] = get_complement(colour[current_v]); component[colour[child_v]]++; Q.push(child_v); } else if(colour[child_v] == colour[current_v]) //It's not bipartite { return 0; } } } this_component_answer = (power_mod(2, component[0]) + power_mod(2, component[1]))%MOD; return this_component_answer; } void solve() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } long long answer = 1; for(int i = 1; i <= no_of_vertices; i++) { if(colour[i] == NOT_KNOWN) answer = (answer*get_component_answer_bfs(i))%MOD; } printf("%I64d\n", answer); clean_for_next_query(no_of_vertices); } int main() { int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 56/Programs/Dice Rolling.cpp ================================================ #include using namespace std; int ceil(int numerator, int denominator) { int quotient = numerator/denominator; int remainder = numerator%denominator; return (quotient + (remainder!= 0)); } void solve() { int target_score; cin >> target_score; int no_of_rolls = ceil(target_score, 7); cout << no_of_rolls << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 56/Programs/Letters Rearranging.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { string S; cin >> S; sort(all(S)); cout << (S[0] == S[S.size() - 1] ? "-1" : S) << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 56/Programs/Mishka and Last Exam.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector B(no_of_elements/2 + 1); for(int i = 1; i <= no_of_elements/2; i++) scanf("%I64d", &B[i]); vector A(no_of_elements + 2, 0); int front = 0, back = no_of_elements + 1; const long long oo = 2e18; A[back] = oo; for(int i = 1; i <= no_of_elements/2; i++) { if(B[i] - A[front] > A[back]) { A[back - 1] = A[back]; back--; A[front + 1] = B[i] - A[back]; front++; } else { A[front + 1] = A[front]; front++; A[back - 1] = B[i] - A[front]; back--; } } for(int i = 1; i <= no_of_elements; i++) printf("%I64d ", A[i]); return 0; } ================================================ FILE: Contests/Educational Round 60/Explanations/Best Subsegment Explanation.txt ================================================ Fact - The arithmetic mean of any segment cannot be greater than the maximum integer in the array. Proof - (a1 + a2 + ... + aN) = M x N, where M is the mean. If M > max{a1, ... , aN}, then M x N will be greater than (a1 + a2 + ... + aN), which is not possible. -------- Now, which segments have the mean = Max ? Those segments that ONLY have the max element. Now, the question has reduced to finding the longest segment of the array consisting of the given element x. ------------ int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; int maximum = 0; for(int i = 1; i <= no_of_elements; i++) maximum = max(maximum, A[i]); int max_longest_segment = 0, longest_segment_here = 0; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != maximum) { longest_segment_here = 0; } else { longest_segment_here++; max_longest_segment = max(max_longest_segment, longest_segment_here); } } cout << max_longest_segment; return 0; } ================================================ FILE: Contests/Educational Round 60/Explanations/Emotes Explanation.txt ================================================ We will be greedy ... 1. We will use the maximum element K times in a row. 2. Then, we will use the second maximum element. And then, we will repeat. This happens in cycles of (K + 1). We need to find out the number of cycles and the cost for each cycle. ------------ int main() { int no_of_elements, total_chosen, maximum_consecutive; cin >> no_of_elements >> total_chosen >> maximum_consecutive; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) cin >> A[i]; sort(all(A)); reverse(all(A)); long long no_of_cycles = total_chosen/(maximum_consecutive + 1); long long cycle_total = A[0]*maximum_consecutive + A[1]; long long remaining = total_chosen%(maximum_consecutive + 1); long long total = cycle_total*no_of_cycles + A[0]*remaining; cout << total; return 0; } ================================================ FILE: Contests/Educational Round 60/Programs/Best Subsegment.cpp ================================================ #include #include using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; int maximum = 0; for(int i = 1; i <= no_of_elements; i++) maximum = max(maximum, A[i]); int max_longest_segment = 0, longest_segment_here = 0; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != maximum) { longest_segment_here = 0; } else { longest_segment_here++; max_longest_segment = max(max_longest_segment, longest_segment_here); } } cout << max_longest_segment; return 0; } ================================================ FILE: Contests/Educational Round 60/Programs/Emotes.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, total_chosen, maximum_consecutive; cin >> no_of_elements >> total_chosen >> maximum_consecutive; vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) cin >> A[i]; sort(all(A)); reverse(all(A)); long long no_of_cycles = total_chosen/(maximum_consecutive + 1); long long cycle_total = A[0]*maximum_consecutive + A[1]; long long remaining = total_chosen%(maximum_consecutive + 1); long long total = cycle_total*no_of_cycles + A[0]*remaining; cout << total; return 0; } ================================================ FILE: Contests/Educational Round 62/Explanations/Detective Book Explanation.txt ================================================ When we are at day i, we will keep on going till A[i] at least. So the target for the day is always maximum of max(target, A[i]). If we have reached i, and i is the current target, then we will increment the number of days as we will close for the day. --- int main() { int no_of_pages; cin >> no_of_pages; vector page(no_of_pages + 1, 0); for(int i = 1; i <= no_of_pages; i++) cin >> page[i]; int no_of_days = 0, day_target = 0; for(int i = 1; i <= no_of_pages; i++) { day_target = max(day_target, page[i]); if(day_target == i) { day_target = 0; no_of_days++; } } cout << no_of_days; return 0; } ================================================ FILE: Contests/Educational Round 62/Explanations/Good Strings Explanation.txt ================================================ We will keep only one character in the string. It will either be the first '>' or the last '<', whichever requires fewer deletions. -------- void solve() { int length; string S; cin >> length >> S; int answer; for(int i = 0; i < length; i++) { if(S[i] == '>') { answer = i; break; } } for(int i = length - 1; i >= 0; i--) { if(S[i] == '<') { answer = min(answer, length - 1 - i); break; } } cout << answer << "\n"; } ================================================ FILE: Contests/Educational Round 62/Explanations/Minimum Triangulation Explanation.txt ================================================ We want to divide the N numbers - 1, 2, 3, ... , N into N - 2 triplets (a, b, c) such that the sum of the products of abc is minimum 1. Each side must occur in at least one triplet. --- If we want to minimise the sum, we need to ensure that the smallest element - 1, is present in each triplet. Now each triplet is really the product of 2 integers. We want to minimise the product. So, we will pair 2 with 3. Pairing 2 with any other number will yield a greater product. Then, by the same logic we will pair 3 with 4, 4 with 5 and so on. ---- int main() { int n; cin >> n; int weight = 0; for(int i = 3; i <= n; i++) weight += i*(i - 1); cout << weight; return 0; } ================================================ FILE: Contests/Educational Round 62/Explanations/Playlist Explanation.txt ================================================ Let us sort all the songs by beauty and then start processing the songs backwards from the last song till the first. We will iterate over all N songs and calculate the pleasure of the playlist if song i, is the song with minimum beauty in the playlist. We will choose the maximum of these pleasures. At our current moment, we will be pointing to the song who's beauty is the minimum. As for the length ... We will choose the maximum K - 1 lengths from [i + 1, ... , N]. For doing this, we will need to maintain a priority queue of length K. At each step, we will remove the smallest length of the priority queue and insert the current length. ---- struct song { LL length, beauty; song(){} song(LL L, LL B) { length = L, beauty = B; } const int operator <(song &S) { return (beauty < S.beauty); } }; int main() { int no_of_songs, max_songs; cin >> no_of_songs >> max_songs; vector songs(no_of_songs); for(int i = 0; i < no_of_songs; i++) cin >> songs[i].length >> songs[i].beauty; sort(all(songs)); LL pleasure = 0; LL current_beauty, current_length = 0; priority_queue , greater > lengths; int current_chosen = 0; for(int i = no_of_songs - 1; i >= 0; i--) { current_beauty = songs[i].beauty; if(current_chosen >= max_songs) { current_length -= lengths.top(); lengths.pop(); } current_length += songs[i].length; lengths.push(songs[i].length); pleasure = max(pleasure, current_beauty*current_length); if(current_chosen < max_songs) { current_chosen++; } } cout << pleasure; return 0; } ================================================ FILE: Contests/Educational Round 62/Programs/Detective Book.cpp ================================================ #include #include using namespace std; int main() { int no_of_pages; cin >> no_of_pages; vector page(no_of_pages + 1, 0); for(int i = 1; i <= no_of_pages; i++) cin >> page[i]; int no_of_days = 0, day_target = 0; for(int i = 1; i <= no_of_pages; i++) { day_target = max(day_target, page[i]); if(day_target == i) { day_target = 0; no_of_days++; } } cout << no_of_days; return 0; } ================================================ FILE: Contests/Educational Round 62/Programs/Good Strings.cpp ================================================ #include #include using namespace std; void solve() { int length; string S; cin >> length >> S; int answer; for(int i = 0; i < length; i++) { if(S[i] == '>') { answer = i; break; } } for(int i = length - 1; i >= 0; i--) { if(S[i] == '<') { answer = min(answer, length - 1 - i); break; } } cout << answer << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 62/Programs/Minimum Triangulation.cpp ================================================ #include using namespace std; int main() { int n; cin >> n; int weight = 0; for(int i = 3; i <= n; i++) weight += i*(i - 1); cout << weight; return 0; } ================================================ FILE: Contests/Educational Round 62/Programs/Playlist.cpp ================================================ #include #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; typedef long long LL; struct song { LL length, beauty; song(){} song(LL L, LL B) { length = L, beauty = B; } const int operator <(song &S) { return (beauty < S.beauty); } }; int main() { int no_of_songs, max_songs; cin >> no_of_songs >> max_songs; vector songs(no_of_songs); for(int i = 0; i < no_of_songs; i++) cin >> songs[i].length >> songs[i].beauty; sort(all(songs)); LL pleasure = 0; LL current_beauty, current_length = 0; priority_queue , greater > lengths; int current_chosen = 0; for(int i = no_of_songs - 1; i >= 0; i--) { current_beauty = songs[i].beauty; if(current_chosen >= max_songs) { current_length -= lengths.top(); lengths.pop(); } current_length += songs[i].length; lengths.push(songs[i].length); pleasure = max(pleasure, current_beauty*current_length); if(current_chosen < max_songs) { current_chosen++; } } cout << pleasure; return 0; } ================================================ FILE: Contests/Educational Round 69/Explanations/Array Splitting Explanation.txt ================================================ Let us suppose that we want to break (A[1], ... , A[n]) at point P. What is the cost ? (A[p] - A[1]) + (A[n] - A[p + 1]) Suppose we want to break it at two points - p1 and p2. What is the cost ? (A[p1] - A[1]) + (A[p2] - A[p1 + 1]) + (A[n] - A[p2 + 1]) = (A[p1] - A[p1 + 1]) + (A[p2] - A[p2 + 1]) + (A[n] - A[1]) Every time we break it at point p, we will add A[p + 1] - A[p] to the cost. (A[n] - A[1]) is a fixed cost that will be there regardless of how we choose our cuts. So, we will create an array of all possible costs of all (N - 1) cuts. The cost is (A[i + 1] - A[i]) Among these costs, we will take the lowest (K - 1) values. These are the cuts we need to split the array into K subarrays. ----- #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_subarrays; cin >> no_of_elements >> no_of_subarrays; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; vector costs; for(int i = 1; i < no_of_elements; i++) costs.push_back(A[i] - A[i + 1]); sort(all(costs)); long long total_cost = A[no_of_elements] - A[1]; for(int i = 0; i < no_of_subarrays - 1; i++) total_cost += costs[i]; cout << total_cost; return 0; } ================================================ FILE: Contests/Educational Round 69/Explanations/DIY Wooden Ladder Explanation.txt ================================================ We want the ladder to be as big as possible. SO we will use the largest pieces of wood available to us to make the ladder's bases. Then we will be using A[n] and A[n - 1] to make the base. Now, we will try to use as many of the (n - 2) available planks available to us to make the ladder. But we cannot use more than (A[n - 1] - 1) planks. The height of the ladder is min{A[n - 1] - 1, n - 2} --- void solve() { int no_of_elements; cin >> no_of_elements; vector length(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) cin >> length[i]; sort(all(length)); int no_of_steps = min(length[no_of_elements - 1] - 1, no_of_elements - 2); cout << no_of_steps << "\n"; } ================================================ FILE: Contests/Educational Round 69/Explanations/Pillars Explanation.txt ================================================ It is not possible, whenever there exists any element A[i], such that there are values greater than A[i] both to it's left and it's right. Proof - Let A[i] = x, Let Y > x and Z > x Let Y be to the left of x and Z to the right of x. Without loss of generatlity, let Z > Y We need to put Y on top of Z and then X on top of Y. But Y has to cross X to reach Z. This is not possible. --- If this isn't the case, then every array element has all the elements greater than it on one side. We simply move the coins along that direction. --- int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; vector max_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) max_till[i] = max(max_till[i - 1], A[i]); vector max_from(no_of_elements + 2, 0); for(int i = no_of_elements; i >= 1; i--) max_from[i] = max(max_from[i + 1], A[i]); int possible = true; for(int i = 2; i < no_of_elements; i++) if(max_till[i] > A[i] && max_from[i] > A[i]) possible = false; cout << (possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Educational Round 69/Programs/Array Splitting.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements, no_of_subarrays; cin >> no_of_elements >> no_of_subarrays; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; vector costs; for(int i = 1; i < no_of_elements; i++) costs.push_back(A[i] - A[i + 1]); sort(all(costs)); long long total_cost = A[no_of_elements] - A[1]; for(int i = 0; i < no_of_subarrays - 1; i++) total_cost += costs[i]; cout << total_cost; return 0; } ================================================ FILE: Contests/Educational Round 69/Programs/DIY Wooden Ladder.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector length(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) cin >> length[i]; sort(all(length)); int no_of_steps = min(length[no_of_elements - 1] - 1, no_of_elements - 2); cout << no_of_steps << "\n"; } int main() { int no_of_queries; cin >> no_of_queries; while(no_of_queries--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 69/Programs/Pillars.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() using namespace std; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; vector max_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) max_till[i] = max(max_till[i - 1], A[i]); vector max_from(no_of_elements + 2, 0); for(int i = no_of_elements; i >= 1; i--) max_from[i] = max(max_from[i + 1], A[i]); int possible = true; for(int i = 2; i < no_of_elements; i++) if(max_till[i] > A[i] && max_from[i] > A[i]) possible = false; cout << (possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Educational Round 69/Rough Notes Link ================================================ https://1drv.ms/b/s!AoiWcyvzkQXViBWmPf3yuemGyCPl?e=EWKY9K ================================================ FILE: Contests/Educational Round 73/Explanations/2048 Game Explanation.txt ================================================ Add everything that is smaller than 2048 and see if a sum larger than 2048 is possible. ----- void solve() { int no_of_elements; cin >> no_of_elements; long long sum = 0; while(no_of_elements--) { int element; cin >> element; if(element <= 2048) sum += element; } cout << (sum >= 2048 ? "YES\n" : "NO\n"); } ================================================ FILE: Contests/Educational Round 73/Explanations/Game With String Explanation.txt ================================================ If there is any segment < B, then Alice can never touch it. Bob wins. If there is more than 1 segment >= 2B, then Bob can make one move on it and then reduce it to a segment of the previous type. If there are no segments >= 2B, we will count the number of segments in [A, 2B]. The parity decides the winner. The only trick is in knowing what to do when there is only 1 segment of length >= 2B. Alice will see if there exists a move she can make on this big segment such that the number of normal segments remaining is even. If there is such a move, she wins. Otherwise, Bob wins. ------ void solve() { int move_1, move_2; string S; cin >> move_1 >> move_2 >> S; int length = 0; vector segments; for(int i = 0; i < S.size(); i++) { if(S[i] == '.') { length++; } if(S[i] != '.' || i == S.size() - 1) { if(length != 0) { segments.push_back(length); } length = 0; } } int bob_segments = 0, normal_segments = 0, big_segments = 0; int big_segment_size = 0; for(int i = 0; i < segments.size(); i++) { if(move_2 <= segments[i] && segments[i] < move_1) { bob_segments++; } if(2*move_2 <= segments[i]) { big_segment_size = segments[i]; big_segments++; } if(move_1 <= segments[i] && segments[i] < 2*move_2) { normal_segments++; } } if(bob_segments > 0 || big_segments > 1) { cout << "NO\n"; return; } if(big_segments == 0) { cout << (normal_segments%2 == 1 ? "YES\n" : "NO\n"); return; } int winning = false; for(int part_1 = 0; big_segment_size - move_1 - part_1 >= 0; part_1++) { int part_2 = big_segment_size - move_1 - part_1; if(part_1 >= 2*move_2 || (move_2 <= part_1 && part_1 < move_1)) continue; if(part_2 >= 2*move_2 || (move_2 <= part_2 && part_2 < move_1)) continue; if( (normal_segments + (part_1 >= move_1) + (part_2 >= move_1))%2 == 0) { winning = true; break; } } cout << (winning ? "YES\n" : "NO\n"); } ================================================ FILE: Contests/Educational Round 73/Explanations/Knights Explanation.txt ================================================ The main invariant is that a knight can only attack squares on the other colour from it. This is why we will paint the board like a chessboard. --- #include using namespace std; int main() { int n; cin >> n; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { char colour = ( (i+j)%2 == 0 ? 'B' : 'W'); cout << colour; } cout << "\n"; } return 0; } ================================================ FILE: Contests/Educational Round 73/Explanations/Make The Fence Great Again Explanation.txt ================================================ The main observation is that every element will be increased at most twice. The reason is that there are only 2 neighbours. Among {i, i + 1, i + 2}, there can only be 2 values (at most) such that the neighbours have an equal value. Then, let f(i, x) be the cost for the first i elements if x additions are done on the i-th element. We can process the transition based on the value of A[i - 1] after y additions. The answer is min{f(n, 0), f(n, 1), f(n, 2)} --- void solve() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); vector cost(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d %I64d", &A[i], &cost[i]); } const long long oo = 1e18; vector > best(no_of_elements + 1, vector (3, 0)); best[0][0] = 0, best[0][1] = best[0][2] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int no_of_adds = 0; no_of_adds <= 2; no_of_adds++) { best[i][no_of_adds] = oo; for(int no_of_previous_adds = 0; no_of_previous_adds <= 2; no_of_previous_adds++) { if(A[i] + no_of_adds != A[i - 1] + no_of_previous_adds) { best[i][no_of_adds] = min(best[i][no_of_adds], best[i - 1][no_of_previous_adds] + no_of_adds*cost[i]); } } } } long long answer = oo; for(int no_of_adds = 0; no_of_adds <= 2; no_of_adds++) { answer = min(answer, best[no_of_elements][no_of_adds]); } printf("%I64d\n", answer); } ================================================ FILE: Contests/Educational Round 73/Explanations/Perfect Team Explanation.txt ================================================ If there are more normal people than Mathematicians and Coders, than we can have as many teams as the minimum of (M, C) by putting 1 of each in each team. Otherwise, we will make as many teams of (N, M, C) as possible. At the end of this, we will have 0 Normal people. Now, if M >= 2C or C >= 2M, then the number of teams we can make is C or M respectively. The reason is that there are 2 of the other kind for every one of one kind. Otherwise, the number of teams we can make is floor[(M + C)/3]. If 2*Min{M, C} > Max{M, C}, Then at each step we will take 2 of the Maximum and 1 of the Minimum. The number of people reduces by 3 each time and we will be unable to make a choice only when the number of people is less than 3. Hence, the answer is floor[(M + C)/3]. --- void solve() { int mathematicians, coders, normal; cin >> mathematicians >> coders >> normal; int teams = 0; if(normal >= min(mathematicians, coders)) { teams = min(mathematicians, coders); } else { teams = normal; mathematicians -= teams; coders -= teams; if(2*min(mathematicians, coders) <= max(mathematicians, coders)) { teams += min(mathematicians, coders); } else { teams += (mathematicians + coders)/3; } } cout << teams << "\n"; } ================================================ FILE: Contests/Educational Round 73/Programs/2048 Game.cpp ================================================ #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; long long sum = 0; while(no_of_elements--) { int element; cin >> element; if(element <= 2048) sum += element; } cout << (sum >= 2048 ? "YES\n" : "NO\n"); } int main() { int no_of_tests; cin >> no_of_tests; while(no_of_tests--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 73/Programs/Game With String.cpp ================================================ #include #include #include #include using namespace std; void solve() { int move_1, move_2; string S; cin >> move_1 >> move_2 >> S; int length = 0; vector segments; for(int i = 0; i < S.size(); i++) { if(S[i] == '.') { length++; } if(S[i] != '.' || i == S.size() - 1) { if(length != 0) { segments.push_back(length); } length = 0; } } int bob_segments = 0, normal_segments = 0, big_segments = 0; int big_segment_size = 0; for(int i = 0; i < segments.size(); i++) { if(move_2 <= segments[i] && segments[i] < move_1) { bob_segments++; } if(2*move_2 <= segments[i]) { big_segment_size = segments[i]; big_segments++; } if(move_1 <= segments[i] && segments[i] < 2*move_2) { normal_segments++; } } if(bob_segments > 0 || big_segments > 1) { cout << "NO\n"; return; } if(big_segments == 0) { cout << (normal_segments%2 == 1 ? "YES\n" : "NO\n"); return; } int winning = false; for(int part_1 = 0; big_segment_size - move_1 - part_1 >= 0; part_1++) { int part_2 = big_segment_size - move_1 - part_1; if(part_1 >= 2*move_2 || (move_2 <= part_1 && part_1 < move_1)) continue; if(part_2 >= 2*move_2 || (move_2 <= part_2 && part_2 < move_1)) continue; if( (normal_segments + (part_1 >= move_1) + (part_2 >= move_1))%2 == 0) { winning = true; break; } } cout << (winning ? "YES\n" : "NO\n"); } int main() { int no_of_tests; cin >> no_of_tests; while(no_of_tests--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 73/Programs/Knights.cpp ================================================ #include using namespace std; const int MAX_N = 105; char board[MAX_N][MAX_N]; int main() { int n; cin >> n; board[1][1] = 'B'; board[1][2] = 'W'; board[2][1] = 'W'; board[2][2] = 'B'; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(i <= 2 && j <= 2) { continue; } if(j <= 2) { board[i][j] = (board[i - 2][j - 1] == 'B' ? 'W' : 'B'); continue; } board[i][j] = (board[i - 1][j - 2] == 'B' ? 'W' : 'B'); } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { cout << board[i][j]; } cout << "\n"; } return 0; } ================================================ FILE: Contests/Educational Round 73/Programs/Make The Fence Great Again.cpp ================================================ #include #include #include using namespace std; void solve() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); vector cost(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d %I64d", &A[i], &cost[i]); } const long long oo = 1e18; vector > best(no_of_elements + 1, vector (3, 0)); best[0][0] = 0, best[0][1] = best[0][2] = 0; for(int i = 1; i <= no_of_elements; i++) { for(int no_of_adds = 0; no_of_adds <= 2; no_of_adds++) { best[i][no_of_adds] = oo; for(int no_of_previous_adds = 0; no_of_previous_adds <= 2; no_of_previous_adds++) { if(A[i] + no_of_adds != A[i - 1] + no_of_previous_adds) { best[i][no_of_adds] = min(best[i][no_of_adds], best[i - 1][no_of_previous_adds] + no_of_adds*cost[i]); } } } } long long answer = oo; for(int no_of_adds = 0; no_of_adds <= 2; no_of_adds++) { answer = min(answer, best[no_of_elements][no_of_adds]); } printf("%I64d\n", answer); } int main() { int no_of_tests; scanf("%d", &no_of_tests); while(no_of_tests--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 73/Programs/Perfect Team.cpp ================================================ #include #include using namespace std; void solve() { int mathematicians, coders, normal; cin >> mathematicians >> coders >> normal; int teams = 0; if(normal >= min(mathematicians, coders)) { teams = min(mathematicians, coders); } else { teams = normal; mathematicians -= teams; coders -= teams; if(2*min(mathematicians, coders) <= max(mathematicians, coders)) { teams += min(mathematicians, coders); } else { teams += (mathematicians + coders)/3; } } cout << teams << "\n"; } int main() { int no_of_tests; cin >> no_of_tests; while(no_of_tests--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 74/Explanations/AB String Explanation.txt ================================================ Rather than trying to count the good substrings, let us try to count the number of bad substrings. Let us use the following fact - A substring is bad if and only if it has only one character of a certain type Proof - If we have only one A in a string, it will never be good since A will not have any palindrome to match with. Now, let us prove that any string which has at least 2 of both A and B is always good. Let us look at every pair (AA) and (BB) Case 1 - AA or BB is consecutive. We have a palindrome right here Case 2 - ABBB..BBBA or BAAA...AAAB The two As or two Bs are the end points of a palindrome ---- This proves that a substring is bad if and only if either A or B occurs exactly 1 time. ----- Now, the question is - Find the number of substrings such that there is only occurence of A or B. Here is what we will do. Look at the segments of As and Bs. Suppose we have x As followed by y Bs AAAA... AB... BBB Each of the x As creates a bad substring with the first B and each of the y Bs creates a bad substring with the last A. We are counting AB twice So, the number of bad substrings here is (x + y - 1) ----- If we expand to include even one more A or one more B, we will have a good substring on our hands ! We will make an array of lengths of segments. Then, we will iterate over them and add (Segment[i] + Segment[i + 1] - 1) to our answer. ---- int main() { long long length; string S; cin >> length >> S; vector segments; for(int i = 0; i < S.size(); i++) { if(i == 0 || S[i] != S[i - 1]) { segments.push_back(1); } else { segments.back()++; } } long long bad_strings = 0; for(int i = 0; i + 1 < segments.size(); i++) { bad_strings += segments[i] + segments[i + 1] - 1; } long long total_strings = (length*(length - 1))/2; long long good_substrings = total_strings - bad_strings; cout << good_substrings; return 0; } ================================================ FILE: Contests/Educational Round 74/Explanations/Keyboard Purchase Explanation.txt ================================================ The brute force approach is to visit all permutations of the array and find the cost for each of them. However, the beautiful thing is that we do not have to do that. Just like the Travelling Salesman problem, we just have to maintain a bitmask that corresponds to which alphabets we have already chosen. Let f(m) represent a mask m, where the i-th bit is set if we have used the i-th alphabet. f(110001) is the minimum cost where we have a keyboard consisting of the first, second and sixth keys. ---- The question is, how do we transition in between states ? When we add a new character to the keyboard, how do we update the cost ? In order to do this, it appears that we need to know the relative positions of the remaining keys. Suppose we know f(110001) and want to calculate f(110011). We want to add the fourth alphabet too. It appears that we know the exact positions of the first, second and sixth alphabets. However, we do not ! We can use the beautiful idea of calculating a sum by the contribution of each of it's components rather than by evaluating each term. --- Suppose, we already have the 1st, 2nd and 6th letters and want to add the 5th letter. The 5-th letter will be added at the 4th position. Let us remove the absolute sign and try to evaluate the contribution of the 5-th letter to this mask. When we add the 5-th letter at the 4-th position, Every time we move from 1. 5-1, we will be adding (4 - p(1)) 2. 5-2, we will be adding (4 - p(2)) 3. 5-6, we will be adding (4 - p(6)) where p(i) is the position of the i-th key. There are 3 keys existing that are already placed in earlier positions. To each of them, we will be adding +4. ---- Every time we move from 4. 5-4, we will be adding (p(4) - 4) 5. 5-3, we will be adding (p(3) - 4) Since {4, 3} will be placed after 5, we will be adding -4 to the sum. ---- So, overall the 5-th letter will be contributing +4 every time it visits a key that is already placed and -4 for every time it visits a key that is not yet placed. ---- Here, is how we will transition - 1. Visit all masks from 000000 to 111111 2. For each mask, iterate over all the set bits and assume that this is the key that is added last. 3. Let m' = m without the i-th bit set 4. Calculate the cost of m' if the i-th bit is added last 5. f(m) = min{f(m), f(m') + cost} f(0) = 0 and f(111111) is the answer ------ int main() { int length, no_of_letters; string password; cin >> length >> no_of_letters >> password; memset(neighbours, 0, sizeof(neighbours)); for(int i = 0; i + 1 < length; i++) { neighbours[password[i] - 'a'][password[i + 1] - 'a']++; neighbours[password[i + 1] - 'a'][password[i] - 'a']++; } int full_mask = (1 << no_of_letters) - 1; for(int mask = 0; mask <= full_mask; mask++) { const int oo = 1e9; cost[mask] = (mask == 0 ? 0 : oo); for(int latest_letter = 0; latest_letter < no_of_letters; latest_letter++) { if(!is_bit_set(mask, latest_letter)) { continue; } int position = bit_count(mask); int cost_to_make_this_last = 0; for(int other_letter = 0; other_letter < no_of_letters; other_letter++) { if(other_letter == latest_letter) { continue; } if(is_bit_set(mask, other_letter)) { cost_to_make_this_last += position*neighbours[latest_letter][other_letter]; } else { cost_to_make_this_last -= position*neighbours[latest_letter][other_letter]; } } int mask_without_last = mask^(1 << latest_letter); cost[mask] = min(cost[mask], cost[mask_without_last] + cost_to_make_this_last); } } cout << cost[full_mask]; return 0; } ================================================ FILE: Contests/Educational Round 74/Explanations/Kill Em All Explanation.txt ================================================ The best approach is to start throwing the bombs from the rightmost position. The reason it pushes everyone closer to the origin. Let us sort the positions - X1 < X2 < ... < Xn Now, we will go through the array from finish till last. The current position of X[i] is (X[i] - E.R), where E is the number of explosions that have happened so far and R is the displacement for each blast. If (X[i] <= 0), then we do not need to throw any more missiles and we are done. The beautiful thing is that we do not need to perform a linear sweep through the entire array and update all the individual positions after each blast. If we know x blasts have occured, we can easily calculate the current position of the X[i] in O(1) time through simple subtraction. ------- Let the difference d = x - y Case 1 - Difference is 1 Then it is not possible Case 2 - Difference is prime Then we just subtract by the entire difference d Case 3 - Difference is composite d = p1^a1 p2^a2 ... pn^an d = p1 q, where q = p1^(a1 - 1) p2^a2 ... pn^an We just subtract p1 from d q times ----- void solve() { int no_of_elements, distance; cin >> no_of_elements >> distance; vector X(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> X[i]; } sort(all(X)); int explosions = 0; for(int i = no_of_elements; i >= 1; i--) { while(X[i] == X[i - 1]) { i--; } if(X[i] - explosions*distance > 0) { explosions++; } } cout << explosions << "\n"; } ================================================ FILE: Contests/Educational Round 74/Explanations/Prime Subtraction Explanation.txt ================================================ Let the difference d = x - y Case 1 - Difference is 1 Then it is not possible Case 2 - Difference is prime Then we just subtract by the entire difference d Case 3 - Difference is composite d = p1^a1 p2^a2 ... pn^an d = p1 q, where q = p1^(a1 - 1) p2^a2 ... pn^an We just subtract p1 from d q times ----- #include using namespace std; void solve() { long long x, y; cin >> x >> y; long long difference = x - y; cout << (difference == 1 ? "NO\n" : "YES\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 74/Programs/AB String.cpp ================================================ #include #include #include #include using namespace std; int main() { long long length; string S; cin >> length >> S; vector segments; for(int i = 0; i < S.size(); i++) { if(i == 0 || S[i] != S[i - 1]) { segments.push_back(1); } else { segments.back()++; } } long long bad_strings = 0; for(int i = 0; i + 1 < segments.size(); i++) { bad_strings += segments[i] + segments[i + 1] - 1; } long long total_strings = (length*(length - 1))/2; long long good_substrings = total_strings - bad_strings; cout << good_substrings; return 0; } ================================================ FILE: Contests/Educational Round 74/Programs/Keyboard Purchase.cpp ================================================ #include #include using namespace std; const int MAX_ALPHA = 21; int neighbours[MAX_ALPHA][MAX_ALPHA], cost[1 << MAX_ALPHA]; int is_bit_set(int n, int bit) { return ( (n&(1 << bit)) != 0); } int bit_count(int n) { int count = 0; while(n > 0) { count += (n%2); n /= 2; } return count; } int main() { int length, no_of_letters; string password; cin >> length >> no_of_letters >> password; memset(neighbours, 0, sizeof(neighbours)); for(int i = 0; i + 1 < length; i++) { neighbours[password[i] - 'a'][password[i + 1] - 'a']++; neighbours[password[i + 1] - 'a'][password[i] - 'a']++; } int full_mask = (1 << no_of_letters) - 1; for(int mask = 0; mask <= full_mask; mask++) { const int oo = 1e9; cost[mask] = (mask == 0 ? 0 : oo); for(int latest_letter = 0; latest_letter < no_of_letters; latest_letter++) { if(!is_bit_set(mask, latest_letter)) { continue; } int position = bit_count(mask); int cost_to_make_this_last = 0; for(int other_letter = 0; other_letter < no_of_letters; other_letter++) { if(other_letter == latest_letter) { continue; } if(is_bit_set(mask, other_letter)) { cost_to_make_this_last += position*neighbours[latest_letter][other_letter]; } else { cost_to_make_this_last -= position*neighbours[latest_letter][other_letter]; } } int mask_without_last = mask^(1 << latest_letter); cost[mask] = min(cost[mask], cost[mask_without_last] + cost_to_make_this_last); } } cout << cost[full_mask]; return 0; } ================================================ FILE: Contests/Educational Round 74/Programs/Kill Em All Explanation.txt ================================================ The best approach is to start throwing the bombs from the rightmost position. The reason it pushes everyone closer to the origin. Let us sort the positions - X1 < X2 < ... < Xn Now, we will go through the array from finish till last. The current position of X[i] is (X[i] - E.R), where E is the number of explosions that have happened so far and R is the displacement for each blast. If (X[i] <= 0), then we do not need to throw any more missiles and we are done. The beautiful thing is that we do not need to perform a linear sweep through the entire array and update all the individual positions after each blast. If we know x blasts have occured, we can easily calculate the current position of the X[i] in O(1) time through simple subtraction. ------- Let the difference d = x - y Case 1 - Difference is 1 Then it is not possible Case 2 - Difference is prime Then we just subtract by the entire difference d Case 3 - Difference is composite d = p1^a1 p2^a2 ... pn^an d = p1 q, where q = p1^(a1 - 1) p2^a2 ... pn^an We just subtract p1 from d q times ----- void solve() { int no_of_elements, distance; cin >> no_of_elements >> distance; vector X(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { cin >> X[i]; } sort(all(X)); int explosions = 0; for(int i = no_of_elements; i >= 1; i--) { while(X[i] == X[i - 1]) { i--; } if(X[i] - explosions*distance > 0) { explosions++; } } cout << explosions << "\n"; } ================================================ FILE: Contests/Educational Round 74/Programs/Prime Subtraction.cpp ================================================ #include using namespace std; void solve() { long long x, y; cin >> x >> y; long long difference = x - y; cout << (difference == 1 ? "NO\n" : "YES\n"); } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 77/Explanations/Yet Another Monster Killing Problem Explanation.txt ================================================ We will sort the heroes by their endurance. We want to know for the endurance level E, what is the maximum power we have For this, we need to have a suffix maximum Then, we will start going through the monster array. We will try to take as large a step as possible. We can use binary search to see if we can take a step of size x. If we take a step of size x, then we have to take the maximum of the monsters [i, i + x] We also have to find out whether the maximum power of any hero with endurance >= x is greater than the power in that range. ----- void solve() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; build(1, 1, no_of_elements); int no_of_heroes; cin >> no_of_heroes; vector heroes(no_of_heroes + 1); for(int i = 1; i <= no_of_heroes; i++) { cin >> heroes[i].power >> heroes[i].endurance; } sort(all(heroes), sort_by_endurance); vector max_power_for_endurance(no_of_elements + 5, 0); for(int i = 1; i <= no_of_heroes; i++) { max_power_for_endurance[heroes[i].endurance] = max(max_power_for_endurance[heroes[i].endurance], heroes[i].power); } for(int i = no_of_elements; i >= 1; i--) { max_power_for_endurance[i] = max(max_power_for_endurance[i + 1], max_power_for_endurance[i]); //cout << "Max Till " << i << " = " << max_power_for_endurance[i] << "\n"; } int days = 0; for(int i = 1; i <= no_of_elements; days++) { if(max_power_for_endurance[no_of_elements - i + 1] >= get_max(1, 1, no_of_elements, i, no_of_elements)) { days++; break; } int left = 0, right = no_of_elements - i + 1; while(right - left > 1) { //cout << "L = " << left << " R = " << right << "\n"; int mid = (left + right)/2; //cout << "Mid = " << mid << " Segment Max = [" << i << //"," << i + mid - 1 << "] = " <= get_max(1, 1, no_of_elements, i, i + mid - 1)) { left = mid; } else { right = mid; } } if(left == 0) { cout << "-1\n"; return; } i = i + left; //cout << "i = " << i << "\n"; } cout << days << "\n"; } ================================================ FILE: Contests/Educational Round 77/Programs/Dominated Subarray.cpp ================================================ #include #include using namespace std; void solve() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; const int MAX = 2e5 + 5; vector frequency(MAX, 0); int is_dominated = false; int smallest_array = MAX; int left = 1, right = 0; while(right + 1 <= no_of_elements) { while(right + 1 <= no_of_elements) { right++; frequency[A[right]]++; if(frequency[A[right]] >= 2) { break; } } while(left <= right) { if(left > no_of_elements) { break; } if(A[left] == A[right] && frequency[A[right]] == 2) { break; } frequency[A[left]]--; left++; } if(frequency[A[right]] == 2) { smallest_array = min(smallest_array, right - left + 1); } } cout << (smallest_array == MAX ? -1 : smallest_array) << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 77/Programs/Magic Stick.cpp ================================================ #include using namespace std; void solve() { long long x, y; cin >> x >> y; if(x == 1 || x == 3) { cout << (x >= y ? "Yes\n" : "No\n"); return; } else if(x == 2) { cout << (y <= 3 ? "Yes\n" : "No\n"); return; } cout << "Yes\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 77/Programs/Two Rival Students.cpp ================================================ #include using namespace std; void solve() { int n, no_of_swaps, a, b; cin >> n >> no_of_swaps >> a >> b; int distance = (max(a, b) - min(a, b)); cout << min(n - 1, no_of_swaps + distance) << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Educational Round 77/Programs/Yet Another Monster Killing Problem.cpp ================================================ #include #include #include #define all(v) (v).begin(), (v).end() #define LEFT(n) (2*n) #define RIGHT(n) (2*n + 1) using namespace std; struct hero { int power, endurance; hero() { power = 0; endurance = 0; } hero(int P, int E) { P = power; E = endurance; } }; int sort_by_endurance(const hero &A, const hero &B) { if(A.endurance == B.endurance) { return (A.power < B.power); } return (A.endurance < B.endurance); } const int MAX_N = 2e5 + 5; int max_tree[4*MAX_N], A[MAX_N]; void build(int n, int left, int right) { if(left == right) { max_tree[n] = A[right]; return; } int mid = (left + right)/2; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } int get_max(int n, int left, int right, int query_left, int query_right) { if(right < query_left || query_right < left) return 0; if(query_left <= left && right <= query_right) return max_tree[n]; int mid = (left + right)/2; int left_max = get_max(LEFT(n), left, mid, query_left, query_right); int right_max = get_max(RIGHT(n), mid + 1, right, query_left, query_right); return max(left_max, right_max); } void solve() { int no_of_elements; cin >> no_of_elements; for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; build(1, 1, no_of_elements); int no_of_heroes; cin >> no_of_heroes; vector heroes(no_of_heroes + 1); for(int i = 1; i <= no_of_heroes; i++) { cin >> heroes[i].power >> heroes[i].endurance; } sort(all(heroes), sort_by_endurance); vector max_power_for_endurance(no_of_elements + 5, 0); for(int i = 1; i <= no_of_heroes; i++) { max_power_for_endurance[heroes[i].endurance] = max(max_power_for_endurance[heroes[i].endurance], heroes[i].power); } for(int i = no_of_elements; i >= 1; i--) { max_power_for_endurance[i] = max(max_power_for_endurance[i + 1], max_power_for_endurance[i]); //cout << "Max Till " << i << " = " << max_power_for_endurance[i] << "\n"; } int days = 0; for(int i = 1; i <= no_of_elements; days++) { if(max_power_for_endurance[no_of_elements - i + 1] >= get_max(1, 1, no_of_elements, i, no_of_elements)) { days++; break; } int left = 0, right = no_of_elements - i + 1; while(right - left > 1) { //cout << "L = " << left << " R = " << right << "\n"; int mid = (left + right)/2; //cout << "Mid = " << mid << " Segment Max = [" << i << //"," << i + mid - 1 << "] = " <= get_max(1, 1, no_of_elements, i, i + mid - 1)) { left = mid; } else { right = mid; } } if(left == 0) { cout << "-1\n"; return; } i = i + left; //cout << "i = " << i << "\n"; } cout << days << "\n"; } int main() { int no_of_test_cases; cin >> no_of_test_cases; while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Explanation/Divisors.txt ================================================ Let us keep track of the exponent of every prime we encounter. We know that if N = p^n1 p2^n2 ... No of factors = (n1 + 1)(n2 + 1) ... Case 1 - The number has either 3 or 5 factors. Only perfect squares have an odd number of factors. So this means the number is of the form p^2 or p^4 So, we will check whether the number is a perfect square. If yes, then check if it is a perfect fourth power. Update the exponent accordingly. long long root = (long long) sqrt(A[i]); if(root*root == A[i]) //Perfect square. Either 3 or 5 factors { long long fourth_root = (long long) sqrt(root); if(fourth_root*fourth_root == root) //A[i] = p^4 { prime_exponent[fourth_root] += 4; } else { prime_exponent[root] += 2; //A[i] = p^2 } factorised[i] = true; } ------------------------- Case 2 - N has 4 factors Now, we know that it is not a perfect square. It is either of the form pq or p^3 since 4 = 2x2 = 4x1 Let us check all prime numbers till 10^6 Case 2a - N has a factor less than 10^6. Check if N is of the form pq or p^3 and update the exponent accordingly Case 2b - N has no factor smaller than 10^6 N has to be of the form pq, since if it was p^3 with all three factors > 10^6, then N > 10^{18} Let us check if N has any common factors with any of the other numbers by finding it's gcd. Case 2bi If it does, then we can factorise N Case 2bii Else, if N = pq and N occurs f times. The number of factors increases by (f + 1)(f + 1) ... [Since both p and q occur f times]. Note that in this case, we don't need to explicitly know the values of p and q. ------------------ long long factor_1 = 0, factor_2 = 0; for(int p = 0; p < primes.size(); p++) { if(A[i]%primes[p] == 0) { factor_1 = primes[p]; if(factor_1*factor_1*factor_1 == A[i]) // A[i] = p^3 { prime_exponent[factor_1] += 3; } else { prime_exponent[factor_1]++; prime_exponent[A[i]/factor_1]++; } factorised[i] = true; break; } } if(!factorised[i]) { for(int j = 1; j <= no_of_numbers; j++) { if(gcd(A[j], A[i]) > 1 && gcd(A[i], A[j]) < A[i]) { factor_1 = gcd(A[i], A[j]); factor_2 = A[i]/factor_1; prime_exponent[factor_1]++; prime_exponent[factor_2]++; factorised[i] = true; break; } } } int frequency = 0; if(!factorised[i]) { for(int j = 1; j <= no_of_numbers; j++) { if(A[i] == A[j]) { frequency++; factorised[j] = true; } } } if(factor_1 == 0 && factor_2 == 0) //Two new factors no_of_divisors = (no_of_divisors*(frequency + 1)*(frequency + 1))%MOD; } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Explanation/King Escape Explanation.txt ================================================ If the queen is in between the king and the target, then the king can never reach the target square as an entire row or column is blocked. However, otherwise the king can always reach his target since an entire row/column can't be blocked. There will always be squares. ---------------- int main() { int n, queen_x, queen_y, king_x, king_y, center_x, center_y; scanf("%d %d %d %d %d %d %d", &n, &queen_x, &queen_y, &king_x, &king_y, ¢er_x, ¢er_y); int queen_middle_x = in_middle(king_x, queen_x, center_x); int queen_middle_y = in_middle(king_y, queen_y, center_y); printf(queen_middle_x || queen_middle_y ? "NO\n" : "YES\n"); return 0; } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Explanation/Permutation Game Explanation.txt ================================================ Now from a given number i, we can only move to squares which have higher number. This suggests there is optimal substructure. Winner[n] = 2, since you can't move. ------------- Insight - If Player 1, makes a move from i, and places it on token j, then she becomes Player 2 for game i ---------------- From a given point, check all legal moves to see if any legal move leads to a position that is winning for player 2. If so, make that move. Else, second player will win that position. --------------------------- vector winner(no_of_elements + 1, 2); for(int i = no_of_elements; i >= 1; i--) { for(int step = i; step <= no_of_elements; step += i) { int backward_square = (position[i] - step); if(backward_square > 0 && A[backward_square] > i && winner[backward_square] == 2) { winner[position[i]] = 1; } int forward_square = (position[i] + step); if(forward_square <= no_of_elements && A[forward_square] > i && winner[forward_square] == 2) { winner[position[i]] = 1; } } } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Explanation/Square Difference Explanation.txt ================================================ The number N = A^2 - B^2 N = (A - B)(A + B) This is always composite unless one of these two terms = 1 and the other is prime. Now only A - B can be = 1, because both are positive integers. All we need to check is if A + B = 1 ---------------------------------------- void solve() { long long a, b; scanf("%I64d %I64d", &a, &b); printf(a - b == 1 && is_prime(a + b) ? "YES\n" : "NO\n"); } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Programs/Divisors.cpp ================================================ #include #include #include #include #include using namespace std; long long gcd(long long a, long long b) { if(min(a, b) == 0) return max(a, b); else return gcd(min(a, b), max(a, b)%min(a, b)); } void precompute(vector &primes, int LIMIT) { vector is_prime(LIMIT + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i < LIMIT; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] < LIMIT; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } } int main() { const int LIMIT = 2e6; vector primes; precompute(primes, LIMIT); int no_of_numbers; scanf("%d", &no_of_numbers); vector A(no_of_numbers + 1); for(int i = 1; i <= no_of_numbers; i++) scanf("%I64d", &A[i]); vector factorised(no_of_numbers + 1, false); const int MOD = 998244353; long long no_of_divisors = 1; map prime_exponent; for(int i = 1; i <= no_of_numbers; i++) { if(factorised[i]) continue; long long root = (long long) sqrt(A[i]); if(root*root == A[i]) //Perfect square. Either 3 or 5 factors { long long fourth_root = (long long) sqrt(root); if(fourth_root*fourth_root == root) //A[i] = p^4 { prime_exponent[fourth_root] += 4; } else { prime_exponent[root] += 2; //A[i] = p^2 } factorised[i] = true; } else //A[i] has 4 factors. A[i] = pq or A[i] = p^3 { long long factor_1 = 0, factor_2 = 0; for(int p = 0; p < primes.size(); p++) { if(A[i]%primes[p] == 0) { factor_1 = primes[p]; if(factor_1*factor_1*factor_1 == A[i]) // A[i] = p^3 { prime_exponent[factor_1] += 3; } else { prime_exponent[factor_1]++; prime_exponent[A[i]/factor_1]++; } factorised[i] = true; break; } } if(!factorised[i]) { for(int j = 1; j <= no_of_numbers; j++) { if(gcd(A[j], A[i]) > 1 && gcd(A[i], A[j]) < A[i]) { factor_1 = gcd(A[i], A[j]); factor_2 = A[i]/factor_1; prime_exponent[factor_1]++; prime_exponent[factor_2]++; factorised[i] = true; break; } } } int frequency = 0; if(!factorised[i]) { for(int j = 1; j <= no_of_numbers; j++) { if(A[i] == A[j]) { frequency++; factorised[j] = true; } } } if(factor_1 == 0 && factor_2 == 0) //Two new factors no_of_divisors = (no_of_divisors*(frequency + 1)*(frequency + 1))%MOD; } } for(map :: iterator it = prime_exponent.begin(); it != prime_exponent.end(); it++) { int divisors_here = it->second + 1; no_of_divisors = (no_of_divisors*divisors_here)%MOD; } printf("%I64d\n", no_of_divisors); return 0; } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Programs/King Escape.cpp ================================================ #include int in_middle(int L, int x, int R) { return ((L <= x && x <= R) || (R <= x && x <= L)); } int main() { int n, queen_x, queen_y, king_x, king_y, center_x, center_y; scanf("%d %d %d %d %d %d %d", &n, &queen_x, &queen_y, &king_x, &king_y, ¢er_x, ¢er_y); int queen_middle_x = in_middle(king_x, queen_x, center_x); int queen_middle_y = in_middle(king_y, queen_y, center_y); printf(queen_middle_x || queen_middle_y ? "NO\n" : "YES\n"); return 0; } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Programs/Permutation Game.cpp ================================================ #include #include #include using namespace std; int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector position(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) position[A[i]] = i; vector winner(no_of_elements + 1, 2); for(int i = no_of_elements; i >= 1; i--) { for(int step = i; step <= no_of_elements; step += i) { int backward_square = (position[i] - step); if(backward_square > 0 && A[backward_square] > i && winner[backward_square] == 2) { winner[position[i]] = 1; } int forward_square = (position[i] + step); if(forward_square <= no_of_elements && A[forward_square] > i && winner[forward_square] == 2) { winner[position[i]] = 1; } } } for(int i = 1; i <= no_of_elements; i++) printf("%c", winner[i] == 1 ? 'A' : 'B'); return 0; } ================================================ FILE: Contests/Lyft Level 5 Challenge 2018 - Elimination Round/Programs/Square Difference.cpp ================================================ #include int is_prime(long long n) { if(n == 1) return false; for(long long i = 2; i*i <= n; i++) if(n%i == 0) return false; return true; } void solve() { long long a, b; scanf("%I64d %I64d", &a, &b); printf(a - b == 1 && is_prime(a + b) ? "YES\n" : "NO\n"); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Mail.Ru Cup 2018 Round 1/Explanation/Appending Mex.txt ================================================ Initially, the mex = 0 At each step, Case 1 - Element > mex This is not possible as the element has to be at most the Mex. If this happens, it's a mistake. Stop. Case 2 - Element = mex Then, mex is not mex + 1 Case 3 - Element < mex This is allowed. Just move on to the next step. ---------------------------------------------------- int main() { int no_of_elements; cin >> no_of_elements; int mex_so_far = 0; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; if(element > mex_so_far) { cout << i; return 0; } else if(element == mex_so_far) { mex_so_far++; } } cout << "-1"; return 0; } ================================================ FILE: Contests/Mail.Ru Cup 2018 Round 1/Explanation/Candies Distribution.txt ================================================ We give each person (A[i] - Left[i] - Right[i]) and then perform an O(n^2) check. ------------------ #include #include using namespace std; int main() { int no_of_people; scanf("%d", &no_of_people); vector left(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &left[i]); vector right(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &right[i]); vector candies(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) candies[i] = no_of_people - left[i] - right[i]; for(int i = 1; i <= no_of_people; i++) { int left_greater = 0; for(int j = 1; j < i; j++) left_greater += (candies[j] > candies[i]); int right_greater = 0; for(int j = i + 1; j <= no_of_people; j++) right_greater += (candies[j] > candies[i]); if(left_greater != left[i] || right_greater != right[i]) { printf("NO\n"); return 0; } } printf("YES\n"); for(int i = 1; i <= no_of_people; i++) printf("%d ", candies[i]); return 0; } ================================================ FILE: Contests/Mail.Ru Cup 2018 Round 1/Explanation/Changing the Array Explanation.txt ================================================ Now XOR(A[L, ... , R]) = XOR(XOR(A[1, ... , R]), XOR(A[1, ... , L - 1])) We will try to be greedy and at each point try to maximise the number of different xor prefixes. ----- int main() { int no_of_elements, k; cin >> no_of_elements >> k; int prefix_xor = 0; map prefix_xor_frequency; prefix_xor_frequency[0] = 1; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; int option_1 = prefix_xor^element; int option_2 = prefix_xor^complement(element, k); if(prefix_xor_frequency[option_1] < prefix_xor_frequency[option_2]) prefix_xor = option_1; else prefix_xor = option_2; prefix_xor_frequency[prefix_xor]++; } LL bad_segments = 0; for(map :: iterator it = prefix_xor_frequency.begin(); it != prefix_xor_frequency.end(); it++) { bad_segments += choose_2(it->second); } LL total_segments = choose_2(no_of_elements) + no_of_elements; LL good_segments = total_segments - bad_segments; cout << good_segments; return 0; } ================================================ FILE: Contests/Mail.Ru Cup 2018 Round 1/Programs/Appending Mex.cpp ================================================ #include #include #include using namespace std; #define all(v) (v).begin(), (v).end() int main() { int no_of_elements; cin >> no_of_elements; int mex_so_far = 0; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; if(element > mex_so_far) { cout << i; return 0; } else if(element == mex_so_far) { mex_so_far++; } } cout << "-1"; return 0; } ================================================ FILE: Contests/Mail.Ru Cup 2018 Round 1/Programs/Candy Distribution.cpp ================================================ #include #include using namespace std; int main() { int no_of_people; scanf("%d", &no_of_people); vector left(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &left[i]); vector right(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &right[i]); vector candies(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) candies[i] = no_of_people - left[i] - right[i]; for(int i = 1; i <= no_of_people; i++) { int left_greater = 0; for(int j = 1; j < i; j++) left_greater += (candies[j] > candies[i]); int right_greater = 0; for(int j = i + 1; j <= no_of_people; j++) right_greater += (candies[j] > candies[i]); if(left_greater != left[i] || right_greater != right[i]) { printf("NO\n"); return 0; } } printf("YES\n"); for(int i = 1; i <= no_of_people; i++) printf("%d ", candies[i]); return 0; } ================================================ FILE: Contests/Mail.Ru Cup 2018 Round 1/Programs/Changing the Array.cpp ================================================ #include #include using namespace std; typedef long long LL; LL choose_2(LL n) { return (n*(n - 1))/2; } int all_ones(int n) { return ((1 << n) - 1); } int complement(int n, int k) { return (all_ones(k) - n); } int main() { int no_of_elements, k; cin >> no_of_elements >> k; int prefix_xor = 0; map prefix_xor_frequency; prefix_xor_frequency[0] = 1; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; int option_1 = prefix_xor^element; int option_2 = prefix_xor^complement(element, k); if(prefix_xor_frequency[option_1] < prefix_xor_frequency[option_2]) prefix_xor = option_1; else prefix_xor = option_2; prefix_xor_frequency[prefix_xor]++; } LL bad_segments = 0; for(map :: iterator it = prefix_xor_frequency.begin(); it != prefix_xor_frequency.end(); it++) { bad_segments += choose_2(it->second); } LL total_segments = choose_2(no_of_elements) + no_of_elements; LL good_segments = total_segments - bad_segments; cout << good_segments; return 0; } ================================================ FILE: Contests/Manthan 2018/Explanation/Equalize Explanation.txt ================================================ Be greedy and swap only when necessary and possible. ----------- int main() { int length; string A, B; cin >> length >> A >> B; int no_of_changes = 0; for(int i = 0; i < length; i++) { if(A[i] != B[i]) { if(i + 1 < length && A[i + 1] != B[i + 1] && A[i] != A[i + 1]) //swap { i++; } no_of_changes++; } } cout << no_of_changes; return 0; } ================================================ FILE: Contests/Manthan 2018/Explanation/Packets Explanation.txt ================================================ The answer is the number of bits in n. int main() { int n; cin >> n; int no_of_bits = count_bits(n); cout << no_of_bits; return 0; } ================================================ FILE: Contests/Manthan 2018/Explanation/Reach Median Explanation.txt ================================================ The middle element must be = S Every element before the middle must be <= S Every element after the middle must be >= S ------------------------------------------------- int middle = no_of_elements/2 + 1; long long no_of_operations = 0; for(int i = 1; i <= no_of_elements; i++) { if(i < middle) { if(A[i] > median_target) { no_of_operations += A[i] - median_target; } } else if(i == middle) { no_of_operations += abs(A[i] - median_target); } else if(i > middle) { if(A[i] < median_target) { no_of_operations += median_target - A[i]; } } } ================================================ FILE: Contests/Manthan 2018/Explanation/Valid BFS Explanation.txt ================================================ Blog Link - http://qr.ae/TUN58X Maintain an adjacency set and then try to simulate the process. ------------------------------------------------------------------------ set tree[MAX_N]; int main() { int no_of_vertices; scanf("%d", &no_of_vertices); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges;i++) { int u, v; scanf("%d %d", &u, &v); tree[u].insert(v); tree[v].insert(u); } vector visit_order(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) scanf("%d", &visit_order[i]); int last = 1; int valid_visit_order = (visit_order[1] == 1); for(int i = 2; i <= no_of_vertices; i++) { while(last < i && tree[visit_order[last]].size() == 0) last++; int head = visit_order[last], v = visit_order[i]; if(tree[head].count(v) == 1) { int parent = head, child = v; tree[parent].erase(child); tree[child].erase(parent); } else { valid_visit_order = false; break; } } printf(valid_visit_order ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/Manthan 2018/Programs/Equalize.cpp ================================================ #include #include #include using namespace std; int main() { int length; string A, B; cin >> length >> A >> B; int no_of_changes = 0; for(int i = 0; i < length; i++) { if(A[i] != B[i]) { if(i + 1 < length && A[i + 1] != B[i + 1]) //swap { i++; } no_of_changes++; } } cout << no_of_changes; return 0; } ================================================ FILE: Contests/Manthan 2018/Programs/Packets.cpp ================================================ #include using namespace std; int count_bits(int n) { int total = 0; while(n) { n = n >> 1; total++; } return total; } int main() { int n; cin >> n; int no_of_bits = count_bits(n); cout << no_of_bits; return 0; } ================================================ FILE: Contests/Manthan 2018/Programs/Reach Median.cpp ================================================ #include #include #include #include #include #include #define all(v) (v).begin() + 1, (v).end() using namespace std; int main() { int no_of_elements, median_target; cin >> no_of_elements >> median_target; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; sort(all(A)); int middle = no_of_elements/2 + 1; long long no_of_operations = 0; for(int i = 1; i <= no_of_elements; i++) { if(i < middle) { no_of_operations += max(0, A[i] - median_target); } else if(i == middle) { no_of_operations += abs(A[i] - median_target); } else if(i > middle) { no_of_operations += max(0, median_target - A[i]); } } cout << no_of_operations; return 0; } ================================================ FILE: Contests/Manthan 2018/Programs/Valid BFS.cpp ================================================ #include #include #include using namespace std; const int MAX_N = 2e5 + 15; set tree[MAX_N]; int main() { int no_of_vertices; scanf("%d", &no_of_vertices); int no_of_edges = no_of_vertices - 1; for(int i = 1; i <= no_of_edges;i++) { int u, v; scanf("%d %d", &u, &v); tree[u].insert(v); tree[v].insert(u); } vector visit_order(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices; i++) scanf("%d", &visit_order[i]); int last = 1; int valid_visit_order = (visit_order[1] == 1); for(int i = 2; i <= no_of_vertices; i++) { while(last < i && tree[visit_order[last]].size() == 0) last++; int head = visit_order[last], v = visit_order[i]; if(tree[head].count(v) == 1) { int parent = head, child = v; tree[parent].erase(child); tree[child].erase(parent); } else if(tree[head].count(v) == 0) { valid_visit_order = false; break; } } printf(valid_visit_order ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Contests/Moscow Team Olympiad 2018/Explanation/Equations of Mathematical Magic Explanation.txt ================================================ We want all x that satisfy the following equation - a - x = a^x Let us look at a from the last bit onwards Suppose the last bit of a is 1, then the last bit of x can 1 1 - 1 = 1^1 = 0 It can also be 0 1 - 0 = 1^0 = 1 What if the last bit of a is 0 ? Then last bit of x can be 0 0 - 0 = 0^0 = 0 Suppose the last bit of a is 0 and the last bit of x is 1. What happens ? Let us look at the leftmost 1 in a. All the bits till this leftmost 1 are toggled. For example if fifth bit is the leftmost 1 and after that there are 4 0s. If we subtract 1 from the first bit, the the other four bits in A are toggled. Now whatever the value of x is for bits 2, 3, 4, 5 ... A - x cannot be equal to A^x because the bits of A are different here now. --------------- Hence, there are two possibilites for every 1 and only one possibility for every 0. --------------------------------------------- void solve() { int n; scanf("%d", &n); long long no_of_ways = 1; while(n) { if(n%2 == 1) no_of_ways = no_of_ways << 1; n = n >> 1; } printf("%I64d\n", no_of_ways); } ================================================ FILE: Contests/Moscow Team Olympiad 2018/Explanation/Make a Triangle Explanation.txt ================================================ Let the sides be a < b < c The triangle is valid if c < a + b Now, if c < a + b, Then since a < c and b < c the other two sides satisfy the inequality. ------------------------------------- We just change the smallest side, the other two sides will obey the inequality. ----------------------- #include #include #include using namespace std; int main() { vector A(3); cin >> A[0] >> A[1] >> A[2]; sort(A.begin(), A.end()); int minutes = 0; if(A[0] + A[1] <= A[2]) { minutes += (A[2] + 1 - A[1] - A[0]); } cout << minutes; return 0; } ================================================ FILE: Contests/Moscow Team Olympiad 2018/Explanation/Oh Those Palindromes Explanation.txt ================================================ It is always optimal to print chunks of each character together. (One way of doing this is by simply sorting the string.) ----------- Why is it optimal ? Every palindrome will have at least two characters. Suppose a certain character occurs f times. Then it can be involved in at most C(f, 2) + C(f, 1) = f(f + 1)/2 palindromes. We get C(f, 2) whenever this character is the end points of any palindrome We get C(f, 1) whenever we have a 1-character palindrome. When they are all printed together there will be f(f + 1)/2 palindromes. Palindrome of length 1, 2, 3, ... , f ----------------------------- int main() { string S; int length; cin >> length >> S; sort(S, S + length); printf("%s\n", S); return 0; } ================================================ FILE: Contests/Moscow Team Olympiad 2018/Programs/Equations of Mathematical Magic.cpp ================================================ #include void solve() { int n; scanf("%d", &n); long long no_of_ways = 1; while(n) { if(n%2 == 1) no_of_ways = no_of_ways << 1; n = n >> 1; } printf("%I64d\n", no_of_ways); } int main() { int no_of_test_cases; scanf("%d", &no_of_test_cases); while(no_of_test_cases--) solve(); return 0; } ================================================ FILE: Contests/Moscow Team Olympiad 2018/Programs/Make a Triangle.cpp ================================================ #include #include #include using namespace std; int main() { vector A(3); cin >> A[0] >> A[1] >> A[2]; sort(A.begin(), A.end()); int minutes = 0; if(A[0] + A[1] <= A[2]) { minutes += (A[2] + 1 - A[1] - A[0]); } cout << minutes; return 0; } ================================================ FILE: Contests/Moscow Team Olympiad 2018/Programs/Oh Those Palindromes.cpp ================================================ #include #include #include #include using namespace std; int main() { string S; int length; cin >> length >> S; sort(S, S + length); printf("%s\n", S); return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Explanation/In Search of An Easy Problem Explanation.txt ================================================ If any one is hard, then stop. ---------------------------------- int main() { int no_of_opinions; scanf("%d", &no_of_opinions); int is_hard = false; while(no_of_opinions--) { const int HARD = 1; int opinion; scanf("%d", &opinion); if(opinion == HARD) is_hard = true; } printf(is_hard ? "HARD\n" : "EASY\n"); return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Explanation/Vasya and Cornfield.txt ================================================ To check if a point lies inside a rectangle, we have to ensure the points lie on the right side of each of the four lines. ------------------------------- int main() { int n, d; scanf("%d %d", &n, &d); int no_of_grasshoppers; scanf("%d", &no_of_grasshoppers); while(no_of_grasshoppers--) { int x, y; scanf("%d %d", &x, &y); printf(-d <= x - y && x - y <= d && d <= x + y && x + y <= 2*n - d ? "YES\n" : "NO\n"); } return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Explanation/Vasya and Golden Ticket Explanation.txt ================================================ Now if the question was asking if there is some way to break it into 2 segments of equal sums, it would be a pretty easy question ... we'd just need to look for a prefix who's sum = S/2. ------------------------- Let us break it down into a smaller question ... Given K, how do we check if A can be divided into K segments each of who's sums are equal. If the sum of the array is S, then the sum of each segment should be S/K. (S should be divisible by K.) ------------------------------------- That means we must search for some prefix who's sum = S/k. Then remove that prefix, and once again look for a prefix who's sum = S/k. We keep doing this ... If at any point our sum exceeds S/k, then it means we can't divide the array into segments who's sum is K because the current segment will always have sum > k. ---------------------------------- int possible_to_divide(vector &A, int target_no_of_parts) { int sum = 0; for(int i = 1; i < A.size(); i++) sum += A[i]; int target_part_sum = sum/target_no_of_parts; int parts_that_are_made = 0; for(int current_part_sum = 0, i = 1; i < A.size(); i++) { current_part_sum += A[i]; if(current_part_sum == target_part_sum) { parts_that_are_made++; current_part_sum = 0; } if(current_part_sum > target_part_sum) return false; } return (parts_that_are_made == target_no_of_parts); } ----------------------------- So first find Sum S, and then iterate over all divisors of S. ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Explanation/Vasya and Good Sequences Explanation.txt ================================================ Fact - If the number of 1's in the range is odd, or if any number has more than half the number of 1s in the range, it is not possible. Proof - If there are an odd number of 1s clearly, there will always be at least one 1 left over. If one number has more than half the number of 1s, then there will always be some 1s in it that are left over. ----------------------------------------------------- Fact - This condition is necessary, but it is also sufficient. Proof - Let us place exactly two 1s in each bit position. For example, the first position from the left has exactly 2 ones. The second position has exactly 2 ones. The third has exactly 2 ones. And so on. ----------------------- How do we do this ? First we count all ranges, where the sum is even. long long good_sequences = 0; long long odd_sums = 0; long long even_sums = 1; for(int i = 1; i <= no_of_elements; i++) { if(sum[i]%2 == 0) { good_sequences += even_sums; even_sums++; } else { good_sequences += odd_sums; odd_sums++; } } --------------------------------- Now, we have to discount the number of ranges where ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Explanation/Vasya and Triangle Explanation.txt ================================================ Area = 1/2 | 1 1 1 | | x1 x2 x3 | | y1 y2 y3 | The determinant is an integer since all the lattice points are integers. So, we can say that 2*Area = Integer. ------------------------------ Now, 2*Area = 2(mn)/k = (2mn)/k This means that k must divide 2mn. --------------------------------------- If k does not divide 2mn, then no triangle is possible. --------------------------------- 1. Cancel all common factors of k and m. 2. Cancel all common factors of k and n. This means k should be either = 1 or = 2 k = 1, if (mn) is a multiple of k k = 2, if (2mn) is a multiple of k If k is any value greater than 2, then it is not possible to have such a triangle. -------------------------------------- Now, how do we construct this triangle ? Let g1 = gcd(k, m) and g2 = gcd(k, n) m' = m/g1 ... n' = n/g2 k' = k/(g1g2) If we have a triangle with vertices (0, 0) (m', 0), (0, n') Area = (m'n')/(2) = (mn)/2(g1g2) Now, --------------------- Case 1 - if K = 1 after dividing by g1 g2, then it means K = g1 g2. Area = mn/2k ... In this case, we multiply numerator and denominator by 2. K was initially at least 2, so if K is 1 now, then it means either the m' or n' has been divided by some number >= 2. So, we pick (0, 0) (2m', 0) (0, n') or (0, 0), (m', 0), (0, 2n') whichever is within the limits. --------------------------------- Case 2 - K = 2 after dividing by g1g2 then it means K = 2g1g2 Then area = (mn)/k .. .There is nothing further to do. ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Programs/In Search of An Easy Problem.cpp ================================================ #include int main() { int no_of_opinions; scanf("%d", &no_of_opinions); int is_hard = false; while(no_of_opinions--) { const int HARD = 1; int opinion; scanf("%d", &opinion); if(opinion == HARD) is_hard = true; } printf(is_hard ? "HARD\n" : "EASY\n"); return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Programs/Vasya and Cornfield.cpp ================================================ #include int main() { int n, d; scanf("%d %d", &n, &d); int no_of_grasshoppers; scanf("%d", &no_of_grasshoppers); while(no_of_grasshoppers--) { int x, y; scanf("%d %d", &x, &y); printf(-d <= x - y && x - y <= d && d <= x + y && x + y <= 2*n - d ? "YES\n" : "NO\n"); } return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Programs/Vasya and Golden Ticket.cpp ================================================ #include #include using namespace std; int possible_to_divide(vector &A, int target_no_of_parts) { int sum = 0; for(int i = 1; i < A.size(); i++) sum += A[i]; int target_part_sum = sum/target_no_of_parts; int parts_that_are_made = 0; for(int current_part_sum = 0, i = 1; i < A.size(); i++) { current_part_sum += A[i]; if(current_part_sum == target_part_sum) { parts_that_are_made++; current_part_sum = 0; } if(current_part_sum > target_part_sum) return false; } return (parts_that_are_made == target_no_of_parts); } int main() { int no_of_digits; scanf("%d", &no_of_digits); vector A(no_of_digits + 1); for(int i = 1; i <= no_of_digits; i++) scanf("%1d", &A[i]); int sum = 0; for(int i = 1; i <= no_of_digits; i++) sum += A[i]; int division_possible = false; for(int i = 2; i <= no_of_digits; i++) { if(sum%i == 0) { if(possible_to_divide(A, i)) { division_possible = true; break; } } } printf(division_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Programs/Vasya and Good Sequences.cpp ================================================ #include #include #include using namespace std; int population_count(long long n) { int no_of_1s = 0; while(n) { if(n%2 == 1) no_of_1s++; n = n >> 1; } return no_of_1s; } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); A[i] = population_count(A[i]); } vector sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) sum[i] = sum[i - 1] + A[i]; long long good_sequences = 0; long long odd_sums = 0; long long even_sums = 1; for(int i = 1; i <= no_of_elements; i++) { if(sum[i]%2 == 0) { good_sequences += even_sums; even_sums++; } else { good_sequences += odd_sums; odd_sums++; } } long long bad_sequences = 0; for(int left = 1; left <= no_of_elements; left++) { const int MAX_RANGE = 128; long long maximum_element = A[left]; for(int right = left; right <= min(no_of_elements, left + MAX_RANGE); right++) { int sum_here = sum[right] - sum[left - 1]; maximum_element = max(maximum_element, A[right]); if(sum_here%2 == 0 && 2*maximum_element > sum_here) { bad_sequences++; } } } good_sequences -= bad_sequences; printf("%I64d\n", good_sequences); return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 1/Programs/Vasya and Triangle.cpp ================================================ #include #define max(a, b) (a > b ? a : b) #define min(a, b) (a < b ? a : b) typedef long long LL; LL gcd(LL a, LL b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } int main() { LL x_limit, y_limit, k; scanf("%I64d %I64d %I64d", &x_limit, &y_limit, &k); //2*Area = (2mn)/k ... K should divide 2mn LL g = gcd(x_limit, k); LL x = x_limit/g; k /= g; g = gcd(y_limit, k); LL y = y_limit/g; k /= g; if(k == 1) { if(2*x <= x_limit) x = 2*x; else y = 2*y; } if(k <= 2) { printf("YES\n"); printf("0 0\n%I64d 0\n0 %I64d\n", x, y); } else { printf("NO\n"); } return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 2/Explanation/Curiosity Has No Limits.txt ================================================ There are only four values each can take. Let us first set T[n] = 0, Then check if there's any number existing such that x|T[n] = A[n - 1] and x&T[n - 1] = B[n - 1] If there is, check if there's any possibile value for T[n - 2] and so on. Here is a recurisve way of doing it - ----------------- int is_possible(vector &T, vector &A, vector &B, int n) { if(n == 0) return true; for(int ele = 0; ele <= 3; ele++) { T[n] = ele; if((T[n]|T[n + 1]) == A[n] && (T[n]&T[n + 1]) == B[n]) { if(is_possible(T, A, B, n - 1)) return true; } } return false; } ------------------------------ ================================================ FILE: Contests/Technocup 2019 Elimination Round 2/Explanation/Golden Plate.txt ================================================ Let us make few observations. 1. If the golden line has r rows and c columns. The total perimeter = 2(r + c) - 4 (We subtract 4 because 4 squares are counted twice.) 2. For every ring, Both r and c decrease by 4. (Decrease by 2 on either side.) --------------------- #include int main() { int rows, columns, k; scanf("%d %d %d", &rows, &columns, &k); int total_perimeter = 0; int r = rows, c = columns; for(int i = 1; i <= k; i++) { int perimeter = 2*r + 2*c - 4; total_perimeter += perimeter; r -= 4; c -= 4; } printf("%d\n", total_perimeter); return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 2/Programs/Curiosity Has No Limits.cpp ================================================ #include #include using namespace std; int is_possible(vector &T, vector &A, vector &B, int n) { if(n == 0) return true; for(int ele = 0; ele <= 3; ele++) { T[n] = ele; if((T[n]|T[n + 1]) == A[n] && (T[n]&T[n + 1]) == B[n]) { if(is_possible(T, A, B, n - 1)) return true; } } return false; } int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i < no_of_elements; i++) cin >> A[i]; vector B(no_of_elements + 1); for(int i = 1; i < no_of_elements; i++) cin >> B[i]; vector T(no_of_elements + 1); for(int i = 0; i <= 3; i++) { T[no_of_elements] = i; if(is_possible(T, A, B, no_of_elements - 1)) { cout << "YES\n"; for(int i = 1; i <= no_of_elements; i++) cout << T[i] << " "; return 0; } } cout << "NO\n"; return 0; } ================================================ FILE: Contests/Technocup 2019 Elimination Round 2/Programs/Golden Plate.cpp ================================================ #include int main() { int rows, columns, k; scanf("%d %d %d", &rows, &columns, &k); int total_perimeter = 0; int r = rows, c = columns; for(int i = 1; i <= k; i++) { int perimeter = 2*r + 2*c - 4; total_perimeter += perimeter; r -= 4; c -= 4; } printf("%d\n", total_perimeter); return 0; } ================================================ FILE: Explanations/Explanations - 1/Boy or Girl - Explanation.txt ================================================ Those days, many boys use beautiful girls' photos as avatars in forums. So it is pretty hard to tell the gender of a user at the first glance. Last year, our hero went to a forum and had a nice chat with a beauty (he thought so). After that they talked very often and eventually they became a couple in the network. But yesterday, he came to see "her" in the real world and found out "she" is actually a very strong man! Our hero is very sad and he is too tired to love again now. So he came up with a way to recognize users' genders by their user names. This is his method: if the number of distinct characters in one's user name is odd, then he is a male, otherwise she is a female. You are given the string that denotes the user name, please help our hero to determine the gender of this user by his method. Input The first line contains a non-empty string, that contains only lowercase English letters the user name. This string contains at most 100 letters. Output If it is a female by our hero's method, print "CHAT WITH HER!" (without the quotes), otherwise, print "IGNORE HIM!" (without the quotes). ------------------------------------------------------------------------------ Build another string called distinct_letters and add every character of username only one time. Count the number of characters of distinct_letters. Check the parity and print correct message. ================================================ FILE: Explanations/Explanations - 1/Translation - Explanation.txt ================================================ The translation from the Berland language into the Birland language is not an easy task. Those languages are very similar: a berlandish word differs from a birlandish word with the same meaning a little: it is spelled (and pronounced) reversely. For example, a Berlandish word code corresponds to a Birlandish word edoc. However, it's easy to make a mistake during the translation. Vasya translated word s from Berlandish into Birlandish as t. Help him: find out if he translated the word correctly. Input The first line contains word s, the second line contains word t. The words consist of lowercase Latin letters. The input data do not consist unnecessary spaces. The words are not empty and their lengths do not exceed 100 symbols. Output If the word t is a word s, written reversely, print YES, otherwise print NO. ---------------------------------------------------------------------------- Pretty Straightforward. Just check if a string is the reverse of another. ================================================ FILE: Explanations/Explanations - 10/A and B Compilation Errors Explanation.txt ================================================ B loves to debug his code. But before he runs the solution and starts debugging, he has to first compile the code. Initially, the compiler displayed n compilation errors, each of them is represented as a positive integer. After some effort, B managed to fix some mistake and then another one mistake. However, despite the fact that B is sure that he corrected the two errors, he can not understand exactly what compilation errors disappeared the compiler of the language which B uses shows errors in the new order every time! B is sure that unlike many other programming languages, compilation errors for his programming language do not depend on each other, that is, if you correct one error, the set of other error does not change. Can you help B find out exactly what two errors he corrected? Input The first line of the input contains integer n (3?=?n?=?105) the initial number of compilation errors. The second line contains n space-separated integers a1,?a2,?...,?an (1?=?ai?=?109) the errors the compiler displayed for the first time. The third line contains n?-?1 space-separated integers b1,?b2,?...,?bn?-?1 the errors displayed at the second compilation. It is guaranteed that the sequence in the third line contains all numbers of the second string except for exactly one. The fourth line contains n?-?2 space-separated integers ?1,??2,?...,??n?-?2 the errors displayed at the third compilation. It is guaranteed that the sequence in the fourth line contains all numbers of the third line except for exactly one. Output Print two numbers on a single line: the numbers of the compilation errors that disappeared after B made the first and the second correction, respectively. -------------------------------------------------------------- It's a classic riddle. Alice tells Bob numbers from 1 to 100 in a random order with one number missing. How does Bob find the missing number ? He keeps track of the sum and subtracts whatever Alice tells him. It's that simple. But, seeing the data structure tag on this question, I was trying to solve it with maps. It's doable but code gets unnecissarily complex. int sum_1 = 0; for(int i = 1; i <= no_of_errors; i++) { scanf("%d", &error_i); sum_1 += error_i; } //Second List int sum_2 = 0; for(int i = 1; i <= no_of_errors - 1; i++) { scanf("%d", &error_i); sum_2 += error_i; } int sum_3 = 0; for(int i = 1; i <= no_of_errors - 2; i++) { scanf("%d", &error_i); sum_3 += error_i; } printf("%d \n%d\n", sum_1-sum_2, sum_2 - sum_3); ================================================ FILE: Explanations/Explanations - 10/Amr and Music Explanation.txt ================================================ Had to use vector of pairs for this one. Learnt to insert a pair into a vector. Use make pair. Sort by defualt sorts the first by the first parameter. You can write a custom sort if you want a different sort. bool custom_sort(const data_type &a, const data_type &b) ... And define how you want the sort to work and pass this function name to the STL sort first and second can be used to access elements of a vector pair just like a map. ----------------------------------------------- typedef pair int_pair; int main() { int no_of_instruments, no_of_days, day_i; scanf("%d %d", &no_of_instruments, &no_of_days); vector < int_pair > no_of_days_to_learn; for(int i = 0; i < no_of_instruments; i++) { scanf("%d", &day_i); no_of_days_to_learn.push_back( make_pair(day_i, i + 1)); } sort(all(no_of_days_to_learn)); vector learnt_instrument; for(int i = 0; i < no_of_instruments && no_of_days > 0; i++) { no_of_days -= no_of_days_to_learn[i].first; if(no_of_days >= 0) learnt_instrument.push_back(no_of_days_to_learn[i].second); } printf("%u\n", learnt_instrument.size()); for(unsigned int i = 0; i < learnt_instrument.size(); i++) printf("%d ", learnt_instrument[i]); return 0; } ================================================ FILE: Explanations/Explanations - 10/Arrival of General Explanation.txt ================================================ A Ministry for Defense sent a general to inspect the Super Secret Military Squad under the command of the Colonel SuperDuper. Having learned the news, the colonel ordered to all n squad soldiers to line up on the parade ground. By the military charter the soldiers should stand in the order of non-increasing of their height. But as there's virtually no time to do that, the soldiers lined up in the arbitrary order. However, the general is rather short-sighted and he thinks that the soldiers lined up correctly if the first soldier in the line has the maximum height and the last soldier has the minimum height. Please note that the way other solders are positioned does not matter, including the case when there are several soldiers whose height is maximum or minimum. Only the heights of the first and the last soldier are important. For example, the general considers the sequence of heights (4, 3, 4, 2, 1, 1) correct and the sequence (4, 3, 1, 2, 2) wrong. Within one second the colonel can swap any two neighboring soldiers. Help him count the minimum time needed to form a line-up which the general will consider correct. ----------------------------------------------------- We need to know the position of the leftmost tallest person and rightmost shortest person (Because there can be multiple maxima and minima). Normally, the answer is (leftmost - 1) + (n - rightmost) However, we need to consider the case where leftmost and rightmost need to go past one another to reach the other end. The case where leftmost > rightmost Suppose tallest is a, shortest is b. i i i b i a i i While getting a to the beginning, we need to change b's position a i i i b i i i Now b has to move one place less than he originally had to. ----------------------------------------- int main() { int no_of_soldiers; scanf("%d", &no_of_soldiers); const int oo = 100 + 1; int tallest_soldier = 0, shortest_soldier = oo; int leftmost_tallest = -1, rightmost_shortest = -1; for(int i = 1; i <= no_of_soldiers; i++) { int height_i; scanf("%d", &height_i); if(height_i > tallest_soldier) { tallest_soldier = height_i; leftmost_tallest = i; } if(height_i <= shortest_soldier) { shortest_soldier = height_i; rightmost_shortest = i; } } int no_of_swaps = 0; if(leftmost_tallest < rightmost_shortest) no_of_swaps = (leftmost_tallest - 1) + (no_of_soldiers - rightmost_shortest); else no_of_swaps = (leftmost_tallest - 1) + (no_of_soldiers - rightmost_shortest) - 1; printf("%d\n", no_of_swaps); return 0; } ================================================ FILE: Explanations/Explanations - 10/Bear and Game Explanation.txt ================================================ Bear Limak likes watching sports on TV. He is going to watch a game today. The game lasts 90 minutes and there are no breaks. Each minute can be either interesting or boring. If 15 consecutive minutes are boring then Limak immediately turns TV off. --------------------------------------- Missed a case which was not explained in the question clearly. If he doesn't find any gap of boring minutes greater than 15 minutes, then the bear watches 90 minutes. The number of boring minutes in between two interesting moments x and y are all the moments from x + 1 to y - 1 ... This is given by (y- 1) - x [Inclusive of y - 1, exclusive of x]. I put in 2 auxilliary variables .. The 0-th interesting minute is 0 and the last interesting minute is 90. (Even if it is boring). --------------------------------------- int main() { int no_of_interesting_minutes, interesting_minute_i, tv_on_minutes = 0; scanf("%d", &no_of_interesting_minutes); bool tv_on = true; vector interesting_minute; interesting_minute.push_back(0); for(int i = 1; i <= no_of_interesting_minutes; i++) { scanf("%d", &interesting_minute_i); interesting_minute.push_back(interesting_minute_i); } if(interesting_minute.back() != 90) interesting_minute.push_back(90); for(unsigned int i = 1; i < interesting_minute.size() ; i++) { if(tv_on) { int boring_interval = (interesting_minute[i] - 1) - interesting_minute[i - 1]; if(boring_interval >= 15) { tv_on_minutes += 15; tv_on = false; } else { tv_on_minutes += boring_interval + 1; //Watch the boring interval + the interesting minute } } } printf("%d\n", tv_on_minutes); return 0; } ================================================ FILE: Explanations/Explanations - 10/Beautiful Year Explanation.txt ================================================ ------------------------------- Given a year, find the next year that has all it's digits distinct. Used a map first but then realised it's too much since there are only 10 digits. Got a bit hard to read so I re-wrote it with a frequency vector. ------------------------------------------------------ int is_beautiful(int year) { vector digit_frequency(10, 0); while(year > 0) { digit_frequency[year%10]++; year = year/10; } for(int i = 0; i < 10; i++) if(digit_frequency[i] > 1) return false; return true; } int main() { int year; scanf("%d", &year); int beautiful_year; for(beautiful_year = year + 1; ; beautiful_year++) if(is_beautiful(beautiful_year)) break; printf("%d\n", beautiful_year); return 0; } ================================================ FILE: Explanations/Explanations - 10/Black Square Explanation.txt ================================================ Polycarp has a checkered sheet of paper of size n??m. Polycarp painted some of cells with black, the others remained white. Inspired by Malevich's "Black Square", Polycarp wants to paint minimum possible number of white cells with black so that all black cells form a square. You are to determine the minimum possible number of cells needed to be painted black so that the black cells form a black square with sides parallel to the painting's sides. All the cells that do not belong to the square should be white. The square's side should have positive length. Input The first line contains two integers n and m (1?=?n,?m?=?100) the sizes of the sheet. The next n lines contain m letters 'B' or 'W' each the description of initial cells' colors. If a letter is 'B', then the corresponding cell is painted black, otherwise it is painted white. Output Print the minimum number of cells needed to be painted black so that the black cells form a black square with sides parallel to the painting's sides. All the cells that do not belong to the square should be white. If it is impossible, print -1. ---------------------------------------------------------- Keep track of the rightmost, leftmost, topmost, downmost black square the number of black squares. The square of all black squares must contain these extreme black squares. Also, all other black square must be inside this. Subtract the number of blocks in this square with the number of black squares. A square is only possible if the side of this side is smaller than the minimum of the rectangle side.int main() { int no_of_rows, no_of_columns; scanf("%d %d", &no_of_rows, &no_of_columns); char rectangle[MAX_LENGTH][MAX_LENGTH]; int no_of_black_squares = 0, left_most = no_of_columns + 1, right_most = -1, highest = -1, lowest = no_of_rows + 1; for(int i = 0; i < no_of_rows; i++) { scanf("%s", rectangle[i]); for(int j = 0; j < no_of_columns; j++) { if(rectangle[i][j] == 'B') { no_of_black_squares ++; left_most = min(left_most, j); right_most = max(right_most, j); highest = max(highest, i); lowest = min(lowest, i); } } } int square_rows = highest - lowest + 1, square_columns = right_most - left_most + 1; int square_side = max(square_columns, square_rows); int repainted = -1; if(no_of_black_squares == 0) { repainted = 1; } else if(square_side <= min(no_of_rows, no_of_columns)) { repainted = square_side*square_side - no_of_black_squares; } printf("%d\n", repainted); return 0; } ---------------------------------------- ================================================ FILE: Explanations/Explanations - 10/Difference Row.txt ================================================ You want to arrange n integers a1, a2, ..., an in some order in a row. Let's define the value of an arrangement as the sum of differences between all pairs of adjacent integers. More formally, let's denote some arrangement as a sequence of integers x1, x2, ..., xn, where sequence x is a permutation of sequence a. The value of such an arrangement is (x1 - x2) + (x2 - x3) + ... + (xn - 1 - xn). Find the largest possible value of an arrangement. Then, output the lexicographically smallest sequence x that corresponds to an arrangement of the largest possible value. ----------------------------------------------- The first observation is that the value of an arrangement telescopes to x1 - xn. To maximise this, we place the biggest element at x1 and the smallest at xn. There are many possible arrangements with these two elements at the ends fixed. But, we have to print the lexicographically smallest. That means the smallest remaining element in the second spot, next smallest in third spot, etc. The array must be sorted in non-decreasing order from 2 to n-1. So, sort the entire array and swap the first and last element. For swapping, I was going to use XOR ... a = a^b, b = a^b, a = a^b. But, STL has an inbuilt function for swapping. --------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector sequence(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &sequence[i]); sort(all(sequence)); swap(sequence[0], sequence.back()); for(unsigned int i = 0; i < sequence.size(); i++) printf("%d ", sequence[i]); return 0; } ================================================ FILE: Explanations/Explanations - 10/Interesting Drink Explanation.txt ================================================ Vasiliy likes to rest after a hard work, so you may often meet him in some bar nearby. As all programmers do, he loves the famous drink "Beecola", which can be bought in n different shops in the city. It's known that the price of one bottle in the shop i is equal to xi coins. Vasiliy plans to buy his favorite drink for q consecutive days. He knows, that on the i-th day he will be able to spent mi coins. Now, for each of the days he want to know in how many different shops he can buy a bottle of "Beecola". ------------------------------------------------- Sort all the drinks in ascending order of price and then use upper bound. upper bound returns the rightmost index that is <= key. It is already one indexed so no need to decrease by 1. If all the prices are greater, than it will return 0. If all are smaller it will return n. ------------------------------------------------------------ int main() { int no_of_shops; scanf("%d", &no_of_shops); vector price_in_shop(no_of_shops); for(int i = 0; i < no_of_shops; i++) scanf("%d", &price_in_shop[i]); sort(all(price_in_shop)); int no_of_days, budget_day_i; scanf("%d", &no_of_days); for(int i = 1; i <= no_of_days; i++) { scanf("%d", &budget_day_i); int no_of_eligible_shops = upper_bound(all(price_in_shop), budget_day_i) - price_in_shop.begin(); printf("%d\n",no_of_eligible_shops); //0 indexed vector so no need to subtract 1. } return 0; } ================================================ FILE: Explanations/Explanations - 10/Keyboard Layouts Explanation.txt ================================================ There are two popular keyboard layouts in Berland, they differ only in letters positions. All the other keys are the same. In Berland they use alphabet with 26 letters which coincides with English alphabet. You are given two strings consisting of 26 distinct letters each: all keys of the first and the second layouts in the same order. You are also given some text consisting of small and capital English letters and digits. It is known that it was typed in the first layout, but the writer intended to type it in the second layout. Print the text if the same keys were pressed in the second layout. Since all keys but letters are the same in both layouts, the capitalization of the letters should remain the same, as well as all other characters. Input The first line contains a string of length 26 consisting of distinct lowercase English letters. This is the first layout. The second line contains a string of length 26 consisting of distinct lowercase English letters. This is the second layout. The third line contains a non-empty string s consisting of lowercase and uppercase English letters and digits. This is the text typed in the first layout. The length of s does not exceed 1000. Output Print the text if the same keys were pressed in the second layout. ----------------------------------------------------------- I did this by making a map ... the first keyboard's characters are mapped to a position number. Then, when the input is read ... I display second_keyboard[map[i]] ...But, it can be done easier and better with a map. That way ... program is easier and cleaner. If the character is not an alphabet, just display it as it is. Otherwise, check if it is capital or not and print the corresponding character after checking case. -------------------------------------------------- int main() { char keyboard_1[NO_OF_ALPHABETS], keyboard_2[NO_OF_ALPHABETS]; scanf("%s %s", keyboard_1, keyboard_2); map corresponding_keyboard_2_char; for(int i = 0; i < NO_OF_ALPHABETS; i++) { corresponding_keyboard_2_char[ keyboard_1[i] ] = keyboard_2[i]; } char text[MAX_LENGTH]; scanf("%s", text); for(int i = 0; text[i] != '\0'; i++) { if(isalpha(text[i])) { char input = tolower(text[i]); putchar(is_capital(text[i]) ? tocapital(corresponding_keyboard_2_char[input]) : corresponding_keyboard_2_char[input]); } else { putchar(text[i]); //Not there in the keyboards } } return 0; } ================================================ FILE: Explanations/Explanations - 10/Life Without Zeroes Explanation.txt ================================================ Get the number without zeroes long long zeroless(long long n) { long long zeroless_n = 0; while(n > 0) { int digit = n%10; if(digit != 0) zeroless_n = zeroless_n*10 + digit; n = n/10; } return reverse(zeroless_n); } int main() { int a, b; scanf("%d %d", &a, &b); printf(zeroless(a) + zeroless(b) == zeroless(a + b) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 10/Modified GCD Explanation.txt ================================================ Well, here is another math class task. In mathematics, GCD is the greatest common divisor, and it's an easy task to calculate the GCD between two positive integers. A common divisor for two positive numbers is a number which both numbers are divisible by. But your teacher wants to give you a harder task, in this task you have to find the greatest common divisor d between two integers a and b that is in a given range from low to high (inclusive), i.e. low?=?d?=?high. It is possible that there is no common divisor in the given range. You will be given the two integers a and b, then n queries. Each query is a range from low to high and you have to answer each query. ---------------------------------------------------------------- Keep a vector containing all the factors of the gcd ... Learnt to use the STL binary search functions on this one ... Upper bound returns the rightmost index that is <= n Lower bound returns the leftmost index that is <= n ------------------------------------------------------------------- int main() { int a, b; scanf("%d %d", &a, &b); int gcd = get_gcd(a, b); vector factors; for(int i = 1; i*i <= gcd; i++) { if(gcd%i == 0) { if(i*i == gcd) { factors.push_back(i); } else { factors.push_back(i); factors.push_back(gcd/i); } } } sort(all(factors)); int number_of_queries; scanf("%d", &number_of_queries); for(int i = 1; i <= number_of_queries; i++) { int left, right, answer; scanf("%d %d", &left, &right); int index = upper_bound(factors.begin(), factors.end(), right) - factors.begin(); //Returns 1 indexed index--; if(factors[index] < left) answer = -1; else answer = factors[index]; printf("%d\n", answer); } return 0; } ================================================ FILE: Explanations/Explanations - 10/Next Test Explanation.txt ================================================ is a system which allows to create programming tasks in a simple and professional way. When you add a test to the problem, the corresponding form asks you for the test index. As in most cases it is clear which index the next test will have, the system suggests the default value of the index. It is calculated as the smallest positive integer which is not used as an index for some previously added test. You are to implement this feature. Create a program which determines the default index of the next test, given the indexes of the previously added tests. -------------------------------------- Used a frequency table here since the least number is required. Got a mistake because it is possible for the answer to be 3001 ... if all 3000 numbers are used. Missed a corner case on this one. ------------------------------------------ int main() { vector is_used(3000 + 2, false); int no_of_tests, test_i, default_for_next; scanf("%d", &no_of_tests); for(int i = 1; i <= no_of_tests; i++) { scanf("%d", &test_i); is_used[test_i] = true; } for(int i = 1; i <= 3001; i++) { if(is_used[i] == false) { default_for_next = i; break; } } printf("%d\n", default_for_next); return 0; } ================================================ FILE: Explanations/Explanations - 10/Presents Explanation.txt ================================================ Little Petya very much likes gifts. Recently he has received a new laptop as a New Year gift from his mother. He immediately decided to give it to somebody else as what can be more pleasant than giving somebody gifts. And on this occasion he organized a New Year party at his place and invited n his friends there. If there's one thing Petya likes more that receiving gifts, that's watching others giving gifts to somebody else. Thus, he safely hid the laptop until the next New Year and made up his mind to watch his friends exchanging gifts while he does not participate in the process. He numbered all his friends with integers from 1 to n. Petya remembered that a friend number i gave a gift to a friend number pi. He also remembered that each of his friends received exactly one gift. Now Petya wants to know for each friend i the number of a friend who has given him a gift. ----------------------------------------------- Very simple implementation. A permutation is given ... We need to display p[p[i]]. ------------------------- int main() { int no_of_people; scanf("%d", &no_of_people); vector present_giver_of(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) { int gift_receiver; scanf("%d", &gift_receiver); present_giver_of[gift_receiver] = i; } for(int i = 1; i <= no_of_people; i++) printf("%d ", present_giver_of[i]); return 0; } ================================================ FILE: Explanations/Explanations - 10/Serega and Coat Rack Explanation.txt ================================================ Sereja owns a restaurant for n people. The restaurant hall has a coat rack with n hooks. Each restaurant visitor can use a hook to hang his clothes on it. Using the i-th hook costs ai rubles. Only one person can hang clothes on one hook. Tonight Sereja expects m guests in the restaurant. Naturally, each guest wants to hang his clothes on an available hook with minimum price (if there are multiple such hooks, he chooses any of them). However if the moment a guest arrives the rack has no available hooks, Sereja must pay a d ruble fine to the guest. Help Sereja find out the profit in rubles (possibly negative) that he will get tonight. You can assume that before the guests arrive, all hooks on the rack are available, all guests come at different time, nobody besides the m guests is visiting Sereja's restaurant tonight. ----------------------------------------- Sort all the hook prices. Count the number of unhappy guests = max(guests - hooks, 0) It it guests - hooks, if guests is greater and 0 if hooks is greater. All the unhappy guests collect a fine. -------------------------------------- int main() { int no_of_hooks, fine, no_of_guests; scanf("%d %d", &no_of_hooks, &fine); vector hook_prices(no_of_hooks); for(int i = 0; i < no_of_hooks; i++) scanf("%d", &hook_prices[i]); sort(all(hook_prices)); scanf("%d", &no_of_guests); int unhappy_guests = max(no_of_guests - no_of_hooks, 0); int total_fine = unhappy_guests*fine; int no_of_satisfied_guests = no_of_guests - unhappy_guests; int income = 0; for(int i = 0; i < no_of_satisfied_guests; i++) income += hook_prices[i]; printf("%d\n", income - total_fine); return 0; } ================================================ FILE: Explanations/Explanations - 10/Swap Sort Explanation.txt ================================================ In this problem your goal is to sort an array consisting of n integers in at most n swaps. For the given array find the sequence of swaps that makes the array sorted in the non-descending order. Swaps are performed consecutively, one after another. Note that in this problem you do not have to minimize the number of swaps your task is to find any sequence that is no longer than n. -------------------------------- Didn't expect a O(n^2) solution to pass. Took a long time to write it because I suspected there was a better solution. Be greedy and perform selection sort. In each iteration place the i-th smallest element at the i-th endex. Maintain a vector of pairs to keep track of the indices of the swaps. Don't swap if the element is already at the right position. (Although swapping an element with itself in the same index is allowed in this problem) In other words, perform selection sort. ------------------------------------- int main() { typedef pair pair_int; int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); vector swaps; //Selection Sort for(int i = 0; i < no_of_elements; i++) { int min_i_index = i; for(int j = i + 1; j < no_of_elements; j++) { if(element[j] < element[min_i_index]) min_i_index = j; } if(min_i_index != i) { swaps.push_back(make_pair(i, min_i_index)); swap(element[min_i_index], element[i]); } } printf("%u\n", swaps.size()); for(unsigned int i = 0; i < swaps.size(); i++) { printf("%d %d\n", swaps[i].first, swaps[i].second); } return 0; } ================================================ FILE: Explanations/Explanations - 10/Taxi Explanation.txt ================================================ Here's the strategy - All the 4s go alone. The 3s and 1s are paired up as far as possible. The remaining 3s go alone. (Note here that after this pairing either the number of 3s or the number of 1s will be 0.) The 2s are paired up together as well as far as possible. If there is a group of 2 remaining (There can only be 0 or 1 remaining group. If there were more, the match and go together), then they are paired up with 2 1s if there are that many 1s. The remaining 1s go in groups of 4. And all the outstanding 1s take another taxi ride. ----------------------------------------------------- int main() { int no_of_groups; scanf("%d", &no_of_groups); int no_of_1s = 0, no_of_2s = 0, no_of_3s = 0, no_of_4s = 0; int group_i; for(int i = 1; i <= no_of_groups; i++) { scanf("%d", &group_i); no_of_1s += (group_i == 1); no_of_2s += (group_i == 2); no_of_3s += (group_i == 3); no_of_4s += (group_i == 4); } int no_of_rides_with_3_and_1 = min(no_of_3s, no_of_1s); int no_of_rides = no_of_4s + no_of_rides_with_3_and_1 + no_of_2s/2; no_of_3s -= no_of_rides_with_3_and_1; no_of_1s -= no_of_rides_with_3_and_1; no_of_2s = no_of_2s%2; no_of_rides += no_of_3s; //Pair up as many 3s with 1s and then the remaining 3s go alone. //Pair of 1s with the remaining 2s if(no_of_2s > 0) { no_of_1s -= 2; no_of_rides++; } if(no_of_1s > 0) no_of_rides += no_of_1s/4 + (no_of_1s%4 != 0); printf("%d\n", no_of_rides); return 0; } ================================================ FILE: Explanations/Explanations - 10/Toy Cars Explanation.txt ================================================ ------------------------------------------- If the i-th row has any collision = 1 or 3, then it means it turned itself over. Otherwise, it never turned itself over. int main() { int no_of_cars; scanf("%d", &no_of_cars); vector good_cars; for(int i = 1; i <= no_of_cars; i++) { bool good_car = true; for(int j = 1; j <= no_of_cars; j++) { int collision; scanf("%d", &collision); if(collision == 1 || collision == 3) good_car = false; } if(good_car) good_cars.push_back(i); } printf("%u\n",good_cars.size()); for(unsigned int i = 0; i < good_cars.size(); i++) printf("%d\n", good_cars[i]); return 0; } ================================================ FILE: Explanations/Explanations - 10/Valera and Plates Explanation.txt ================================================ Valera is a lazy student. He has m clean bowls and k clean plates. Valera has made an eating plan for the next n days. As Valera is lazy, he will eat exactly one dish per day. At that, in order to eat a dish, he needs exactly one clean plate or bowl. We know that Valera can cook only two types of dishes. He can eat dishes of the first type from bowls and dishes of the second type from either bowls or plates. When Valera finishes eating, he leaves a dirty plate/bowl behind. His life philosophy doesn't let him eat from dirty kitchenware. So sometimes he needs to wash his plate/bowl before eating. Find the minimum number of times Valera will need to wash a plate/bowl, if he acts optimally. ------------------------------------------- Clean only if there are no clean containers of that kind. If the dish is of type 1, check no of bowls. If dish is of type 2, first check if there are any plates, THEN check if there are any bowls. ------------------------------- int main() { int no_of_days, no_of_bowls, no_of_plates; scanf("%d %d %d", &no_of_days, &no_of_bowls, &no_of_plates); int no_of_cleanings = 0; for(int i = 1; i <= no_of_days; i++) { int dish_type; scanf("%d", &dish_type); if(dish_type == 1) { if(no_of_bowls == 0) no_of_cleanings++; else no_of_bowls--; } if(dish_type == 2) { if(no_of_plates == 0 && no_of_bowls == 0) no_of_cleanings++; else if(no_of_plates > 0) no_of_plates--; else no_of_bowls--; } } printf("%d\n", no_of_cleanings); return 0; } ================================================ FILE: Explanations/Explanations - 10/Vanya and Cubes Explanation.txt ================================================ ---------------------------------------- The i-th floor of this pyramid from the top has T_i cubes. Keep subtracting T_i from cubes till it becomes negative ... The floor that makes the number of cubes negative is one less than the number of floors we can have. --------------------------------------- int main() { int no_of_cubes, height; scanf("%d", &no_of_cubes); for(height = 1; ; height++) { no_of_cubes -= (height*(height + 1))/2; if(no_of_cubes < 0) break; } height--; printf("%d\n", height); return 0; } ================================================ FILE: Explanations/Explanations - 11/BerSU Ball Explanation.txt ================================================ The Berland State University is hosting a ballroom dance in celebration of its 100500-th anniversary! n boys and m girls are already busy rehearsing waltz, minuet, polonaise and quadrille moves. We know that several boy&girl pairs are going to be invited to the ball. However, the partners' dancing skill in each pair must differ by at most one. For each boy, we know his dancing skills. Similarly, for each girl we know her dancing skills. Write a code that can determine the largest possible number of pairs that can be formed from n boys and m girls. ------------------------------------------------------------ Sort all boys and girls. Go through each of the girls, one by one. Binary search for someone of skill g[i] - 1, and then traverse the list till someone of skill at most g[i] + 1 and match to the first available person. lower_bound STL binary search function came in handy here. --------------------------------------- int main() { int no_of_girls; scanf("%d", &no_of_girls); vector girl_skills(no_of_girls); for(int i = 0; i < no_of_girls; i++) scanf("%d", &girl_skills[i]); int no_of_boys; scanf("%d", &no_of_boys); vector boy_skills(no_of_boys); for(int i = 0; i < no_of_boys; i++) scanf("%d", &boy_skills[i]); sort(all(girl_skills)); sort(all(boy_skills)); vector is_available(no_of_boys, true); int no_of_pairs = 0; for(int i = 0; i < no_of_girls; i++) { int eligible_boy = lower_bound(all(boy_skills), girl_skills[i] - 1) - boy_skills.begin(); for( ;abs(boy_skills[eligible_boy] - girl_skills[i]) <= 1 && eligible_boy < no_of_boys; eligible_boy++) { if(is_available[eligible_boy]) { no_of_pairs++; is_available[eligible_boy] = false; break; } } } printf("%d\n", no_of_pairs); return 0; } ================================================ FILE: Explanations/Explanations - 11/Elections Explanation.txt ================================================ The country of Byalechinsk is running elections involving n candidates. The country consists of m cities. We know how many people in each city voted for each candidate. The electoral system in the country is pretty unusual. At the first stage of elections the votes are counted for each city: it is assumed that in each city won the candidate who got the highest number of votes in this city, and if several candidates got the maximum number of votes, then the winner is the one with a smaller index. At the second stage of elections the winner is determined by the same principle over the cities: the winner of the elections is the candidate who won in the maximum number of cities, and among those who got the maximum number of cities the winner is the one with a smaller index. Determine who will win the elections. ------------------------------------ I misunderstood this question. It isn't the person with the greatest number of total votes. It's the person who won in the most number of cities. A tricky test case was when everybody got 0 votes. The winner has to be candidate 1, then. ----------------------------------- int main() { int no_of_candidates, no_of_cities; scanf("%d %d", &no_of_candidates, &no_of_cities); vector no_of_wins_for(no_of_candidates + 1, 0); for(int city_i = 1; city_i <= no_of_cities; city_i++) { int round_winner = 1, winner_votes = 0; //If everyone gets 0 votes, the first candidate must win. for(int candidate_i = 1; candidate_i <= no_of_candidates; candidate_i++) { int votes; scanf("%d", &votes); if(votes > winner_votes) { round_winner = candidate_i; winner_votes = votes; } } no_of_wins_for[round_winner]++; } int winner = 0; for(int i = 1; i <= no_of_candidates; i++) if(no_of_wins_for[i] > no_of_wins_for[winner]) winner = i; printf("%d\n", winner); return 0; } ================================================ FILE: Explanations/Explanations - 11/Football Explanation.txt ================================================ Petya loves football very much. One day, as he was watching a football match, he was writing the players' current positions on a piece of paper. To simplify the situation he depicted it as a string consisting of zeroes and ones. A zero corresponds to players of one team; a one corresponds to players of another team. If there are at least 7 players of some team standing one after another, then the situation is considered dangerous. For example, the situation 00100110111111101 is dangerous and 11110111011101 is not. You are given the current situation. Determine whether it is dangerous or not. ---------------------------------------------- Keep track of the longest contiguous sequence of identical characters. int main() { char players[MAX_LENGTH]; scanf("%s", players); int maximum_dangerous_sequence = 1, current_dangerous_sequence = 1; for(int i = 1; players[i] != '\0'; i++) { current_dangerous_sequence = (players[i] == players[i - 1] ? current_dangerous_sequence + 1 : 1); maximum_dangerous_sequence = max(maximum_dangerous_sequence, current_dangerous_sequence); } printf(maximum_dangerous_sequence >= 7 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 11/Free Cash Alternate Solution Explanation.txt ================================================ Valera runs a 24/7 fast food cafe. He magically learned that next day n people will visit his cafe. For each person we know the arrival time: the i-th person comes exactly at hi hours mi minutes. The cafe spends less than a minute to serve each client, but if a client comes in and sees that there is no free cash, than he doesn't want to wait and leaves the cafe immediately. Valera is very greedy, so he wants to serve all n customers next day (and get more profit). However, for that he needs to ensure that at each moment of time the number of working cashes is no less than the number of clients in the cafe. Help Valera count the minimum number of cashes to work at his cafe next day, so that they can serve all visitors. ------------------------------------------------- This solution takes advanatage of the fact that the times are given in chronological order. This is O(N). ----------------------- int main() { int no_of_customers; scanf("%d ", &no_of_customers); int hour_i, minute_i, previous_hour = 0, previous_minute = 0; int no_of_customers_at_this_time = 0, max_customers_arriving_together = 0; for(int i = 1; i <= no_of_customers; i++) { scanf("%d %d", &hour_i, &minute_i); no_of_customers_at_this_time = (hour_i == previous_hour && minute_i == previous_minute ? no_of_customers_at_this_time + 1 : 1); max_customers_arriving_together = max(max_customers_arriving_together, no_of_customers_at_this_time); previous_hour = hour_i; previous_minute = minute_i; } printf("%d\n", max_customers_arriving_together); return 0; } ================================================ FILE: Explanations/Explanations - 11/Free Cash Explanation.txt ================================================ Valera runs a 24/7 fast food cafe. He magically learned that next day n people will visit his cafe. For each person we know the arrival time: the i-th person comes exactly at hi hours mi minutes. The cafe spends less than a minute to serve each client, but if a client comes in and sees that there is no free cash, than he doesn't want to wait and leaves the cafe immediately. Valera is very greedy, so he wants to serve all n customers next day (and get more profit). However, for that he needs to ensure that at each moment of time the number of working cashes is no less than the number of clients in the cafe. Help Valera count the minimum number of cashes to work at his cafe next day, so that they can serve all visitors. ----------------------------------------------- The maximum number of customers arriving simulataneously at the same time is the answer. Keep track of the frequency of each arrival time. I did this by calculating time in terms of number of minutes from 12. This solution works even if the entries are not in chronological order. Since they're in chronological order, another way of solving this is to keep track of the longest consecutive sequence of identical elements. That is an O(N) solution ... This is an O(N log N) solution since it involves insertion into a balanced tree. --------------------------------------------------------------------- int main() { const int NO_OF_MINUTES_IN_HOUR = 60; int no_of_customers, no_of_minutes, no_of_hours; scanf("%d ", &no_of_customers); map no_of_customers_arriving_at; for(int i = 1; i <= no_of_customers; i++) { scanf("%d %d", &no_of_hours, &no_of_minutes); int arrival_time = no_of_hours*NO_OF_MINUTES_IN_HOUR + no_of_minutes; no_of_customers_arriving_at[arrival_time]++; } int max_customers_arriving_together = 0; for(map :: iterator it = no_of_customers_arriving_at.begin(); it != no_of_customers_arriving_at.end(); it++) { max_customers_arriving_together = max(max_customers_arriving_together, it->second); } printf("%d\n", max_customers_arriving_together); return 0; } ================================================ FILE: Explanations/Explanations - 11/Games.txt ================================================ Manao works on a sports TV. He's spent much time watching the football games of some country. After a while he began to notice different patterns. For example, each team has two sets of uniforms: home uniform and guest uniform. When a team plays a game at home, the players put on the home uniform. When a team plays as a guest on somebody else's stadium, the players put on the guest uniform. The only exception to that rule is: when the home uniform color of the host team matches the guests' uniform, the host team puts on its guest uniform as well. For each team the color of the home and guest uniform is different. There are n teams taking part in the national championship. The championship consists of n·(n - 1) games: each team invites each other team to its stadium. At this point Manao wondered: how many times during the championship is a host team going to put on the guest uniform? Note that the order of the games does not affect this number. You know the colors of the home and guest uniform for each team. For simplicity, the colors are numbered by integers in such a way that no two distinct colors have the same number. Help Manao find the answer to his question. ------------------------------------- First of all, no team has the same guest and home uniform. Keep track of the frequency of each guest uniform. For each home uniform h, no_of_changes increses by frequency_guest_uniform[h]. Used a map to keep track of frequency. ------------------------------ int main() { int no_of_teams; scanf("%d", &no_of_teams); vector home_uniform(no_of_teams + 1); map no_of_guest_uniforms; for(int i = 1; i <= no_of_teams; i++) { int guest_uniform; scanf("%d %d", &home_uniform[i], &guest_uniform); no_of_guest_uniforms[guest_uniform]++; } int no_of_changes = 0; for(int i = 1; i <= no_of_teams; i++) { no_of_changes += no_of_guest_uniforms[home_uniform[i]]; } printf("%d\n", no_of_changes); return 0; } ================================================ FILE: Explanations/Explanations - 11/Johnny Likes Numbers Explanation.txt ================================================ Given n and k, find the next multiple of k after n. -------------------------------------------------- Very simple. next multiple = n + (k - n%k) -------------------------------------------------- int main() { int n, k; scanf("%d %d", &n, &k); int next_multiple = n + (k - n%k); printf("%d\n", next_multiple); return 0; } ================================================ FILE: Explanations/Explanations - 11/Magic Spheres Explanation.txt ================================================ Carl is a beginner magician. He has a blue, b violet and c orange magic spheres. In one move he can transform two spheres of the same color into one sphere of any other color. To make a spell that has never been seen before, he needs at least x blue, y violet and z orange spheres. Can he get them (possible, in multiple actions)? ----------------------------------------------------- Keep track of the number of spheres you need - this is merely the difference between the required amount and the existing amount or 0, if we already have the required amount and don't need any spheres Keep track of the number of new spheres possible - this is the difference between existing amount and the required amount divided by 2 or 0 is no new spheres are possible Ultimately, the trick is possible if the number of new spheres possible is greater than or equal to the number of new spheres required. --------------------------------------------------------- int main() { int blue, violet, orange; scanf("%d %d %d", &blue, &violet, &orange); int required_blue, required_violet, required_orange; scanf("%d %d %d", &required_blue, &required_violet, &required_orange); int no_of_new_spheres_possible = 0, no_of_new_spheres_needed = 0; no_of_new_spheres_needed = max(required_blue - blue, 0) + max(required_orange - orange, 0) + max(required_violet - violet, 0); no_of_new_spheres_possible = max( (blue - required_blue)/2, 0) + max( (orange - required_orange)/2, 0) + max( (violet - required_violet)/2, 0); printf(no_of_new_spheres_possible >= no_of_new_spheres_needed ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Explanations/Explanations - 11/New Year and Hurry Explanation.txt ================================================ Limak is going to participate in a contest on the last day of the 2016. The contest will start at 20:00 and will last four hours, exactly until midnight. There will be n problems, sorted by difficulty, i.e. problem 1 is the easiest and problem n is the hardest. Limak knows it will take him 5i minutes to solve the i-th problem. Limak's friends organize a New Year's Eve party and Limak wants to be there at midnight or earlier. He needs k minutes to get there from his house, where he will participate in the contest first. How many problems can Limak solve if he wants to make it to the party? -------------------------------------------- First subtract k from total time (4 hours). Solve as many problems as you can (either the time is insufficient for the problem or all the problems have been solved). Go through the problems with i = 1 to n, Check if time - 5i >= 0, then it can be solved (Solve the problem and then reduce the time) I forgot to reduce the time the first time. ----------------------------------- int main() { int travel_time, no_of_problems; scanf("%d %d", &no_of_problems, &travel_time); const int NO_OF_MINUTES_IN_HOUR = 60; int time = 4*NO_OF_MINUTES_IN_HOUR; time = time - travel_time; int solved_problems = 0; for(int problem_i = 1; problem_i <= no_of_problems; problem_i++) { if(time - 5*problem_i >= 0) { time = time - 5*problem_i; solved_problems++; } else //Time is insufficient { break; } } printf("%d\n", solved_problems); return 0; } ================================================ FILE: Explanations/Explanations - 11/Nicholas and Permutation Explanation.txt ================================================ Nicholas has an array a that contains n distinct integers from 1 to n. In other words, Nicholas has a permutation of size n. Nicholas want the minimum element (integer 1) and the maximum element (integer n) to be as far as possible from each other. He wants to perform exactly one swap in order to maximize the distance between the minimum and the maximum elements. The distance between two elements is considered to be equal to the absolute difference between their positions. --------------------------------------------- We are interested only in the index of 1 and n. There are two strategies to maximise the distance. Place the leftmost index at the first position and then measure (right - 1) Place the rightmost at n and then measure (n - left). We have to take the element closest to the extremum and swap it with it. ----------------------------------- int main() { int n; scanf("%d", &n); int index_1, index_n; for(int i = 1; i <= n; i++) { int element; scanf("%d", &element); if(element == 1) index_1 = i; else if(element == n) index_n = i; } int distance = max( max(index_1, index_n) - 1, n - min(index_1, index_n) ); printf("%d\n", distance); return 0; } ================================================ FILE: Explanations/Explanations - 11/Petya and Staircases Explanation.txt ================================================ Little boy Petya loves stairs very much. But he is bored from simple going up and down them he loves jumping over several stairs at a time. As he stands on some stair, he can either jump to the next one or jump over one or two stairs at a time. But some stairs are too dirty and Petya doesn't want to step on them. Now Petya is on the first stair of the staircase, consisting of n stairs. He also knows the numbers of the dirty stairs of this staircase. Help Petya find out if he can jump through the entire staircase and reach the last stair number n without touching a dirty stair once. One has to note that anyway Petya should step on the first and last stairs, so if the first or the last stair is dirty, then Petya cannot choose a path with clean steps only. ----------------------------------------- Petya can jump across consecutive stairs, skip one stair or two stairs. Jumping across 3 conseutive stairs is not allowed. Just check if there are any 3 consecutive dirty stairs. I tried it with a boolean vector first but I didn't see that there can be 1e9 steps ... so, just sorted the dirty steps. Also check if the first or last stair is dirty. Got a runtime error if there are 0 dirty stairs. That was a tricky case. --------------------------------------------- int main() { int no_of_steps, no_of_dirty_steps; scanf("%d %d", &no_of_steps, &no_of_dirty_steps); vector dirty_steps(no_of_dirty_steps); for(int i = 0; i < no_of_dirty_steps; i++) scanf("%d", &dirty_steps[i]); sort(all(dirty_steps)); bool is_possible = true; if(no_of_dirty_steps > 0) { if(dirty_steps.front() == 1 || dirty_steps.back() == no_of_steps) { is_possible = false; } else { for(int i = 2; i < no_of_dirty_steps; i++) { if(dirty_steps[i] == dirty_steps[i - 1] + 1 && dirty_steps[i] == dirty_steps[i - 2] + 2) //Three consecutive dirty steps { is_possible = false; break; } } } } printf(is_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 11/Playing with Dice Explanation.txt ================================================ Two players are playing a game. First each of them writes an integer from 1 to 6, and then a dice is thrown. The player whose written number got closer to the number on the dice wins. If both payers have the same difference, it's a draw. The first player wrote number a, the second player wrote number b. How many ways to throw a dice are there, at which the first player wins, or there is a draw, or the second player wins? ------------------------------------------- Just be careful to use abs. int main() { int num_1, num_2; scanf("%d %d", &num_1, &num_2); int one_wins = 0, draw = 0, two_wins = 0; for(int dice_i = 1; dice_i <= 6; dice_i++) { one_wins += (abs(num_1 - dice_i) < abs(num_2 - dice_i)); two_wins += (abs(num_1 - dice_i) > abs(num_2 - dice_i)); draw += (abs(num_1 - dice_i) == abs(num_2 - dice_i)); } printf("%d %d %d", one_wins, draw, two_wins); return 0; } ================================================ FILE: Explanations/Explanations - 11/Saitama Destroys Hotel Explanation.txt ================================================ Saitama accidentally destroyed a hotel again. To repay the hotel company, Genos has volunteered to operate an elevator in one of its other hotels. The elevator is special it starts on the top floor, can only move down, and has infinite capacity. Floors are numbered from 0 to s and elevator initially starts on floor s at time 0. The elevator takes exactly 1 second to move down exactly 1 floor and negligible time to pick up passengers. Genos is given a list detailing when and on which floor passengers arrive. Please determine how long in seconds it will take Genos to bring all passengers to floor 0. --------------------------------------------------- Simple implementation. Keep track of the total time you've taken to travel. If the passenger arrival time at any floor is greater than total time, then wait and add wait time to total travel time. wait = max(passenger arrival - total time, 0) You don't wait if the passenger is already there. This is tricky. I chose to use two different vectors instead of a vector of pairs because I couldn't think of a good name to give to this vector that would explain it's purpose. The only trick of this problem is that you must calculate the time take to reach floor 0 from the last stop ... don't stop processing at the last stop. Similar to that problem where a bear watches a football game only if there aren't 15 boring minutes in a row. There I forgot to check that last interval from 90 till last stop ---------------------------------------------- int main() { int no_of_stops, top_floor; scanf("%d %d", &no_of_stops, &top_floor); vector floor_stop(no_of_stops); vector passenger_arrival_time(no_of_stops); for(int i = 0; i < no_of_stops; i++) scanf("%d %d", &floor_stop[i], &passenger_arrival_time[i]); reverse(all(floor_stop)); reverse(all(passenger_arrival_time)); int total_travel_time = 0, current_floor = top_floor; for(int i = 0; i < no_of_stops; i++) { total_travel_time += (current_floor - floor_stop[i]); int wait_time = max(passenger_arrival_time[i] - total_travel_time, 0); total_travel_time += wait_time; current_floor = floor_stop[i]; } total_travel_time += current_floor; //Go to floor 0 from the last floor stop printf("%d\n", total_travel_time); return 0; } ================================================ FILE: Explanations/Explanations - 11/Sasha and Sticks Explanation.txt ================================================ It's one more school day now. Sasha doesn't like classes and is always bored at them. So, each day he invents some game and plays in it alone or with friends. Today he invented one simple game to play with Lena, with whom he shares a desk. The rules are simple. Sasha draws n sticks in a row. After that the players take turns crossing out exactly k sticks from left or right in each turn. Sasha moves first, because he is the inventor of the game. If there are less than k sticks on the paper before some turn, the game ends. Sasha wins if he makes strictly more moves than Lena. Sasha wants to know the result of the game before playing, you are to help him. -------------------------------------------- In each turn k sticks are drawn. A win is possible if the number of turns is odd. int main() { long long no_of_sticks, one_turn_draw; scanf("%I64d %I64d", &no_of_sticks, &one_turn_draw); long long no_of_turns = no_of_sticks/one_turn_draw; printf(no_of_turns%2 == 1 ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Explanations/Explanations - 11/Soft Drinking Explanation.txt ================================================ This winter is so cold in Nvodsk! A group of n friends decided to buy k bottles of a soft drink called "Take-It-Light" to warm up a bit. Each bottle has l milliliters of the drink. Also they bought c limes and cut each of them into d slices. After that they found p grams of salt. To make a toast, each friend needs nl milliliters of the drink, a slice of lime and np grams of salt. The friends want to make as many toasts as they can, provided they all drink the same amount. How many toasts can each friend make? ---------------------------------------- It should be a striaghtforward problem but I was wondering why amount of salt for one round is a multiple of total amount of salt available. I saw the example explanation given and realised, np was just another variable name and didn't mean product of n and p. Could have been clearer. Find the amount of drink required for one round and the number of rounds possible with it alone. Find the amount of limes and the number of rounds possible with them alone Find the amount of salt available and the number of rounds possible with them alone. Answer is minimum of these three. ------------------------------------------ #define min(a, b) (a < b ? a : b) #define min_3(a, b, c) min(a, min(b, c)) int main() { int no_of_friends , no_of_bottles, bottle_volume, no_of_limes, no_of_slices, total_salt, one_round_drink, one_round_salt; scanf("%d %d %d %d", &no_of_friends, &no_of_bottles, &bottle_volume, &no_of_limes); scanf("%d %d %d %d", &no_of_slices, &total_salt, &one_round_drink, &one_round_salt); int no_of_toasts = min_3( (no_of_bottles*bottle_volume)/one_round_drink, no_of_limes*no_of_slices, total_salt/one_round_salt )/no_of_friends; printf("%d\n", no_of_toasts); return 0; } ================================================ FILE: Explanations/Explanations - 11/The Child and The Homework Explanation.txt ================================================ Once upon a time a child got a test consisting of multiple-choice questions as homework. A multiple-choice question consists of four choices: A, B, C and D. Each choice has a description, and the child should find out the only one that is correct. Fortunately the child knows how to solve such complicated test. The child will follow the algorithm: If there is some choice whose description at least twice shorter than all other descriptions, or at least twice longer than all other descriptions, then the child thinks the choice is great. If there is exactly one great choice then the child chooses it. Otherwise the child chooses C (the child think it is the luckiest choice). You are given a multiple-choice questions, can you predict child's choose? ----------------------------------------------------------- To check if a length is less than twice any other length, it is enough to compare the smallest and second smallest element. Likewise for the longest length. Because only the shortest length can be smaller than twice all other length, and if it isn't twice as small as second smallest, then it's not true, And if it is smaller than second smallest, it will be at least twice as small as every other element. Used a vector of int-char pairs for this one. Sort it ... The default answer is C Check if there are two options (Then answer is C). If there's only one option, choose it. Be careful about the length of the option ... It's len - 2, Because you shouldn't count the alphabet and the dot. Also didn't make the common bug of allocating memory for a vector of pairs and then pushing back (Will only access 0s with that).... Another bug could be while checking twice as small ... Perform multiplication of smallest element, not division of second smallest element. ---------------------------------------------------- int main() { typedef pair int_char; char option[MAX_LENGTH]; vector option_length; for(int i = 0; i < 4; i++) { scanf("%s", option); option_length.push_back(make_pair(strlen(option) - 2, 'A' + i)); //Excluding the alphabet and the . } sort(all(option_length)); char answer = 'C'; if(2*option_length[0].first <= option_length[1].first && option_length[3].first >= 2*option_length[2].first)//Two options { answer = 'C'; } else if(2*option_length[0].first <= option_length[1].first) { answer = option_length[0].second; } else if(option_length[3].first >= 2*option_length[2].first) { answer = option_length[3].second; } printf("%c\n", answer); return 0; } ================================================ FILE: Explanations/Explanations - 11/The New Year Meeting Friends Alternate Solution.txt ================================================ There are three friend living on the straight line Ox in Lineland. The first friend lives at the point x1, the second friend lives at the point x2, and the third friend lives at the point x3. They plan to celebrate the New Year together, so they need to meet at one point. What is the minimum total distance they have to travel in order to meet at some point and celebrate the New Year? It's guaranteed that the optimal answer is always integer. --------------------------------------------------------------------- There is an elegant proof similar to proofs of medians of points. Let us suppose they meet at a point x in between the left most and right most. Now, regardless of the position of x, left most person must travel x units and right most must travel (d - x) units, where d is the distance from rightmost to leftmost d = rightmost - leftmost Wherever x is, the two corner most people must meet. And they will always travel (x + d - x) = d distance. The third friend must also go the meeting point x. Distance = d + |x - middle| The travelling of d distance is fixed, however we can minimise the second summand and make it 0. The distance travelled is minimum when the two corner most friends meet at the location of the middle friend. And the distance travelled is d. ------------------------------------------------------ #define min_3(a, b, c) min(a, min(b, c)) #define max_3(a, b, c) max(a, max(b, c)) int main() { int location_1, location_2, location_3; scanf("%d %d %d", &location_1, &location_2, &location_3); int leftmost = min_3(location_1, location_2, location_3); int rightmost = max_3(location_1, location_2, location_3); printf("%d\n", rightmost - leftmost); return 0; } ================================================ FILE: Explanations/Explanations - 11/The New Year Meeting Friends Explanation.txt ================================================ There are three friend living on the straight line Ox in Lineland. The first friend lives at the point x1, the second friend lives at the point x2, and the third friend lives at the point x3. They plan to celebrate the New Year together, so they need to meet at one point. What is the minimum total distance they have to travel in order to meet at some point and celebrate the New Year? It's guaranteed that the optimal answer is always integer. --------------------------------------------------- The constraints were pretty small here so I decided to iterate in between every integer from leftmost to rightmost. There's a better solution though ... Answer is always rightmost-leftmost. I put the proof in the other solution ------------------------------------------------------ int main() { const int no_of_friends = 3; vector location(no_of_friends); scanf("%d %d %d", &location[0], &location[1], &location[2]); sort(all(location)); int minimum_distance = 300; for(int meet_point = location[0]; meet_point <= location[2]; meet_point++) { int distance = abs(meet_point - location[0]) + abs(meet_point - location[1]) + abs(meet_point - location[2]); minimum_distance = min(minimum_distance, distance); } printf("%d\n", minimum_distance); return 0; } ================================================ FILE: Explanations/Explanations - 11/Word Explanation.txt ================================================ Vasya is very upset that many people on the Net mix uppercase and lowercase letters in one word. That's why he decided to invent an extension for his favorite browser that would change the letters' register in every word so that it either only consisted of lowercase letters or, vice versa, only of uppercase ones. At that as little as possible letters should be changed in the word. For example, the word HoUse must be replaced with house, and the word ViP with VIP. If a word contains an equal number of uppercase and lowercase letters, you should replace all the letters with lowercase ones. For example, maTRIx should be replaced by matrix. Your task is to use the given method on one given word. ------------------------------------- Simple implementation. int main() { char word[MAX_LENGTH]; scanf("%s", word); int i, no_of_capitals = 0, no_of_lower_case = 0, length; for(i = 0; word[i] != '\0'; i++) { no_of_capitals += is_capital(word[i]) ; } length = i; no_of_lower_case = (length - no_of_capitals); if(no_of_lower_case >= no_of_capitals) { for(i = 0; word[i] != '\0'; i++) { putchar(lower_case(word[i])); } } else { for(int i = 0; i < length; i++) { putchar(capital(word[i])); } } return 0; } ================================================ FILE: Explanations/Explanations - 2/A and B Chess - Explanation.txt ================================================ A and B are preparing themselves for programming contests. To train their logical thinking and solve problems better, A and B decided to play chess. During the game A wondered whose position is now stronger. For each chess piece we know its weight: the queen's weight is 9, the rook's weight is 5, the bishop's weight is 3, the knight's weight is 3, the pawn's weight is 1, the king's weight isn't considered in evaluating position. The player's weight equals to the sum of weights of all his pieces on the board. As A doesn't like counting, he asked you to help him determine which player has the larger position weight. Input The input contains eight lines, eight characters each the board's description. The white pieces on the board are marked with uppercase letters, the black pieces are marked with lowercase letters. The white pieces are denoted as follows: the queen is represented is 'Q', the rook as 'R', the bishop as'B', the knight as 'N', the pawn as 'P', the king as 'K'. The black pieces are denoted as 'q', 'r', 'b', 'n', 'p', 'k', respectively. An empty square of the board is marked as '.' (a dot). It is not guaranteed that the given chess position can be achieved in a real game. Specifically, there can be an arbitrary (possibly zero) number pieces of each type, the king may be under attack and so on. Output Print "White" (without quotes) if the weight of the position of the white pieces is more than the weight of the position of the black pieces, print "Black" if the weight of the black pieces is more than the weight of the white pieces and print "Draw" if the weights of the white and black pieces are equal. ----------------------------------------------------------------------------------------------------- Store the board as an array of 8 strings with each row of the board as one string. Scan through the board. If you get a piece, check the colour of the piece and add the weight of the piece to the strength of the colour. Compare the strengths of the two colours at the end and print the appropriate message. ================================================ FILE: Explanations/Explanations - 2/Chat Room - Explanation.txt ================================================ Vasya has recently learned to type and log on to the Internet. He immediately entered a chat room and decided to say hello to everybody. Vasya typed the word s. It is considered that Vasya managed to say hello if several letters can be deleted from the typed word so that it resulted in the word "hello". For example, if Vasya types the word "ahhellllloou", it will be considered that he said hello, and if he types "hlelo", it will be considered that Vasya got misunderstood and he didn't manage to say hello. Determine whether Vasya managed to say hello by the given word s. Input The first and only line contains the word s, which Vasya typed. This word consisits of small Latin letters, its length is no less that 1 and no more than 100 letters. Output If Vasya managed to say hello, print "YES", otherwise print "NO". -------------------------------------------------------------------- Go through the message and search for hello characters sequentially. Find an h first, and then look for an e, and then look for an l and so on. If you find all five, you've found the message. If the message is over and all characters have not been found, then display NO. ================================================ FILE: Explanations/Explanations - 2/Word Capitalisation - Explanation.txt ================================================ Capitalization is writing a word with its first letter as a capital letter. Your task is to capitalize the given word. Note, that during capitalization all the letters except the first one remains unchanged. Input A single line contains a non-empty word. This word consists of lowercase and uppercase English letters. The length of the word will not exceed 103. Output Output the given word after capitalization. ---------------------------------------------------------------------------------- Check if the first alphabet of the given word is a small letter. If it is, subtract the ASCII value of ('a' - 'A'). In ASCII, the value of capitals is less than small letters. So, simply offset the first alphabet by the required value. ================================================ FILE: Explanations/Explanations - 3/Checking the Calendar - Expanation.txt ================================================ You are given names of two days of the week. Please, determine whether it is possible that during some non-leap year the first day of some month was equal to the first day of the week you are given, while the first day of the next month was equal to the second day of the week you are given. Both months should belong to one year. In this problem, we consider the Gregorian calendar to be used. The number of months in this calendar is equal to 12. The number of days in months during any non-leap year is: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31. Names of the days of the week are given with lowercase English letters: "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday". Input The input consists of two lines, each of them containing the name of exactly one day of the week. It's guaranteed that each string in the input is from the set "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday". Output Print "YES" (without quotes) if such situation is possible during some non-leap year. Otherwise, print "NO" (without quotes). ------------------------------------------------------------------------------------------- Let a month begin on day 1 and have x days. x = 7q + r, r is a number less than 7. The day 7q + 1 will have the same day of the week as the first day The next month begins at day r + 1. The difference in between 1(mod 7) and the allowable values of (r + 1) give us the answer. All days of a week get a number assigned to them from 1 - 7 in the order they appear in the week. We only consider the (day2 - day1) mod 7. However, we don't want negative values, so (2-5) mod 7 should be 4 not -3. So, for computer implementation, write (day2 - day1 + 7) mod 7. 1.If the month has 31 days, then 31 = 4(7) + 3. The first day is on 1(mod 7). The next month's first day is on 4(mod 7). So, difference of 3 is allowed 2.IF the month has 30 = 4(7) + 2. A difference of 2 is allowed 3. If the month has 28 = 7(4) days. Both the first days are on 1(mod 7) so a difference of 0 is allowed. ================================================ FILE: Explanations/Explanations - 3/Die Roll - Explanation.txt ================================================ Yakko, Wakko and Dot, world-famous animaniacs, decided to rest from acting in cartoons, and take a leave to travel a bit. Yakko dreamt to go to Pennsylvania, his Motherland and the Motherland of his ancestors. Wakko thought about Tasmania, its beaches, sun and sea. Dot chose Transylvania as the most mysterious and unpredictable place. But to their great regret, the leave turned to be very short, so it will be enough to visit one of the three above named places. That's why Yakko, as the cleverest, came up with a truly genius idea: let each of the three roll an ordinary six-sided die, and the one with the highest amount of points will be the winner, and will take the other two to the place of his/her dreams. Yakko thrown a die and got Y points, Wakko W points. It was Dot's turn. But she didn't hurry. Dot wanted to know for sure what were her chances to visit Transylvania. It is known that Yakko and Wakko are true gentlemen, that's why if they have the same amount of points with Dot, they will let Dot win. Input The only line of the input file contains two natural numbers Y and W the results of Yakko's and Wakko's die rolls. Output Output the required probability in the form of irreducible fraction in format A/B, where A the numerator, and B the denominator. If the required probability equals to zero, output 0/1. If the required probability equals to 1, output 1/1. -------------------------------------------------------------------------------------------- Dot wins in all cases where she gets a score >= max{Y, W} So, Dot_wins = 6 - max{Y,W} + 1 {+1 because she wins if she equalises. If she hits the maxima, she wins} ================================================ FILE: Explanations/Explanations - 4/Chewbecca and Number - Explanation.txt ================================================ Luke Skywalker gave Chewbacca an integer number x. Chewbacca isn't good at numbers but he loves inverting digits in them. Inverting digit t means replacing it with digit 9?-?t. Help Chewbacca to transform the initial number x to the minimum possible positive number by inverting some (possibly, zero) digits. The decimal representation of the final number shouldn't start with a zero. Input The first line contains a single integer x (1?=?x?=?10^{18}) the number that Luke Skywalker gave to Chewbacca. Output Print the minimum possible positive number that Chewbacca can obtain after inverting some digits. The number shouldn't contain leading zeroes. ----------------------------------------------------------------- All digits from 5-9 have to be inverted. Everything else is untouched. The first digit shouldn't be inverted if it's a 9 since leading 0s aren't allowed. ================================================ FILE: Explanations/Explanations - 4/King Moves - Explanation.txt ================================================ The only king stands on the standard chess board. You are given his position in format "cd", where c is the column from 'a' to 'h' and d is the row from '1' to '8'. Find the number of moves permitted for the king. King moves from the position e4 Input The only line contains the king's position in the format "cd", where 'c' is the column from 'a' to 'h' and 'd' is the row from '1' to '8'. Output Print the only integer x the number of moves permitted for the king. --------------------------------------------------------------------------------------------- Case 1 : King is at a corner piece [a/h][1/8] - There are 3 legal moves in these squares. Case 2 : King is at the last row or column [a/h][2-7] or [b-g][1/8] - There are 5 legal moves in these squares. Case 3 : King is anywhere else - 8 legal moves in these squares. ================================================ FILE: Explanations/Explanations - 4/Lineland Mail - Explanation.txt ================================================ All cities of Lineland are located on the Ox coordinate axis. Thus, each city is associated with its position xi — a coordinate on the Ox axis. No two cities are located at a single point. Lineland residents love to send letters to each other. A person may send a letter only if the recipient lives in another city (because if they live in the same city, then it is easier to drop in). Strange but true, the cost of sending the letter is exactly equal to the distance between the sender's city and the recipient's city. For each city calculate two values ​​mini and maxi, where mini is the minimum cost of sending a letter from the i-th city to some other city, and maxi is the the maximum cost of sending a letter from the i-th city to some other city Input The first line of the input contains integer n (2 ≤ n ≤ 10^5) — the number of cities in Lineland. The second line contains the sequence of n distinct integers x1, x2, ..., xn ( - 10^9 ≤ xi ≤ 10^9), where xi is the x-coordinate of the i-th city. All the xi's are distinct and follow in ascending order. Output Print n lines, the i-th line must contain two integers mini, maxi, separated by a space, where mini is the minimum cost of sending a letter from the i-th city, and maxi is the maximum cost of sending a letter from the i-th city. ------------------------------------------------------------------------------------------------------------------ The cities are given in ascending order. Minimum - The minimum distance city is one of the adjacent cities. Min[i] = min{C[i] - C[i-1], C[i+1] - C[i]} The first and last city have only one adjacent city so we need to write Min[1] = C[2]-C[1] and Min[n] = C[n]-C[n-1] and not use the loop condition to avoid di out of bound access Maximum - The maximum distance is either the first city or the last city. Max[i] = max{C[i] - C[0], C[n] - C[i]} ================================================ FILE: Explanations/Explanations - 4/Random Teams- Explanation.txt ================================================ --------------------------------------------------------------------------------------------------------------------------------- Consider a set of teams t_1, t_2, ... , t_m with number of people p_1, p_2, .... , p_m. We describe a procedure for increasing the number of friendships in an arrangement, given an arrangement. Case 1 : There is a single team which has more number of people than any other team. Without loss of generality, let the team with maximum number of people be t_1. It has p_1 people. Choose any other team, say t_2. Let F denote the total number of friendships. Then, F = F - (p_2 - 1) + p_1 = F + (p_1 - p_2 + 1) Since p_1 is the maximum number of people, p_1 - p_2 > 0. This means that the total number of friendships increases by atleast one by performing this procedure. Case 2: There are multiple teams which have the maximum number of people. We select any two of them and transfer one person from one team to another. The number of friendships increases by 1. The team we have transfered the person to now has more people than any other team. We now have a single maxima and it is reduced to the first case. -------------------------------------------------------------------------- We can no longer perform this procedure when every team other than t_1 has only 1 person i.e. when all teams from t_2 to t_m have 1 person only and t_1 has (n - (m - 1) ) people. The number of friendships in any other arrangement can be increased. This cannot. Therefore, this is the configuration with the maximum number of friendships. Maximum number of friendships = (n - (m-1) ) C (2) = (n-m+1)(n-m)/2 -------------------------------------------------------------------------------------- Now, consider a procedure for reducing the number of friendships in an arrangement. ================================================ FILE: Explanations/Explanations - 4/Tetrahedron - Explanation.txt ================================================ You are given a tetrahedron. Let's mark its vertices with letters A, B, C and D correspondingly. An ant is standing in the vertex D of the tetrahedron. The ant is quite active and he wouldn't stay idle. At each moment of time he makes a step from one vertex to another one along some edge of the tetrahedron. The ant just can't stand on one place. You do not have to do much to solve the problem: your task is to count the number of ways in which the ant can go from the initial vertex D to itself in exactly n steps. In other words, you are asked to find out the number of different cyclic paths with the length of n from vertex D to itself. As the number can be quite large, you should print it modulo 1000000007 (10^9 + 7). Input The first line contains the only integer n (1 ≤ n ≤ 10^7) — the required length of the cyclic path. Output Print the only integer — the required number of ways modulo 1000000007 (10^9 + 7). ------------------------------------------------------------------------------------------- Here, D is the only vertex that is different from the others. A, B and C are indistinguishable in the sense that they all share one edge with the destination and two edges with the non-destinations. Let f(n, X) be the number of ways to reach the destination D from vertex 'X' if there are n moves left and the ant is currently on 'X'. f(0, D) = 1 {Because we are already at the destination} f(0, A/B/C) = 0 {Because we aren't at the destination} This is the reason they are two different cases From a given vertex, the ant can make 3 moves. Case 1 : If the ant is on vertex D, then he can move to either vertex A, B or C. f(n, D) = 3 f(n-1, D) Case 2 : If the ant is on A, B or C, then he can move to either the destination or one of it's other two non-destination neighbours. f(n, A/B/C) = f(n-1, D) + 2(n-1, A/B/C) Since, the pointer notation would make it hard to read and to evaluate f(n, X) we only need f(n - 1, X), we don't need to store the value in a table. We can get away with auxiliary variables storing f(n-1, D) and f(n-1, A/B/C). This improves readability and space consumed. f(n, D) is the answer since the ant originally starts from D. ================================================ FILE: Explanations/Explanations - 5/Star - Explanation.txt ================================================ Print the n-th star number. It consists of a central number and 12 copies of the (n-1)th triangular number. S_n = 6n(n-1) + 1 ================================================ FILE: Explanations/Explanations - 6/A Shell Game - Explanation.txt ================================================ Today the Z city residents enjoy a shell game competition. The residents are gathered on the main square to watch the breath-taking performance. The performer puts 3 non-transparent cups upside down in a row. Then he openly puts a small ball under one of the cups and starts to shuffle the cups around very quickly so that on the whole he makes exactly 3 shuffles. After that the spectators have exactly one attempt to guess in which cup they think the ball is and if the answer is correct they get a prize. Maybe you can try to find the ball too? Input The first input line contains an integer from 1 to 3 index of the cup which covers the ball before the shuffles. The following three lines describe the shuffles. Each description of a shuffle contains two distinct integers from 1 to 3 indexes of the cups which the performer shuffled this time. The cups are numbered from left to right and are renumbered after each shuffle from left to right again. In other words, the cup on the left always has index 1, the one in the middle index 2 and the one on the right index 3. Output In the first line output an integer from 1 to 3 index of the cup which will have the ball after all the shuffles. ----------------------------------------------------------------------------------------- This problem was interesting because of the way input and output had to be given - files. I had to use a filepointer to open a file in read mode and another in write mode. Read and write into them. And then close the file at the end of the program. However, I didn't do error control (what happens in case the file pointer is NULL). Simple simulation suffices. for(i = 1; i <= NO_OF_SHUFFLES; i++) { fscanf(input,"%d %d",&shell_1, &shell_2); if(ball_shell == shell_1) { ball_shell = shell_2; } else if(ball_shell == shell_2) { ball_shell = shell_1; } } ================================================ FILE: Explanations/Explanations - 7/An Abandoned Sentiment From The Past - Explanation.txt ================================================ A few years ago, Hitagi encountered a giant crab, who stole the whole of her body weight. Ever since, she tried to avoid contact with others, for fear that this secret might be noticed. To get rid of the oddity and recover her weight, a special integer sequence is needed. Hitagi's sequence has been broken for a long time, but now Kaiki provides an opportunity. Hitagi's sequence a has a length of n. Lost elements in it are denoted by zeros. Kaiki provides another sequence b, whose length k equals the number of lost elements in a (i.e. the number of zeros). Hitagi is to replace each zero in a with an element from b so that each element in b should be used exactly once. Hitagi knows, however, that, apart from 0, no integer occurs in a and b more than once in total. If the resulting sequence is not an increasing sequence, then it has the power to recover Hitagi from the oddity. You are to determine whether this is possible, or Kaiki's sequence is just another fake. In other words, you should detect whether it is possible to replace each zero in a with an integer from b so that each integer from b is used exactly once, and the resulting sequence is not increasing. --------------------------------------------------------------------------------------------- Firstly, notice that if there was more than one zero, we can always make the sequence non-increasing by plugging in the values of b in any non-increasing order into a. The only case we need to check is when there is one 0. In that case, check if the number from b is non-increasing with respect to it's existing neighbours(1 or 2, depending on the position of the 0). Also, check if any non-zero element of a is smaller than or equal to it's predecessor while reading input. It is possible for the replaced element to be in order with it's neighbours, but out of order with some other element. For example, let m be place in between u and v. u < m < v. If there is some element k to the left of u, out of order with m, such that, k > m, then k > u as well. If there is some element k to the right of v out of order with m, such that, k < m, then k < v as well. That is why the elements of a need to be checked while reading the input. --------------------------------------------- for(i = 0; i < entire_length; i++) { scanf("%d", &a[i]); if(a[i] == 0) zero_index = i; else if(i > 0 && a[i] <= a[i - 1]) is_possible = true; } for(i = 0; i < no_of_zeroes; i++) Only the case where no of missing zeroes is 1 is interesting, so we don't use an array. scanf("%d",&missing_number); --------------------------------- if(no_of_zeroes > 1) { is_possible = true; } else { if(zero_index == 0) { if(missing_number >= a[zero_index + 1]) is_possible = true; } else if(zero_index == entire_length - 1) { if(missing_number <= a[zero_index - 1]) is_possible = true; } else if(missing_number >= a[zero_index + 1] || missing_number <= a[zero_index - 1]) { is_possible = true; } } ----------- ================================================ FILE: Explanations/Explanations - 7/Combination Lock Explanation.txt ================================================ The combination lock is represented by n rotating disks with digits from 0 to 9 written on them. Scrooge McDuck has to turn some disks so that the combination of digits on the disks forms a secret combination. In one move, he can rotate one disk one digit forwards or backwards. In particular, in one move he can go from digit 0 to digit 9 and vice versa. ------------------------------------------------------------------------------------- What minimum number of actions does he need for that?On each turn check if it's optimal to go forwards or backwards ... Going backwards is simple b-a, forwards is (10 + a) - b because we need to cross 'a' locks after '0' ------------------------------------------------- for(int i = 0; i < number_of_locks; i++) { int start, ending; start = min(current_state[i], final_state[i]) - '0'; ending = max(current_state[i], final_state[i]) - '0'; number_of_moves += min(ending - start, 10 + start - ending); //Optimal to go forwards or backwards } ================================================ FILE: Explanations/Explanations - 7/Find Marble - Explanation.txt ================================================ Petya and Vasya are playing a game. Petya's got n non-transparent glasses, standing in a row. The glasses' positions are indexed with integers from 1 to n from left to right. Note that the positions are indexed but the glasses are not. First Petya puts a marble under the glass in position s. Then he performs some (possibly zero) shuffling operations. One shuffling operation means moving the glass from the first position to position p1, the glass from the second position to position p2 and so on. That is, a glass goes from position i to position pi. Consider all glasses are moving simultaneously during one shuffling operation. When the glasses are shuffled, the marble doesn't travel from one glass to another: it moves together with the glass it was initially been put in. After all shuffling operations Petya shows Vasya that the ball has moved to position t. Vasya's task is to say what minimum number of shuffling operations Petya has performed or determine that Petya has made a mistake and the marble could not have got from position s to position t. ------------------------------------------------------------------------------------------------------------------------------------- We keep going from i to p[i] till we reach t or detect a cycle before it. Since no location is visited by two glasses, we only need to check if we reach s at some point. So, s-> u-> v -> t Since s visits u, no other glass visits u. Since u visits v, no other glass visits v. So, if there is a cycle if must end only at s. Otherwise we would need to maintain a boolean vector with each element to keep track of whether or not we have visited it. ------------------------------ for(i = initial_position; ; i = *(shuffled_result + i), minimum_shuffles++) if( (i == initial_position && minimum_shuffles!= 0) || (i == final_position) ) break; printf("%d\n", (i == final_position ? minimum_shuffles : -1) ); ------------------------------------------- We need to check that minimum shuffles is not 0 when i = initial position because it is always true in the starting iteration. Another way of doing it. do { if(i == final_position) break; i = *(shuffled_result + i); minimum_shuffles++; } while(i != initial_position); ================================================ FILE: Explanations/Explanations - 7/Free Ice Cream Explanation.txt ================================================ After their adventure with the magic mirror Kay and Gerda have returned home and sometimes give free ice cream to kids in the summer. At the start of the day they have x ice cream packs. Since the ice cream is free, people start standing in the queue before Kay and Gerda's house even in the night. Each person in the queue wants either to take several ice cream packs for himself and his friends or to give several ice cream packs to Kay and Gerda (carriers that bring ice cream have to stand in the same queue). If a carrier with d ice cream packs comes to the house, then Kay and Gerda take all his packs. If a child who wants to take d ice cream packs comes to the house, then Kay and Gerda will give him d packs if they have enough ice cream, otherwise the child will get no ice cream at all and will leave in distress. Kay wants to find the amount of ice cream they will have after all people will leave from the queue, and Gerda wants to find the number of distressed kids. ------------------------------------------------------ Simple implementation. Keep track of the number of packets and how many requests are unsatisfied. Missed the fact that overflow can occur the first time. for(int i = 1; i <= no_of_people; i++) { char action; int amount; scanf(" %c %d", &action, &amount); if(action == '+') ice_cream += amount; else if(amount > ice_cream) distressed_kids++; else ice_cream -= amount; } printf("%I64d %d\n", ice_cream, distressed_kids); ================================================ FILE: Explanations/Explanations - 7/Hexadecimal's Theorem Alternate Solution Explanation.txt ================================================ Express a Fibonacci number as the sum of three not necissarily distinct Fibonacci numbers ... ------------------------------------------------------- n = 0 + 0 + n, n and 0 are all Fibonacci numbers and we are done ! int main() { int n; scanf("%d", &n); printf("0 0 %d\n", n); return 0; } ================================================ FILE: Explanations/Explanations - 7/Hexadecimal's Theorem Explanation.txt ================================================ Express a Fibonacci number as the sum of three not necissarily distinct Fibonacci numbers ... --------------------------------------------------- F(n) = F(n - 1) + F(n - 2) = F(n - 1) + F(n - 3) + F(n - 4) So, I precomputed the list of all Fibonacci numbers, handled the case up to n = 3 manually and then used the above recurrence to get the answer. ------------------------------------------------------------------- void precompute_fibonacci() { const int MAX = 1e9; fibonacci.push_back(0); fibonacci.push_back(1); for(int i = 2; fibonacci[i - 1] + fibonacci[i - 2] <= MAX; i++) fibonacci.push_back(fibonacci[i - 1] + fibonacci[i - 2]); } ------------------------------ precompute_fibonacci(); int n; scanf("%d", &n); if(n == 0) //F(0) printf("0 0 0\n"); else if(n == 1)//F(1) and F(2) printf("1 0 0\n"); else if(n == 2) //F(3) printf("1 1 0\n"); else { int index = 4; while(fibonacci[index] != n) index++; printf("%d %d %d\n",fibonacci[index - 1], fibonacci[index - 3], fibonacci[index - 4]); } ---------------------------------------------------------- Good use of the recurrence but there is a much simpler solution ! n = 0 + 0 + n, n and 0 are all Fibonacci numbers and we are done ! ================================================ FILE: Explanations/Explanations - 7/Mahmod and Longest Uncommon Subsequence - Explanation.txt ================================================ While Mahmoud and Ehab were practicing for IOI, they found a problem which name was Longest common subsequence. They solved it, and then Ehab challenged Mahmoud with another problem. Given two strings a and b, find the length of their longest uncommon subsequence, which is the longest string that is a subsequence of one of them and not a subsequence of the other. A subsequence of some string is a sequence of characters that appears in the same order in the string, The appearances don't have to be consecutive, for example, strings "ac", "bc", "abc" and "a" are subsequences of string "abc" while strings "abbc" and "acb" are not. The empty string is a subsequence of any string. Any string is a subsequence of itself. ------------------------------------------------------------------------------------------------- If the strings are not equal, then the longest uncommon subsequence is the larger string. If they are equal, there is no uncommon subsequence. printf("%d\n", (strcmp(string_1, string_2) != 0 ? max( strlen(string_1),strlen(string_2) ) : -1) ); ================================================ FILE: Explanations/Explanations - 7/Optimal Point on a Line - Explanation.txt ================================================ You are given n points on a line with their coordinates xi. Find the point x so the sum of distances to the given points is minimal. ----------------------------------------------------------------------- The median minimises the distance. If there is a sorted list of n elements, x1 x2 ... xn, then the element at position n/2 is the median. Let us prove that the median has the least distance to all the points. Case 1: n is even, If there are two points x1, and x2, the answer is one of these points. (|xn - x| + |x1 - x|) + (|x(n-1) - x| + |x2 - x|) + ... + (|x(n/2) - x| + |x(n/2+1) - x)|) The point that minimises this distance must lie inside each of these intervals. The two medians satisfy this property. Case 2: n is odd. Let there be 3 elements - x1, x2 and x3. Here, the minimum sum of distances from one point to the other 2 is by x2. As we add pairs of points to this set - one at the extreme right and one at the extreme left. By the same logic, if there are 2n + 1 points, and we split it into n pairs and xm, where xm is the median, xm is the only point that lies inside every interval. So, it minimises the distance. ------------------------------- sort(points, points + no_of_points); median = points[(no_of_points - 1)/2]; ----------------------- Array is indexed from 0. So, we consider (n-1)/2 Instead of n/2 since the last element is (n-1) ================================================ FILE: Explanations/Explanations - 7/Pashmak and Flowers - Explanation.txt ================================================ Pashmak decided to give Parmida a pair of flowers from the garden. There are n flowers in the garden and the i-th of them has a beauty number bi. Parmida is a very strange girl so she doesn't want to have the two most beautiful flowers necessarily. She wants to have those pairs of flowers that their beauty difference is maximal possible! Your task is to write a program which calculates two things: The maximum beauty difference of flowers that Pashmak can give to Parmida. The number of ways that Pashmak can pick the flowers. Two ways are considered different if and only if there is at least one flower that is chosen in the first way and not chosen in the second way. --------------------------------------------------------------------------------------------- We need to count the number of maxima and the number of minima and multiply them. I had overlooked overflow at first in multiplication and the case where the maxima and minima are equal. In that case, the answer is n(n-1)/2, where n is the number of flowers because all flowers are equally beautiful. Multiplying number of minima and maxima will not be correct in that case since it will be overcounting pairs. for(i = 1; i <= no_of_flowers; i++) { scanf("%d",¤t_beauty); if(current_beauty == most_beautiful) no_of_maxima++; if(current_beauty == least_beautiful) no_of_minima++; if(current_beauty < least_beautiful) least_beautiful = current_beauty, no_of_minima = 1; if(current_beauty > most_beautiful) most_beautiful = current_beauty, no_of_maxima = 1; } //If all flowers are equally beautiful, then choices = n(n-1)/2 no_of_choices = ( most_beautiful == least_beautiful ? (no_of_flowers*1LL*(no_of_flowers - 1) )/2 : no_of_minima*1LL*no_of_maxima ); printf("%d %I64d\n",(most_beautiful - least_beautiful), no_of_choices); -------------------------------------------------------------------------------------------------- Note - type casting by multiplying by 1LL is necessary to avoid overflow, otherwise 32 bit multiplication will be performed. ================================================ FILE: Explanations/Explanations - 7/Young Physicist - Explanation.txt ================================================ A guy named Vasya attends the final grade of a high school. One day Vasya decided to watch a match of his favorite hockey team. And, as the boy loves hockey very much, even more than physics, he forgot to do the homework. Specifically, he forgot to complete his physics tasks. Next day the teacher got very angry at Vasya and decided to teach him a lesson. He gave the lazy student a seemingly easy task: You are given an idle body in space and the forces that affect it. The body can be considered as a material point with coordinates (0; 0; 0). Vasya had only to answer whether it is in equilibrium. "Piece of cake" thought Vasya, we need only to check if the sum of all vectors is equal to 0. So, Vasya began to solve the problem. But later it turned out that there can be lots and lots of these forces, and Vasya can not cope without your help. Help him. Write a program that determines whether a body is idle or is moving by the given vectors of forces. --------------------------------------------------------------------------------- for(i = 1; i <= no_of_vectors; i++) { scanf("%d %d %d",&x, &y, &z); total_x += x; total_y += y; total_z += z; } printf(total_x == 0 && total_y == 0 && total_z == 0 ? "YES\n" : "NO\n"); ================================================ FILE: Explanations/Explanations - 8/A and B Team Training Explanation.txt ================================================ A and B are preparing themselves for programming contests. An important part of preparing for a competition is sharing programming knowledge from the experienced members to those who are just beginning to deal with the contests. Therefore, during the next team training A decided to make teams so that newbies are solving problems together with experienced participants. A believes that the optimal team of three people should consist of one experienced participant and two newbies. Thus, each experienced participant can share the experience with a large number of people. However, B believes that the optimal team should have two experienced members plus one newbie. Thus, each newbie can gain more knowledge and experience. As a result, A and B have decided that all the teams during the training session should belong to one of the two types described above. Furthermore, they agree that the total number of teams should be as much as possible. There are n experienced members and m newbies on the training session. Can you calculate what maximum number of teams can be formed? ------------------------------------------------ Each team must have one experienced and one new person ... So, the number of teams can never exceed min(experienced, new). So, we start from the maximum number of teams greedily and go down to 1 and choose the greatest configuration that is possible. To check if a configuration of i teams is possible ... We make i teams consisting of 1 experienced and 1 new person. Then, we check if we have enough people to fill the third spot in all the i teams. ----------------------------------------- no_of_teams = min(experienced_people_no, newbie_no); while(no_of_teams > 0) { no_of_available_people = (experienced_people_no + newbie_no) - 2*no_of_teams; if(no_of_available_people >= no_of_teams) break; no_of_teams--; } printf("%d\n", no_of_teams); ================================================ FILE: Explanations/Explanations - 8/Almost Primes Explanation.txt ================================================ A number is said to be almost primes if it has exactly two distinct prime factors. For a given n, display the number of almost primes up to n. ------------------------------------------------------- Do a sieve ... Initially all numbers have 0 prime factors ... Pick up the first number that has 0 prime factors, and increase the number of factors of all it's multiples by 1. And then have a prefix array ... no_of_almost_primes_till[i] = no_of_almost_primes_till[i-1] + (is_almost_prime(i) == true) Each query can be answered in O(1) time, but in CodeForces there is only one query per test case. ------------------------------------------------------------ vector no_of_almost_primes_till(3000 + 1, 0); void precompute_primes() { vector no_of_prime_factors(3000 + 1, 0); for(int i = 2; i <= 3000; i++) { if(no_of_prime_factors[i] == 0) { for(int multiple = i; multiple <= 3000; multiple += i) { no_of_prime_factors[multiple]++; } } } for(int i = 1; i <= 3000; i++) { no_of_almost_primes_till[i] = no_of_almost_primes_till[i - 1] + (no_of_prime_factors[i] == 2); } } int main() { precompute_primes(); int n; scanf("%d", &n); printf("%d\n", no_of_almost_primes_till[n]); return 0; } ================================================ FILE: Explanations/Explanations - 8/Brian's Photos.txt ================================================ Small, but very brave, mouse Brain was not accepted to summer school of young villains. He was upset and decided to postpone his plans of taking over the world, but to become a photographer instead. As you may know, the coolest photos are on the film (because you can specify the hashtag #film for such). Brain took a lot of colourful pictures on colored and black-and-white film. Then he developed and translated it into a digital form. But now, color and black-and-white photos are in one folder, and to sort them, one needs to spend more than one hour! As soon as Brain is a photographer not programmer now, he asks you to help him determine for a single photo whether it is colored or black-and-white. Photo can be represented as a matrix sized n × m, and each element of the matrix stores a symbol indicating corresponding pixel color. There are only 6 colors: 'C' (cyan) 'M' (magenta) 'Y' (yellow) 'W' (white) 'G' (grey) 'B' (black) The photo is considered black-and-white if it has only white, black and grey pixels in it. If there are any of cyan, magenta or yellow pixels in the photo then it is considered colored. ---------------------------------------------------- Simple implementation ... But I got a wrong answer because I had forgotten to put a space in front of scanf while scanning a character ... It reads the whitespace too ------------------------------- for(int row = 1; row <= no_of_rows; row++) { for(int column = 1; column <= no_of_columns; column++) { char colour; scanf(" %c", &colour); if(colour != 'B' && colour != 'G' && colour != 'W') is_colourful = true; } } printf(is_colourful ? "#Color\n" : "#Black&White\n"); ================================================ FILE: Explanations/Explanations - 8/Ceil and Flowers Explanation.txt ================================================ Fox Ciel has some flowers: r red flowers, g green flowers and b blue flowers. She wants to use these flowers to make several bouquets. There are 4 types of bouquets: To make a "red bouquet", it needs 3 red flowers. To make a "green bouquet", it needs 3 green flowers. To make a "blue bouquet", it needs 3 blue flowers. To make a "mixing bouquet", it needs 1 red, 1 green and 1 blue flower. Help Fox Ciel to find the maximal number of bouquets she can make. --------------------------------------------------- I tried some strategies that didn't work ... Like, take as many mixed boquets as possible and then take the rest, and then take as many monochromatic boquets as possible and then take the mixed boquet. The answer requires noticing that the number of mixed boquets never needs to be more than 3. If we have 3 mixed boquets, we can think of them as 3 boquets of each colour. So, just count how many boquets there would be if there was one mixed boquet, two mixed boquets and no mixed boquets. -------------------------------------------------------- #define min_3(a, b, c) min(a, min(b, c) ) #define max_3(a, b, c) max(a, max(b, c) ) using namespace std; int main() { int green, red, blue; scanf("%d %d %d",&red, &green, &blue); int one_mixed_boquet = 0, two_mixed_boquet = 0, no_mixed_boquet; no_mixed_boquet = red/3 + green/3 + blue/3; if(min_3(red,green, blue) >= 1) one_mixed_boquet = 1 + (red - 1)/3 + (green - 1)/3 + (blue - 1)/3; if(min_3(red, green, blue) >= 2) two_mixed_boquet = 2 + (red - 2)/3 + (green - 2)/3 + (blue - 2)/3; printf("%d\n",max_3(no_mixed_boquet, two_mixed_boquet, one_mixed_boquet)); return 0; } ================================================ FILE: Explanations/Explanations - 8/Choosing Teams Explanation.txt ================================================ The Saratov State University Olympiad Programmers Training Center (SSU OPTC) has n students. For each student you know the number of times he/she has participated in the ACM ICPC world programming championship. According to the ACM ICPC rules, each person can participate in the world championship at most 5 times. The head of the SSU OPTC is recently gathering teams to participate in the world championship. Each team must consist of exactly three people, at that, any person cannot be a member of two or more teams. What maximum number of teams can the head make if he wants each team to participate in the world championship with the same members at least k times? -------------------------------------------- Sort the people by the number of attempts they have ... Look at people in batches of three .. If for a given i, A[i + 2] + k <= 5, then increment number of teams, i = i + 3. ---------------------------------------- int main() { int number_of_people, number_of_attempts; scanf("%d %d", &number_of_people, &number_of_attempts); vector attempts (number_of_people); for(int i = 0; i < number_of_people; i++) scanf("%d", &attempts[i]); sort(all(attempts)); int no_of_teams = 0, i = 0; while(i + 2 < number_of_people && (attempts[i +2] + number_of_attempts) <= 5) { i += 3; no_of_teams++; } printf("%d\n",no_of_teams); return 0; } ================================================ FILE: Explanations/Explanations - 8/HQ9+ Explanation.txt ================================================ HQ9+ is a joke programming language which has only four one-character instructions: "H" prints "Hello, World!", "Q" prints the source code of the program itself, "9" prints the lyrics of "99 Bottles of Beer" song, "+" increments the value stored in the internal accumulator. Instructions "H" and "Q" are case-sensitive and must be uppercase. The characters of the program which are not instructions are ignored. You are given a program written in HQ9+. You have to figure out whether executing this program will produce any output. Input The input will consist of a single line p which will give a program in HQ9+. String p will contain between 1 and 100 characters, inclusive. ASCII-code of each character of p will be between 33 (exclamation mark) and 126 (tilde), inclusive. Output Output "YES", if executing the program will produce any output, and "NO" otherwise. ----------------------------------------------------------- int main() { bool produces_output = false; char program[MAX_LENGTH]; scanf("%s", program); for(int i = 0; program[i] != '\0'; i++) { if(program[i] == 'H' || program[i] == 'Q' || program[i] == '9') { produces_output = true; break; } } printf(produces_output ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 8/Hexadecimal's Numbers Explanation.txt ================================================ One beautiful July morning a terrible thing happened in Mainframe: a mean virus Megabyte somehow got access to the memory of his not less mean sister Hexadecimal. He loaded there a huge amount of n different natural numbers from 1 to n to obtain total control over her energy. But his plan failed. The reason for this was very simple: Hexadecimal didn't perceive any information, apart from numbers written in binary format. This means that if a number in a decimal representation contained characters apart from 0 and 1, it was not stored in the memory. Now Megabyte wants to know, how many numbers were loaded successfully. ---------------------------------------------- All the numbers which survive are the ones containing only 1s and 0s in the DECIMAL representation... It isn't possible to check from 1 to 1e9, which numbers are good ... Instead Notice that all binary strings survive ... There are at most 2^10 - 1 of these numbers. We get this by summing over 2 + 2^2 + 2^3 + ... + 2^9 ... There are 2^n binary strings of length n. So what is done is have a bitmask that goes from 1 to 2^10 - 1, get the decimal value of the bitmask ... and check if it is smaller than n. ------------------------------------------ Converting a bitmask to decimal int corresponding_decimal(int bitmask) { int decimal = 0; //Get the bitmask in decimal For example, 11 should be eleven .. So, we treat it like a polynomial, multiply decimal by 10 at each step and add //it to whatever bit was there ... 11 will be 1*10 + 1. for(int i = 31; i >= 0; i--) { decimal = decimal*10 + ( (bitmask & (1 << i) ) != 0) ; } return decimal; } Treat it like a polynomial ... Go from the MSB to the LSB MSB is x^31 ... LSB is x^0 ... To evaluate the polynomail use Horner's method. At each step, P = x*P + c, where c is the next coefficient. Here, x is 10 and coefficient is at most 1 ... So just check if it isn't zero and add it. A common bug is writing (bitmask & (1 << i)) == 1, that is not correct. We must check that it is NOT 0, instead of checking if it is 1. Because, the AND operation leaves a 1 at the i-th position ... This means the string is 100000...0 (i - 1) zeroes ... It is not 1. If the answer is non-zero, it means the i-th bit is set. So 1 is added as that is what the relational operator returns. ----------------------------------------------------- int max_numbers = (1 << 10) - 1; //At most 2^10 - 1 numbers for(int bitmask = 1; bitmask <= max_numbers; bitmask++) { if(corresponding_decimal(bitmask) > limit) break; no_of_saved_numbers++; } ================================================ FILE: Explanations/Explanations - 8/Jzzhu and Sequences Explanation.txt ================================================ F(i) = F(i - 1) + F(i + 1) ---------------------------------------- CodeChef had a very similar problem and a DP won't pass the time limit... Notice that the sequence is periodic with period 6. Just handle the overflow. --------------------------------------------- X = (X + MOD)%MOD; Y = (Y + MOD)%MOD; switch(number_of_terms%6) { case 1: answer = X; break; case 2: answer = Y; break; case 3: answer = Y + MOD - X; break; case 4: answer = 0 + MOD - X; break; case 5: answer = 0 + MOD - Y; break; case 0: answer = X + MOD - Y; break; } answer = (answer + MOD)%MOD; ================================================ FILE: Explanations/Explanations - 8/K Factorisation Explanation.txt ================================================ -------------------------------------------------- If we just run through the factors like i, n/i for i = 1 to root(n), we won't get a list of numbes who's product is n. For that, we need the prime factorisation of n ... Write all of the prime factors (with duplicity) of n down on a vector ... Replace any two numbers by their product and reduce the size of the list till it becomes = k. If the initial size of the list is less than k, then it is not possible. Given a positive integer n, find k integers (not necessary distinct) such that all these integers are strictly greater than 1, and their product is equal to n. -------------------------------- TO find the prime factorisation, we start from i = 2 and go up to N. Whenever i divides n, continuously divide n/i till it is no longer divisible by i (so that if N is divisible by i, it will not be divisible by any of i's factors when we encounter them. ... This is similar to a sieve.) Add i to the list. ---------------------------------------- I have multiplied the last two elements of the vector once it crosses k.. Although the final solution didn't use it... I learnt how to pass vectors as parameters by reference -------------------------- int main() { unsigned int n, number_of_factors; scanf("%d %d", &n, &number_of_factors); vector factor; for(unsigned int i = 2; i <= n ; i++) { while(n%i == 0) { if(factor.size() == number_of_factors) factor.back() *=i; else factor.push_back(i); n = n/i; } } if(factor.size() < number_of_factors) printf("-1\n"); else for(unsigned int i = 0; i < number_of_factors; i++) printf("%d ",factor[i]); return 0; } ================================================ FILE: Explanations/Explanations - 8/Noldbach Problem Explanation.txt ================================================ Nick is interested in prime numbers. Once he read about Goldbach problem. It states that every even integer greater than 2 can be expressed as the sum of two primes. That got Nick's attention and he decided to invent a problem of his own and call it Noldbach problem. Since Nick is interested only in prime numbers, Noldbach problem states that at least k prime numbers from 2 to n inclusively can be expressed as the sum of three integer numbers: two neighboring prime numbers and 1. For example, 19 = 7 + 11 + 1, or 13 = 5 + 7 + 1. Two prime numbers are called neighboring if there are no other prime numbers between them. You are to help Nick, and find out if he is right or wrong. ------------------------------------------------------ Here's what I did ... Precomputed a list of all primes till 1000. Maintained a boolean vector of length 1000 such that B[i] is true, if it is Noldbach number and false otherwise. Now, instead of iterating from i = 1 to N in the given range to check the given conditions ... Pick up the primes in the precomputed vector and check if they're Noldbach numbers ... This means we have to do log N iterations instead of O(N) for each query ... However precomputation is O(N log log N + log N). There were some answers that didn't precompute anythhing... Go from i = 1 to N, apply a O(root(n)) test on all numbers ... Push it into a vector Then for all primes in the given range, check if each prime is the sum of consecutive primes + 1. O(log^2 N). -------------------------------------- vector noldbach_number(1000 + 1, false); vector primes; void precompute_noldbach() { vector is_prime(1000 + 1, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= 1000; i++) { if(is_prime[i]) { for(int multiple = 2*i; multiple <= 1000; multiple += i) { is_prime[multiple] = false; } primes.push_back(i); } } for(int i = 0; primes[i] + primes[i + 1] <= 1000 ; i++) { noldbach_number[primes[i] + primes[i + 1] + 1] = true; } } -------------------------------------------------------- Sieve is done first to build a vector of primes ... Then the noldbach numbers are precomputed. ---------------------------------------------- int main() { precompute_noldbach(); int n, k; scanf("%d %d", &n, &k); int conjecture_count = 0; for(int i = 0; primes[i] <= n; i++) { if(noldbach_number[primes[i]]) conjecture_count++; } printf(conjecture_count >= k ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 8/Oleysa and Rodion Explanation.txt ================================================ Olesya loves numbers consisting of n digits, and Rodion only likes numbers that are divisible by t. Find some number that satisfies both of them. Your task is: given the n and t print an integer strictly larger than zero consisting of n digits that is divisible by t. If such number doesn't exist, print -1 -------------------------------------------------- Use the simplest solution that works ... I was initially going for searching for the lcm and then pad it with zeroes ... But, there's a better solution ! Print K and then fill the remaining N-1 spots with 0s. ... The only time we need to print -1 is when n = 1, k = 10 ---------------------------------------------- if(number_of_digits == 1 && multiple == 10) { printf("-1\n"); } else { printf("%d", multiple); int no_of_zeroes = (multiple == 10 ? number_of_digits - 2 : number_of_digits - 1); for(int zero_count = 1; zero_count <= no_of_zeroes; zero_count++) printf("0"); } ================================================ FILE: Explanations/Explanations - 8/Petr and Book Explanation.txt ================================================ One Sunday Petr went to a bookshop and bought a new book on sports programming. The book had exactly n pages. Petr decided to start reading it starting from the next day, that is, from Monday. Petr's got a very tight schedule and for each day of the week he knows how many pages he will be able to read on that day. Some days are so busy that Petr will have no time to read whatsoever. However, we know that he will be able to read at least one page a week. Assuming that Petr will not skip days and will read as much as he can every day, determine on which day of the week he will read the last page of the book. ------------------------------------------ int main() { int no_of_pages; scanf("%d", &no_of_pages); int i; vector pages_read_on_day(7); for(i = 0; i < 7; i++) scanf("%d", &pages_read_on_day[i]); i = 0; while(true) { no_of_pages -= pages_read_on_day[i]; if(no_of_pages <= 0) break; i = (i + 1)%7; } printf("%d\n",i + 1); return 0; } ================================================ FILE: Explanations/Explanations - 8/Petya and Strings Explanation.txt ================================================ Little Petya loves presents. His mum bought him two strings of the same size for his birthday. The strings consist of uppercase and lowercase Latin letters. Now Petya wants to compare those two strings lexicographically. The letters' case does not matter, that is an uppercase letter is considered equivalent to the corresponding lowercase letter. Help Petya perform the comparison. ------------------------------------------------------- Maybe if I had more time, I would make both strings lower character and then use strcmp so that there's no abrupt end ... But I wanted to finish this as soon as possible. #define tolower(c) (c < 'a' ? (c + 'a' - 'A') : c) int main() { char string_1[MAX_LENGTH], string_2[MAX_LENGTH]; scanf("%s %s", string_1, string_2); for(int i = 0; string_1[i] != '\0'; i++) { if(tolower(string_1[i]) > tolower(string_2[i]) ) { printf("1\n"); return 0; } else if(tolower(string_1[i]) < tolower(string_2[i]) ) { printf("-1\n"); return 0; } } printf("0\n"); return 0; } ================================================ FILE: Explanations/Explanations - 8/Sum of Digits Explanation.txt ================================================ Having watched the last Harry Potter film, little Gerald also decided to practice magic. He found in his father's magical book a spell that turns any number in the sum of its digits. At the moment Gerald learned that, he came across a number n. How many times can Gerald put a spell on it until the number becomes one-digit? ---------------------------------------------- This is similar to the big GCD problem ... We only need to use big numbers once ... If the initial number is 10^ ... the digit sum can't be greater than 9x10^5, and then can't be bigger than 54 and then one more ... So, since the number of spells can be at most 4, first find digit sum on the string and then use the normal digit sum function. Single digit numbers require 0 spells. ------------------------------------------ if(number[1] != '\0') { for(i = 0; number[i] != '\0'; i++) digit_sum += (number[i] - '0'); no_of_spells = 1; while(digit_sum >= 10) { no_of_spells++; digit_sum = find_digit_sum(digit_sum); } } ================================================ FILE: Explanations/Explanations - 8/T Primes Alternate Solution Explanation.txt ================================================ Last time I maintained a set so the complexity was O(D log log D + N log S), D = 1e6, N is the number of queries and S is the size of the set. Now I just maintained a vector ... Checked if the query is a perfect square and if that square root is prime. O(D log log D + T), where T is the complexity of finding square root ... This was much faster ... Probably because it was quicker to find the square root than a tree query. --------------------------------------------------------- vector is_prime(1000000 + 1, true); void precompute_prime_squares() { is_prime[0] = is_prime[1] = false; for(int i = 2; i <= 1e6; i++) if(is_prime[i]) for(int multiple = 2*i; multiple <= 1e6; multiple += i) is_prime[multiple] = false; } int main() { int no_of_queries; scanf("%d", &no_of_queries); precompute_prime_squares(); for(int i = 1; i <= no_of_queries; i++) { long long number, root; scanf("%I64d", &number); root = (int) sqrt(number); printf(root*root == number && is_prime[root] ? "YES\n" : "NO\n"); } return 0; } ================================================ FILE: Explanations/Explanations - 8/T Primes Explanation.txt ================================================ A number is said to be T prime if it has three positive divisors... Given a number upto 10^12, say if it is a T prime... ------------------------------------- The only numbers which have an odd number of divisors are perfect squares. If it has three divisors, then it means that T primes are squares of prime numbers ... Here's what I did ... Did Sieve of Erathosthenes to find all primes up to 1e6 ... Maintained a set of all the square primes ... Checking the count of a set is O(log N), where N is the size of a set ... I looked at some other approaches ... People used optimised IO ... putchar and such ... Precomputed primes up to 1e6 ... Input N, M = int sqrt(M) ... If M*M = N & is_prime(M) ... YES This seems to have less time complexity because the query is answered in O(1) time once we know the square root as opposed to log(N) time ... But, I didn't use this because I am uncomfortable with the behaviour of any floating point functions .. I don't know what exactly sqrt does ... Rounding off may cause errors. Also, calculating the square of a number is much easier than calculating it's square root ... So, that solution is O(N log log N + T), where T is the time taken to find the square root of a number. Mine is O(N log log N + log N), because of the time taken to query the count of an element in a set ... (balanced tree). ------------------------------------------------------------ set prime_square; void precompute_prime_squares() { vector is_prime(1000000 + 1, true); for(int i = 2; i <= 1e6; i++) { if(is_prime[i]) { prime_square.insert(i*1LL*i); for(int multiple = 2*i; multiple <= 1e6; multiple += i) is_prime[multiple] = false; } } } int main() { int no_of_queries; scanf("%d", &no_of_queries); precompute_prime_squares(); for(int i = 1; i <= no_of_queries; i++) { long long number; scanf("%I64d", &number); printf(prime_square.count(number) == 1 ? "YES\n" : "NO\n"); } return 0; } ================================================ FILE: Explanations/Explanations - 8/Wet Shark and Odd and Even Explanation.txt ================================================ Today, Wet Shark is given n integers. Using any of these integers no more than once, Wet Shark wants to get maximum possible even (divisible by 2) sum. Please, calculate this value for Wet Shark. Note, that if Wet Shark uses no integers from the n integers, the sum is an even integer 0. ------------------------------------------------- If sum is odd, subtract the smallest odd number ... Else, the sum is the answer. min_odd_number = 1e9 + 1; for(int i = 1; i <= number_of_elements; i++) { scanf("%d", &number_i); sum += number_i; if(number_i%2 == 1) min_odd_number = min(min_odd_number, number_i); } printf("%I64d\n", sum%2 == 0 ? sum : sum - min_odd_number); ================================================ FILE: Explanations/Explanations - 8/Yarslav and Permutations Explanation.txt ================================================ Yaroslav has an array that consists of n integers. In one second Yaroslav can swap two neighboring array elements. Now Yaroslav is wondering if he can obtain an array where any two neighboring elements would be distinct in a finite time. Help Yaroslav. ---------------------------------------------------- We cannot stop two numbers from being placed next to each other if one of them occurs more than ceil(n/2) times. We can prove this using the pigonehole principle .... If n is even, there are n adjacent pairs ... If one element occurs more than n/2 times, there must be one pair with both it's elements being the same. If n is odd, then there are n adjacent pairs and the last element ... So, if n occurs more than n/2 + 1 times, a same-pair can't be avoided. Also, it is easy to see that if there is an element that occurs more than n/2 times, it must be the most frequent element ... And if the most frequent element doesn't occur n/2 times, none of them do ! I used a hash-map for this one ... While inserting an element into the map, first it checks if a node with the key exists ... If it doesn't exist, a node with the key value is created initialised to 0. Then, we increment it. While accessing the elements of the map, first create an iterator of map .. iterator goes from .begin() to end() .. These are references. Compare the frequency to it->second ... Because the second is the value, the first is the key ... In our case, the second is the frequency, the first is the element. -------------------------------- int main() { int number_of_elements, element_i; scanf("%d", &number_of_elements); map frequency; for(int i = 1; i <= number_of_elements; i++) { scanf("%d", &element_i); frequency[element_i]++; } int max_frequency = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) max_frequency = max(max_frequency, it->second); int half_size = number_of_elements/2 + number_of_elements%2; printf(max_frequency > half_size ? "NO\n" : "YES\n"); return 0; } ================================================ FILE: Explanations/Explanations - 9/Appleman and Toastman Explanation.txt ================================================ Appleman and Toastman play a game. Initially Appleman gives one group of n numbers to the Toastman, then they start to complete the following tasks: Each time Toastman gets a group of numbers, he sums up all the numbers and adds this sum to the score. Then he gives the group to the Appleman. Each time Appleman gets a group consisting of a single number, he throws this group out. Each time Appleman gets a group consisting of more than one number, he splits the group into two non-empty groups (he can do it in any way) and gives each of them to Toastman. After guys complete all the tasks they look at the score value. What is the maximum possible value of score they can get? -------------------------------------------------------- Here's the best strategy. Sort the elements a1 < a2 < ... < an. The idea is to choose as many large sums as many times as possible. an is the largest element ... So, we try to choose it as many times as possible. ---------------------------------------- a1 + a2 + ... + an. Lose the smallest element a2 + ... + an a3+..+ an an. We can see that an is a part of n different sums so an gets counted n times to the score. Consider another element not an ... Say, ap, p < n a1 + a2 + ... ap + ... + an a2 + ... ap + ... + an ap + .... + an ap is a part of p different groups ... It gets counted one more time as a single ton element ... So, it gets counted p + 1 times. Every element is counted i + 1 times, except the last element which is only counted i times. This is because the sum starting at ai, and the singleton ai are the same sum for an. ------------------------------------------------- int main() { int no_of_groups; long long answer = 0; scanf("%d", &no_of_groups); vector group(no_of_groups + 1, 0); for(int i = 1; i <= no_of_groups; i++) { scanf("%d", &group[i]); } sort(all(group)); for(unsigned int i = group.size() - 1; i >= 1; i--) { int no_of_times_i_is_counted = (i == group.size() - 1 ? i : i + 1); answer += no_of_times_i_is_counted*1LL*group[i]; } printf("%I64d\n", answer); return 0; } ------------------------------- Wasn't as easy as it looks ... Then I realised it's A for div 1, and C for div 2 ! That explains a lot ! Anyway, good problem ... I enjoy problems which take advantage of double counting .. .It's hard to iterated each sum ... But easy to count number of sums each element is a part of. ================================================ FILE: Explanations/Explanations - 9/Bear and Five Cards Explanation.txt ================================================ A little bear Limak plays a game. He has five cards. There is one number written on each card. Each number is a positive integer. Limak can discard (throw out) some cards. His goal is to minimize the sum of numbers written on remaining (not discarded) cards. He is allowed to at most once discard two or three cards with the same number. Of course, he won't discard cards if it's impossible to choose two or three cards with the same number. Given five numbers written on cards, cay you find the minimum sum of numbers on remaining cards? ------------------------------------------------ Since the constraints are quite small, I thought of maintaining a frequency table up to 100 and then going downwards and taking out the first element possible. Then, I realised there might be a conflict ... For example, we may have a hoice of taking out 2 30s or 3 25s ... Going downwards and taking out the first choice might not be optimal. You need to keep track of the maximum sum subtracted. I chose to do it with a map. It is maintained as a balanced tree underneath. To find the minimum amount, it will only take five iterations, at most, instead of 100 like the table. Go through each entry of the map ... If it's frequency is greater than 1, check the amount that can be subtracted - either 2n or 3n, depending on it's frequency. Compare it with the overall maximum amount that can be subtracted. An advantage of map is that it would still work efficieintly if the card number went up to 1e18 ... It will only take O(n) worst case processing, where n is the number of cards. We already have the array sum because it was calculated along with the input. Subtract the maximum subtractable amount from the sum and display it. Ensure it is initialised to 0. -------------------------------------------------- int main() { map frequency; const int no_of_cards = 5; int sum = 0; for(int i = 1; i <= no_of_cards; i++) { int card_i; scanf("%d", &card_i); sum += card_i; frequency[card_i]++; } int max_subtracted = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { int number_i = it->first; int frequency_i = it->second; int subtracted_amount = 0; if(frequency_i > 1) { subtracted_amount = (frequency_i > 2 ? 3*number_i : 2*number_i); } max_subtracted = max(max_subtracted, subtracted_amount); } printf("%d\n", sum - max_subtracted); return 0; } --------------------------------- STL is so powerful. Hash table implemented as balanced trees make everything so easy and efficient. ================================================ FILE: Explanations/Explanations - 9/Bus to Udayland Explanation.txt ================================================ ZS the Coder and Chris the Baboon are travelling to Udayland! To get there, they have to get on the special IOI bus. The IOI bus has n rows of seats. There are 4 seats in each row, and the seats are separated into pairs by a walkway. When ZS and Chris came, some places in the bus was already occupied. ZS and Chris are good friends. They insist to get a pair of neighbouring empty seats. Two seats are considered neighbouring if they are in the same row and in the same pair. Given the configuration of the bus, can you help ZS and Chris determine where they should sit? ------------------------------------------------------------- Simple implementation error ... I got a run time error because I embarassingly interchanged the rows and columns while declaring the matrix ... Rows come first ! lol. int main() { char bus_seating[MAX_ROWS][ROW_LENGTH]; int no_of_rows; scanf("%d", &no_of_rows); bool can_sit_together = false; for(int i = 0; i < no_of_rows; i++) { scanf("%s", bus_seating[i]); if(bus_seating[i][0] == 'O' && bus_seating[i][1] == 'O' && can_sit_together == false) { bus_seating[i][0] = bus_seating[i][1] = '+'; can_sit_together = true; } if(bus_seating[i][3] == 'O' && bus_seating[i][4] == 'O' && can_sit_together == false) { bus_seating[i][3] = bus_seating[i][4] = '+'; can_sit_together = true; } } if(can_sit_together) { printf("YES\n"); for(int i = 0; i < no_of_rows; i++) printf("%s\n",bus_seating[i]); } else { printf("NO\n"); } return 0; } ================================================ FILE: Explanations/Explanations - 9/Circle Line Explanation.txt ================================================ -------------------------------------------------- Between any two stations there are two routes ... One forward, and the other roundabout. Find both value and give the minimum ... Be careful about incrementing i to ensure it behaves like a circle. If i has reached n, the next value of i is 1. Otherwise it is i+1. --------------------------------------------- int main() { int no_of_stations, start, destination; scanf("%d", &no_of_stations); vector distance(no_of_stations + 1); for(int i = 1; i <= no_of_stations; i++) scanf("%d", &distance[i]); scanf("%d %d", &start, &destination); int straight_distance = 0; for(int i = start; i != destination; i = (i == no_of_stations ? 1 : i + 1)) straight_distance += distance[i]; int round_distance = 0; for(int i = destination; i != start; i = (i == no_of_stations ? 1 : i + 1)) round_distance += distance[i]; printf("%d\n", min(straight_distance, round_distance)); return 0; } ================================================ FILE: Explanations/Explanations - 9/Crazy Computer Explanation.txt ================================================ Simple implementation ... int main() { int no_of_words, minute_i, maximum_break; scanf("%d %d", &no_of_words, &maximum_break); int previous_minute = 0, no_of_words_on_screen = 0; for(int i = 1; i <= no_of_words; i++) { scanf("%d", &minute_i); no_of_words_on_screen = (minute_i - previous_minute <= maximum_break ? no_of_words_on_screen + 1 : 1); previous_minute = minute_i; } printf("%d\n", no_of_words_on_screen); return 0; } ================================================ FILE: Explanations/Explanations - 9/Crossword Solving Explanation.txt ================================================ ---------------------------------------------------- I thought there was a smarter and slicker solution than taking the smaller string, placing it at every allowable index and counting and keeping track of number of changes. I almost gave up and decided to code the brute force approach because I saw it would pass the time limit. In fact, the 'brute force' approach was the answer itself ! It would have been simpler and more believeable if I had known that it is possible to copy one vector to another ... I had solved this question using boolean vectors first. And keeping track of changes at every iteration. There's a simpler and cleaner way. I learnt how to use clear() on a vector. Also, v1 = v2, copies v2 into v1, and v1 now has v2's size. Compare at every allowable index and push all changes into a vector ... Compare the size of this vector with the minimum change vector, If change. size() < minimum change.size(), minimum_change = change ... Simple as that ...No need of re-initialising an entire vector. --------------------------------------------------------- Initially, size of change is m + 1, so anything replaces it. Remember clearing current change every iteration or it will just grow. ----------------------------------------------------------------- int main() { int key_length, text_length; char key[MAX_LENGTH], text[MAX_LENGTH]; scanf("%d %d %s %s", &key_length, &text_length, key, text); vector change(key_length + 1); vector current_change; for(int i = 0; i + key_length <= text_length ; i++) { current_change.clear(); for(int j = 0; j < key_length; j++) { if(key[j] != text[i + j]) { current_change.push_back(j); } } if(current_change.size() < change.size()) { change = current_change; } } printf("%u\n", change.size()); if(change.size() > 0) { for(unsigned int i = 0; i < change.size(); i++) printf("%d ", change[i] + 1); } return 0; } ================================================ FILE: Explanations/Explanations - 9/Divisibility Explanation.txt ================================================ Find the number of numbers that are divisible by k in [a, b] ... a and b can be negative and fit into 64 bit data type. ----------------------------------------------------------------------- If a and b are on different sides of the number line, then the number of factors is = b/k + a/k + 1... Note that we are adding and not (a-1)/k, but a/k. We want to add all factors from 0 to b and from 0 to -a ... We add 1 to ensure 0 is also included in the total. If they are on the same side of the number line, assume without loss of generality that they are both positive, no of factors = b/k - (a -1)/k ... However, this gave me an error ... If k = 1 and a = 0, the the answer is b/1 - (0-1)/1 = b + 1 ... It shouldn't be + 1 .. The idea is that we are discounting all multiples of k before a ... But when it is 1, then -1/1 = -1 ... Any other number gives -1/n = 0 ... This creates an error. To simplify things, if a = 0, answer = b/k + 1 ... all of k's multiples including 0. Otherwise, answer = b/k - (a-1)/k. --------------------------------------------------------------------- int main() { long long k, left, right, no_of_multiples = 0; scanf("%I64d %I64d %I64d", &k, &left, &right); if(right > 0 && left < 0) { left = abs(left); no_of_multiples = (right)/k + (left)/k + 1; //Add 0 as a multiple as well. } else { long long greater_limit = max(abs(right), abs(left)); long long lower_limit = min(abs(right), abs(left)); if(lower_limit == 0) { no_of_multiples = (greater_limit)/k + 1; //Count 0 as well } else { no_of_multiples = (greater_limit)/k - (lower_limit - 1)/k; } } printf("%I64d\n", no_of_multiples); return 0; } ================================================ FILE: Explanations/Explanations - 9/Fox and Number Game Explanation.txt ================================================ Fox Ciel is playing a game with numbers now. Ciel has n positive integers: x1, x2, ..., xn. She can do the following operation as many times as needed: select two different indexes i and j such that xi > xj hold, and then apply assignment xi = xi - xj. The goal is to make the sum of all numbers as small as possible. Please help Ciel to find this minimal sum. ----------------------------------------------- gcd(a, b) = gcd(a, b - a) ... Ultimately, all numbers are equal to their gcd. The gcd is invariant. Sum is n*gcd. ------------------------------ int main() { int no_of_elements, element_i, array_gcd; scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &element_i); array_gcd = (i == 1 ? element_i : gcd(array_gcd, element_i)); } printf("%d\n", array_gcd*no_of_elements); return 0; } ================================================ FILE: Explanations/Explanations - 9/Haiku Explanation.txt ================================================ Haiku is a genre of Japanese traditional poetry. A haiku poem consists of 17 syllables split into three phrases, containing 5, 7 and 5 syllables correspondingly (the first phrase should contain exactly 5 syllables, the second phrase should contain exactly 7 syllables, and the third phrase should contain exactly 5 syllables). A haiku masterpiece contains a description of a moment in those three phrases. Every word is important in a small poem, which is why haiku are rich with symbols. Each word has a special meaning, a special role. The main principle of haiku is to say much using a few words. To simplify the matter, in the given problem we will consider that the number of syllable in the phrase is equal to the number of vowel letters there. Only the following letters are regarded as vowels ----------------------------------- Problem is pretty simple, by itself but learnt a couple of things in implementation. First of all, couldn't use scanf because I want the spaces too. Was going to use gets, then learnt that gets causes buffer overflow and in turn undefined behaviour because it doesn't know how many bytes to read. If it has buffer 2048, and input is 4096 there will be an overflow and unexpected behaviour. It is safer to use fgets ... Fgets also keeps track of newline and stores it into the string. Read from standard input. ----------------------------------------------- int main() { bool is_haiku = true; char line[MAX_LENGTH]; const int no_of_lines = 3; for(int i = 1; i <= no_of_lines; i++) { int vowel_count = 0; fgets(line, MAX_LENGTH, stdin); for(int letter = 0; line[letter] != '\n'; letter++) vowel_count += is_vowel(line[letter]); if(i == 2) { if(vowel_count != 7) is_haiku = false; } else { if(vowel_count != 5) is_haiku = false; } } printf(is_haiku ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 9/Is your Horseshow on the Other Hoof Explanation.txt ================================================ Simple implementation... Count frequency of each hoof. The strategy is to use 1 hoof of a particular colour and throw away the rest. int main() { map frequency; int hoof_i, no_of_hooves = 4; for(int i = 1; i <= no_of_hooves;i++) { scanf("%d", &hoof_i); frequency[hoof_i]++; } int no_of_new_hooves = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { int frequency_i = it->second; no_of_new_hooves += frequency_i - 1; //Keep one copy and throw the rest } printf("%d\n", no_of_new_hooves); return 0; } ================================================ FILE: Explanations/Explanations - 9/K-th Divisor Explanation.txt ================================================ Find the k-th factor of N or find that it doesn't exist. --------------------------------------------------------------- There are two approaches to this. Go from i = 1 to root(n) ... If i is a factor, store i and n/i in a vector. Sort the vector in the end. Display v[k - 1] (since vector is 0-indexed). I didn't want to do this since it had sorting and it's not entirely necessary. 1. Go from i = 1 to root(n). Store all the factors till root(n). 2. Let us suppose we have x factors ... If n is a perfect square, then we have 2x - 1 factors, otherwise, there are 2x factors. 3. If k > no of factors, answer = -1. 4. Else, if k <= x, answer is V[k - 1], since vector is 0-indexed. 5. If k > x, then it means answer is N/V[no_of_factors - k] ... The first factor from the end is linked to the first factor from the start. 1 ... no_of_factors 2 ... no_of_factors - 1 3 ... no_of_factors - 2 . . Their sum is invariant = no_of_factors + 1, So, if N has f factors in total, and the k-th factor is greater than it's square root, it is N/V[f - k - 1] ... Since, our vector is 0-indexed, we may omit the -1. (Because k + k' = f - 1, where the k and k' factor multiply to give N) This approach is much superior to the other approach ... (Difference of about 400 ms) This is O(root(N)) ... That is O(root(N) + S log S), where S is the number of factors. This is more memory efficient too because the vector can be int and doesn't need to be long. I was getting a TLE here ... That wasn't because of the algorithm ... In the loop, I didn't type cast i ... so while i itself will always fit into 32 bit type, i*i will cause an overflow, and the condition i*i <= n will never be false if the overflow isn't caught. In short, store all the factors of N from 1 till root(n) Get the number of factors. If k > f, answer = -1, Else if k < root(n), answer = V[k - 1] Else answer = V[f - k] ------------------------------------------------------------------------ int main() { long long num, answer; unsigned int k, max_number_of_divisors; scanf("%I64d %d", &num, &k); vector divisors; for(int i = 1; i*1LL*i <= num; i++) if(num%i == 0) divisors.push_back(i); max_number_of_divisors = 2*divisors.size(); if(divisors.back()*1LL*divisors.back() == num) max_number_of_divisors--; //Square root gets counted twice if(k > max_number_of_divisors) { answer = -1; } else { if(k <= divisors.size()) answer = divisors[k - 1]; else answer = num/divisors[max_number_of_divisors - k ]; } printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations - 9/Kitahara Haruki's Gift Explanation.txt ================================================ itahara Haruki has bought n apples for Touma Kazusa and Ogiso Setsuna. Now he wants to divide all the apples between the friends. Each apple weights 100 grams or 200 grams. Of course Kitahara Haruki doesn't want to offend any of his friend. Therefore the total weight of the apples given to Touma Kazusa must be equal to the total weight of the apples given to Ogiso Setsuna. But unfortunately Kitahara Haruki doesn't have a knife right now, so he cannot split any apple into some parts. Please, tell him: is it possible to divide all the apples in a fair way between his friends? ------------------------------------------ This problem is really simple, but I still made two mistakes. First my approach ... Notice that the only way to make a matching in between the two families is 1 200 = 2 100. So, we divide 200s into 2 as far as we can. We will be left either with 1 200 or 0 200 ... If there is 1, use 2 100s to balance it out and then check if there are an even number of 100s left. If there are 0 200s, just check if the number of 100s is even. I made a mistake ... I didn't check if the number of 100s is positive .... For example, if there's one 100 and 3 200s .. 1 200 will be left. If we use 2 100s to balance it, we will have -1 100, which is not possible.... So, check if we have non negative no of 100s after it's over. Also, by mistake I reduced no of 100s by 2 regardless ... This gives WA for 200 200 ... It is balanced out but if I still subtract 2 100s, I will have negative 100s. Subtract by 2*(no_of_200s) Those were the two bugs - check if there are non negative 100s at the end and also subtract 2 only if there is an outstanding 200 weight. ----------------------------------------- int main() { int no_of_apples, weight_i; scanf("%d", &no_of_apples); int no_of_100s = 0, no_of_200s = 0; for(int i = 1; i <= no_of_apples; i++) { scanf("%d", &weight_i); no_of_100s += (weight_i == 100); no_of_200s += (weight_i == 200); } no_of_200s = (no_of_200s%2); //Distribute half of them to either group. no_of_100s = no_of_100s - 2*no_of_200s; //Balancing out the 200 - there may be 1 or 0 printf(no_of_100s%2 == 0 && no_of_100s >= 0 ? "YES\n" : "NO\n"); //check if remaining 100s can be divided in half. return 0; } ================================================ FILE: Explanations/Explanations - 9/Little Elephant and Function Explanation.txt ================================================ The Little Elephant enjoys recursive functions. This time he enjoys the sorting function. Let a is a permutation of an integers from 1 to n, inclusive, and ai denotes the i-th element of the permutation. The Little Elephant's recursive function f(x), that sorts the first x permutation's elements, works as follows: If x?=?1, exit the function. Otherwise, call f(x?-?1), and then make swap(ax?-?1,?ax) (swap the x-th and (x?-?1)-th elements of a). The Little Elephant's teacher believes that this function does not work correctly. But that-be do not get an F, the Little Elephant wants to show the performance of its function. Help him, find a permutation of numbers from 1 to n, such that after performing the Little Elephant's function (that is call f(n)), the permutation will be sorted in ascending order. ------------------------------------------------------- Important to have some understanding of recursive stackframes for this one. At first I thought it first swaps, ax and a(x-1) and then calls f(x - 1). In that case the answer is a sorted array, rotated one place to the left. Like, 2 3 4 1 Because every swap will - 2 3 1 4, 2 1 3 4 and finally 1 2 3 4 ... The order of elements doesn't change ... The smallest element goes to the first position. But, this is wrong. What happens is that it first calls f(x-1), f(x-2) ... and so on till it reaches f(1) and then starts swapping. So, in other words starting from position 2 till n, ai and a(i - 1) are swapped. In this case, the answer is a sorted array rotated one place to the RIGHT. the order of elements doesn't change this way ... The first element occupies the last position. 4 1 2 3, 1 4 2 3, 1 2 4 3 and finally 1 2 3 4. ----------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); printf("%d ", no_of_elements); for(int i = 1; i < no_of_elements; i++) printf("%d ", i); return 0; } ================================================ FILE: Explanations/Explanations - 9/Little Elephant and Problem Explanation.txt ================================================ The Little Elephant has got a problem somebody has been touching his sorted by non-decreasing array a of length n and possibly swapped some elements of the array. The Little Elephant doesn't want to call the police until he understands if he could have accidentally changed the array himself. He thinks that he could have accidentally changed array a, only if array a can be sorted in no more than one operation of swapping elements (not necessarily adjacent). That is, the Little Elephant could have accidentally swapped some two elements. Help the Little Elephant, determine if he could have accidentally changed the array a, sorted by non-decreasing, himself. ------------------------------------------------------- Sort the array and check how many positions differ with the original array. int main() { int no_of_elements; scanf("%d", &no_of_elements); vector original_array(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original_array[i]); vector sorted_array = original_array; sort(all(sorted_array)); int differences = 0; for(int i = 0; i < no_of_elements; i++) differences += (sorted_array[i] != original_array[i]); printf(differences <= 2 ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations - 9/New Year and Days Explanation.txt ================================================ Today is Wednesday, the third day of the week. What's more interesting is that tomorrow is the last day of the year 2015. Limak is a little polar bear. He enjoyed this year a lot. Now, he is so eager to the coming year 2016. Limak wants to prove how responsible a bear he is. He is going to regularly save candies for the entire year 2016! He considers various saving plans. He can save one candy either on some fixed day of the week or on some fixed day of the month. Limak chose one particular plan. He isn't sure how many candies he will save in the 2016 with his plan. Please, calculate it and tell him. ----------------------------------------------------- A simple problem, of course ... I found an elegant way of checking conditions. Dec 30 is Wed ... 31st is Thurs ... 1st is Friday ... Since 2016, is a leap year it will end two days after Jan 1st instead of one. So, it ends on Sat ... There is one extra Fri and Sat. Also, scanf only reads a string till it encounters a whitespace so I used two of them ... made things easier... No need to use string comparison to identify time period. -------------------------------------------------------- int main() { int savings = 0, date; char of[2 + 1], time_period[MAX_TIME_LENGTH]; scanf("%d %s %s", &date ,of, time_period); //Scanf reads a string till it encounters a whitespace ... so I used two strings. if(time_period[0] == 'm') //Month { savings = 12*(date <= 29) + 11*(date == 30) + 7*(date == 31); //Only one of these can be true. } else if(time_period[0] == 'w') //Week { savings = 52 + (date == 5 || date == 6); // Days 6 and 7 occur one more time } printf("%d\n", savings); return 0; } ------------------------------------------------------------ The way savings is written looks like an equation in vector algebra with all the relational expressions resembling dimensions ... Only of the dimensions is true at a time for month, and for the day ... only 5 and 6 have an extra day. ================================================ FILE: Explanations/Explanations - 9/One Dimensional Japanese Crossword Explanation.txt ================================================ -------------------------------------- Go through the string .. Whenever a B is encountered, count the subsegment of Bs. int main() { int no_of_blocks, segment_length; char crossword[MAX_LENGTH]; scanf("%d %s", &no_of_blocks, crossword); vector black_segment_length; for(int i = 0; i < no_of_blocks; i += segment_length + 1) { segment_length = 0; while(crossword[i + segment_length] == 'B') { segment_length++; } if(segment_length > 0) black_segment_length.push_back(segment_length); } printf("%u\n", black_segment_length.size()); for(unsigned int i = 0; i < black_segment_length.size(); i++) printf("%d ",black_segment_length[i]); return 0; } ================================================ FILE: Explanations/Explanations - 9/Present from Lena Explanation.txt ================================================ -------------------------------------- These pattern printing problems are pretty interesting ... The idea is to divide the pattern into many triangles. Also, have another loop for printing spaces. Here, for some reason, they didn't want a space at the end of a line ... That made the code a bit harder to read but I wasn't getting AC when there was a space. ------------------------------------- int main() { int n; scanf("%d", &n); for(int row = 0; row <= n; row++) { for(int space = 0; space < n - row; space++) printf(" "); for(int number = 0; number <= row; number++) if(row == 0) printf("%d", number); else printf("%d ", number); for(int number = row - 1; number >= 0; number--) if(number == 0) printf("%d", number); else printf("%d ", number); printf("\n"); } for(int row = n - 1; row >= 0; row--) { for(int space = 0; space < n - row; space++) printf(" "); for(int number = 0; number <= row; number++) if(row == 0) printf("%d", number); else printf("%d ", number); for(int number = row - 1; number >= 0; number--) if(number == 0) printf("%d", number); else printf("%d ", number); printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations - 9/Prime Matrix.txt ================================================ You've got an n × m matrix. The matrix consists of integers. In one move, you can apply a single transformation to the matrix: choose an arbitrary element of the matrix and increase it by 1. Each element can be increased an arbitrary number of times. You are really curious about prime numbers. Let us remind you that a prime number is a positive integer that has exactly two distinct positive integer divisors: itself and number one. For example, numbers 2, 3, 5 are prime and numbers 1, 4, 6 are not. A matrix is prime if at least one of the two following conditions fulfills: the matrix has a row with prime numbers only; the matrix has a column with prime numbers only; Your task is to count the minimum number of moves needed to get a prime matrix from the one you've got. ---------------------------------------------- Learnt how to implement a matrix as a vector of vectors ... Also, learnt that it's not recommended in real life applications but fine in competitive programming. vector > matrix(no_of_rows, vector (no_of_columns, 0) ) Important to put a space in between the > ... vector is the type of the vector and it is allocated, no_of_columns copies of vector s. -------------------------------------- Used a sieve ... Got a runtime error because I made a mistake in the inner loop of the sieve ... Used an i. Here's what I did ... Precomputed all primes till 1e5 + 3. Made another vector called prime_distance ... where prime_distance[i] contains the minimum number which needs to be added to get to a prime number. To get it .. Start at i = 1e5 + 3 and go down to 0 ... Keep track of the latest prime encountered and prime_distance[i] = latest prime - i. ------------------------- vector prime_distance(1e5 + 4); void precompute_prime_distance() { vector is_prime(1e5 + 10, true); is_prime[0] = is_prime[1] = false; for(int i = 2; i <= 1e5 + 3; i++) { if(is_prime[i]) { for(int multiple = 2*i; multiple <= 1e5 + 3; multiple += i) { is_prime[multiple] = false; } } } int last_prime; for(int i = 1e5 + 3; i >= 0; i--) if(is_prime[i]) last_prime = i; prime_distance[i] = last_prime - i; } } ------------------------------------------ While reading the matrix ... STore prime_distance[i][j] in [i][j]. After that find the minimum row and column sum. ------------------------------------------- int main() { const int INFINITY = 1e9 + 1; int no_of_rows, no_of_columns; scanf("%d %d", &no_of_rows, &no_of_columns); precompute_prime_distance(); vector > matrix(no_of_rows, vector (no_of_columns) ); for(int row = 0; row < no_of_rows; row++) { for(int column = 0; column < no_of_columns; column++) { int element; scanf("%d", &element); matrix[row][column] = prime_distance[element]; } } int min_row_sum = INFINITY; for(int row = 0; row < no_of_rows; row++) { int row_sum = 0; for(int column = 0; column < no_of_columns; column++) { row_sum += matrix[row][column]; } min_row_sum = min(min_row_sum, row_sum); } int min_column_sum = INFINITY; for(int column = 0; column < no_of_columns; column++) { int column_sum = 0; for(int row = 0; row < no_of_rows; row++) { column_sum += matrix[row][column]; } min_column_sum = min(min_column_sum, column_sum); } printf("%d\n",min(min_row_sum, min_column_sum)); return 0; } ================================================ FILE: Explanations/Explanations - 9/String Task Explanation.txt ================================================ -------------------------------------- The only trick of this problem is that y is also considered a vowel. I didn't know how many bytes the STL string allocates so I used both STL string and C string. int main() { char initial_string[MAX_LENGTH]; string answer; scanf("%s", initial_string); for(int i = 0; initial_string[i] != '\0'; i++) { if(is_vowel(to_lower(initial_string[i])) == false) { answer += '.'; answer += to_lower(initial_string[i]); } } cout << answer << "\n"; return 0; } ================================================ FILE: Explanations/Explanations - 9/Subtractions Explanation.txt ================================================ -------------------------------------- This is another way of asking the number of steps to find the GCD using the Euclidean algorithm. I used static variables here ! Static vriables retain their value through a recursive function call ... Static variables are useful to measure recursion depth and collect meta-data about the recursion. All recursive calls use the same instance of data. Using a static variable would be fine if there was only one query. But, here there are many queries, and the static variable doesn't start at 0 for each query. It starts at the value the last query ended. So, better to just write a simply non-tail recursive function. ----------------------------------------------- int no_of_steps_in_finding_gcd(int a, int b) { int m = min(a, b); int n = max(a, b); if(m == 0) return 0; else return n/m + no_of_steps_in_finding_gcd(m, n%m); } void solve() { int a, b; scanf("%d %d", &a, &b); printf("%d\n", no_of_steps_in_finding_gcd(a, b) ); } ------------------------------ ================================================ FILE: Explanations/Explanations - 9/Toy Army Explanation.txt ================================================ The hero of our story, Valera, and his best friend Arcady are still in school, and therefore they spend all the free time playing turn-based strategy "GAGA: Go And Go Again". The gameplay is as follows. There are two armies on the playing field each of which consists of n men (n is always even). The current player specifies for each of her soldiers an enemy's soldier he will shoot (a target) and then all the player's soldiers shot simultaneously. This is a game world, and so each soldier shoots perfectly, that is he absolutely always hits the specified target. If an enemy soldier is hit, he will surely die. It may happen that several soldiers had been indicated the same target. Killed soldiers do not participate in the game anymore. The game "GAGA" consists of three steps: first Valera makes a move, then Arcady, then Valera again and the game ends. You are asked to calculate the maximum total number of soldiers that may be killed during the game. ------------------------------------------------------- This is one of those problems that's a lot harder to prove than to code ... To maximise the number of killed soldiers, both sides will have to kill as many soldiers as possible ... Notice that if there were only 2 turns, then n soldiers will always be killed no matter what. Proof - If the first side kills all n soldiers on it's turn, then n soldiers are killed and there are no alive soldiers on the other side for turn 2. If the first side kills k soldiers, .... then the n-k surviving soldiers will all kill 1 soldiers each. They have to do this because they only get 1 turn. So, number of soldiers dead after 2 turns = k + (n - k) = n. -------------------------------- Now, on turn 3 ... the number of soldiers killed has to be maximised ... This is the strategy that needs to be optimised... For this, side 1 has to kill half of side 2's soldiers on it's first turn... IF side 1 kills less than half of their soldiers ... Then after all of side 2's soldiers kill a soldier ... side 1 will not have enough soldiers to completely kill side 1. If they killed more than half of their soldiers, then after two turns it would be n + r ... r < n/2 [r is all the people killed on turn 3 - survivors of side 1] ... The way to maximise r is to set r = n/2. If r is greater, we get a less than optimal result. --------------------------------------------- Ans = n + n/2 = 3n/2 ... if n is even ... If n is odd then n/2 is rounded off to the higher side ... ------------------------------------------ int main() { int number_of_soldiers, killed; scanf("%d", &number_of_soldiers); killed = 3*((number_of_soldiers + 1)/2); printf("%d\n", killed); return 0; } ================================================ FILE: Explanations/Explanations 12/Anastasia and Pebbles Explanation.txt ================================================ Anastasia loves going for a walk in Central Uzhlyandian Park. But she became uninterested in simple walking, so she began to collect Uzhlyandian pebbles. At first, she decided to collect all the pebbles she could find in the park. She has only two pockets. She can put at most k pebbles in each pocket at the same time. There are n different pebble types in the park, and there are wi pebbles of the i-th type. Anastasia is very responsible, so she never mixes pebbles of different types in same pocket. However, she can put different kinds of pebbles in different pockets at the same time. Unfortunately, she can't spend all her time collecting pebbles, so she can collect pebbles from the park only once a day. Help her to find the minimum number of days needed to collect all the pebbles of Uzhlyandian Central Park, taking into consideration that Anastasia can't place pebbles of different types in same pocket. ---------------------------------------------- First imagine that there's only one pocket ... How long will it take to pick up wi pebbles ? ceil(wi/k) ... Now we have two pockets ... No of days = ceil(no of pebbles/2) ---------------------------------------------------- int main() { int no_of_pebble_types, pebble_limit; scanf("%d %d", &no_of_pebble_types, &pebble_limit); int days_to_collect_all_pebbles = 0; for(int i = 1; i <= no_of_pebble_types; i++) { int pebble_i; scanf("%d", &pebble_i); days_to_collect_all_pebbles += pebble_i/pebble_limit + (pebble_i%pebble_limit != 0); //Ceil } days_to_collect_all_pebbles = days_to_collect_all_pebbles/2 + days_to_collect_all_pebbles%2; printf("%d\n", days_to_collect_all_pebbles); return 0; } ================================================ FILE: Explanations/Explanations 12/Bear and Three Balls Explanation.txt ================================================ Limak is a little polar bear. He has n balls, the i-th ball has size ti. Limak wants to give one ball to each of his three friends. Giving gifts isn't easy there are two rules Limak must obey to make friends happy: No two friends can get balls of the same size. No two friends can get balls of sizes that differ by more than 2. For example, Limak can choose balls with sizes 4, 5 and 3, or balls with sizes 90, 91 and 92. But he can't choose balls with sizes 5, 5 and 6 (two friends would get balls of the same size), and he can't choose balls with sizes 30, 31 and 33 (because sizes 30 and 33 differ by more than 2). Your task is to check whether Limak can choose three balls that satisfy conditions above. ---------------------------------------------------- Maintain a set of all ball numbers ... Pick up every ball and check if ball + 1, ball - 1 are also present in the set. Each count operation and insert operation occurs in log N time ... Overall complexity is O(N log N). N elements. ------------------------------ int main() { int no_of_balls; scanf("%d", &no_of_balls); set ball; for(int i = 1; i <= no_of_balls; i++) { int ball_i; scanf("%d", &ball_i); ball.insert(ball_i); } bool gift_givable = false; for(set :: iterator i = ball.begin(); i != ball.end(); i++) { int ball_i = *i; if(ball.count(ball_i + 1) == 1 && ball.count(ball_i - 1) == 1) { gift_givable = true; break; } } printf(gift_givable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 12/Co Prime Array Explanation.txt ================================================ You are given an array of n elements, you must make it a co-prime array in as few moves as possible. In each move you can insert any positive integral number you want not greater than 109 in any place in the array. An array is co-prime if any two adjacent numbers of it are co-prime. In the number theory, two integers a and b are said to be co-prime if the only positive integer that divides both of them is 1. ---------------------------------------------- This is similar to the question asking what is the smallest currency that cannot be expressed. If there is no 1, it is 1 and if 1 is there all can be expressed. Or is there an element in this array which divides every other element ? If it is yes, then it has to be the smallest element. Or what is the length of longest coprime sequence in array ? If any two elements are coprime, entire array is coprime. Here, the observation needed is that gcd(1, n) = 1. Insert all elements into the new vector, but just check if adjacent elements are coprime. If any two adjacent elements are not coprime. Insert a 1 in between. ----------------------------------------------------- int main() { int no_of_numbers; scanf("%d", &no_of_numbers); vector coprime_array; for(int i = 1; i <= no_of_numbers; i++) { int number_i; scanf("%d", &number_i); if(i == 1 || gcd(coprime_array.back(), number_i) == 1) { coprime_array.push_back(number_i); } else { coprime_array.push_back(1); coprime_array.push_back(number_i); } } int no_of_operations = coprime_array.size() - no_of_numbers; printf("%d\n", no_of_operations); for(unsigned int i = 0; i < coprime_array.size(); i++) printf("%d ", coprime_array[i]); return 0; } ================================================ FILE: Explanations/Explanations 12/Dima and Friends Explanation.txt ================================================ Dima and his friends have been playing hide and seek at Dima's place all night. As a result, Dima's place got messy. In the morning they decided that they need to clean the place. To decide who exactly would clean the apartment, the friends want to play a counting-out game. First, all the guys stand in a circle, and then each of them shows some number of fingers on one hand (one to five), and then the boys count in a circle, starting from Dima, the number of people, respective to the total number of fingers shown. The person on who the countdown stops will clean the apartment. For example, if Dima and one of his friends played hide and seek, and 7 fingers were shown during the counting-out, then Dima would clean the place. If there were 2 or say, 8 fingers shown, then his friend would clean the place. Dima knows how many fingers each of his friends will show during the counting-out. Now he is interested in the number of ways to show some number of fingers on one hand (one to five), so that he did not have to clean the place. Help Dima. ----------------------------------------------- Firstly, no of people = no of friends + 1 Dima will have to clean the apartment if the total number of fingers = 1 mod (no of people) Go from i = 1 to 5 and count how many i's when added to other fingers don't make the total 1 mod (no of people). ----------------------------------------------- int main() { int no_of_friends; scanf("%d", &no_of_friends); int other_fingers = 0; for(int i = 1; i <= no_of_friends; i++) { int finger_i; scanf("%d", &finger_i); other_fingers += finger_i; } const int NO_OF_FINGERS = 5; int no_of_choices = 0, no_of_people = no_of_friends + 1; for(int dima_fingers = 1; dima_fingers <= NO_OF_FINGERS; dima_fingers++) { int total_fingers = other_fingers + dima_fingers; no_of_choices += (total_fingers%no_of_people != 1); } printf("%d\n", no_of_choices); return 0; } ================================================ FILE: Explanations/Explanations 12/Dreamoon and Stairs Alternate Solution Explanation.txt ================================================ ----------------------------------------------------- Okay, it is established that the lower limit for number of steps = ceil(n/2) ... and upper bound is n. Let's say the lower limit, l = q.m + r, by the division algorithm, 0 <= r < m ... So the first mulitple of m greater than l will be (q + 1). m or q.m if l is a multiple of m. More succintly, it can be written as multiplier = ceil[l/m] = (l/m + (l%m != 0)) , if l is not a multiple of m, then add 1, else it is simply l/m. ceil(l/m)*m gives the smallest multiple of m greater than l. If l is a multiple of l, it returns l. Else it returns another number > l and multiple of m. Just check if the smallest multiple of m greater than l is smaller than the no of steps. ----------------------------------------------- int main() { int no_of_steps, multiple; scanf("%d %d", &no_of_steps, &multiple); int lower_limit = no_of_steps/2 + no_of_steps%2; int smallest_multiplier = lower_limit/multiple + (lower_limit%multiple != 0); int minimum_number_of_steps = smallest_multiplier*multiple; printf("%d\n", (minimum_number_of_steps <= no_of_steps ? minimum_number_of_steps : - 1)); return 0; } ================================================ FILE: Explanations/Explanations 12/Dreamoon and Stairs Explanation.txt ================================================ Dreamoon wants to climb up a stair of n steps. He can climb 1 or 2 steps at each move. Dreamoon wants the number of moves to be a multiple of an integer m. What is the minimal number of moves making him climb to the top of the stairs that satisfies his condition? --------------------------------------------------------- Establish a lower bound for the number of steps you must take - this is ceil(n/2) In this case, we take as many steps of 2 as possible and then take one last step. The number of steps cannot be less than this. The number of steps cannot be greater than the number of steps either. In that case, we take n steps of 1. The lower bound consists of all steps of 2, upper bound consists of all steps of 1. I iterated from the lower bound to the upper bound ... and in each step, replace a step of 2 by 2 steps of 1 (Increasing the number of steps by 1). Choose the first no of steps that is a multiple of m. This is O(n) ... There is an O(1) solution as well. ------------------------------------------------- int main() { int no_of_steps, multiple; scanf("%d %d", &no_of_steps, &multiple); int minimum_no_of_steps = no_of_steps/2 + no_of_steps%2; while(minimum_no_of_steps <= no_of_steps) { if(minimum_no_of_steps%multiple == 0) { break; } minimum_no_of_steps++; } printf(minimum_no_of_steps > no_of_steps ? "-1\n" : "%d\n", minimum_no_of_steps); return 0; } ================================================ FILE: Explanations/Explanations 12/Fashion in Berland Explanation.txt ================================================ According to rules of the Berland fashion, a jacket should be fastened by all the buttons except only one, but not necessarily it should be the last one. Also if the jacket has only one button, it should be fastened, so the jacket will not swinging open. You are given a jacket with n buttons. Determine if it is fastened in a right way. -------------------------------------------------------- The case where there's one button confused me. I thought one button can't be fashionable no matter what ... But, if there's one button it should be closed. --------------------------------- int main() { int no_of_buttons; scanf("%d", &no_of_buttons); int no_of_open_buttons = 0; for(int i = 1; i <= no_of_buttons; i++) { int button_i; scanf("%d", &button_i); no_of_open_buttons += (button_i == 0); } bool fashionable = (no_of_buttons > 1 && no_of_open_buttons == 1) || (no_of_buttons == 1 && no_of_open_buttons == 0); printf(fashionable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 12/Inbox (100500) Explanation.txt ================================================ Over time, Alexey's mail box got littered with too many letters. Some of them are read, while others are unread. Alexey's mail program can either show a list of all letters or show the content of a single letter. As soon as the program shows the content of an unread letter, it becomes read letter (if the program shows the content of a read letter nothing happens). In one click he can do any of the following operations: Move from the list of letters to the content of any single letter. Return to the list of letters from single letter viewing mode. In single letter viewing mode, move to the next or to the previous letter in the list. You cannot move from the first letter to the previous one or from the last letter to the next one. The program cannot delete the letters from the list or rearrange them. Alexey wants to read all the unread letters and go watch football. Now he is viewing the list of all letters and for each letter he can see if it is read or unread. What minimum number of operations does Alexey need to perform to read all unread letters? ---------------------------------------------- So, every unread letter needs to be read ... So the number of operations must be at least as many as the number of unread letters. Another observation is that switching from letter i to i + 1 takes 1 operation ... and switching from i to i + 2 ... needs 2 ... First go to big display mode and then choose 2 Whenever there are consecutive unread letters, switch in between them and use an extra move to go to big display mode when it isn't like that. We need the following information - no of unread letters and no of unread segments. We need to perform skips = 1 less than the number of unread segments. However, the special case is when there are 0 unread segments, ... the answer shouldn't be -1 ... Just add max(no of segments - 1, 0) to no of unread letters. ------------------------------ int main() { int no_of_letters; scanf("%d", &no_of_letters); int previous_letter_status = 0, no_of_unread_letters = 0, no_of_unread_segments = 0; for(int i = 1; i <= no_of_letters; i++) { int unread; scanf("%d", &unread); no_of_unread_letters += (unread == 1); if(previous_letter_status == 0 && unread == 1) no_of_unread_segments++; previous_letter_status = unread; } int no_of_operations = no_of_unread_letters + max(no_of_unread_segments - 1, 0); //Incase there are no unread segments, it should be 0 printf("%d\n", no_of_operations); return 0; } ================================================ FILE: Explanations/Explanations 12/Key Races Explanation.txt ================================================ Two boys decided to compete in text typing on the site "Key races". During the competition, they have to type a text consisting of s characters. The first participant types one character in v1 milliseconds and has ping t1 milliseconds. The second participant types one character in v2 milliseconds and has ping t2 milliseconds. If connection ping (delay) is t milliseconds, the competition passes for a participant as follows: Exactly after t milliseconds after the start of the competition the participant receives the text to be entered. Right after that he starts to type it. Exactly t milliseconds after he ends typing all the text, the site receives information about it. The winner is the participant whose information on the success comes earlier. If the information comes from both participants at the same time, it is considered that there is a draw. Given the length of the text and the information about participants, determine the result of the game. --------------------------------------------------------------------------------- int main() { int length_text, speed_1, speed_2, ping_1, ping_2; scanf("%d %d %d %d %d", &length_text, &speed_1, &speed_2, &ping_1, &ping_2); int total_time_1 = speed_1*length_text + 2*ping_1; int total_time_2 = speed_2*length_text + 2*ping_2; if(total_time_1 == total_time_2) printf("Friendship\n"); else printf(total_time_1 < total_time_2 ? "First\n" : "Second\n"); return 0; } ================================================ FILE: Explanations/Explanations 12/Lecture Explanation.txt ================================================ You have a new professor of graph theory and he speaks very quickly. You come up with the following plan to keep up with his lecture and make notes. You know two languages, and the professor is giving the lecture in the first one. The words in both languages consist of lowercase English characters, each language consists of several words. For each language, all words are distinct, i.e. they are spelled differently. Moreover, the words of these languages have a one-to-one correspondence, that is, for each word in each language, there exists exactly one word in the other language having has the same meaning. You can write down every word the professor says in either the first language or the second language. Of course, during the lecture you write down each word in the language in which the word is shorter. In case of equal lengths of the corresponding words you prefer the word of the first language. You are given the text of the lecture the professor is going to read. Find out how the lecture will be recorded in your notes. ------------------------------------------- I solved the problem more generally - I solved the problem for when the professor talks in mixed languages and output must be the shortest word of each language. Use two dictionaries ... One which maps words from first language to second language and other which maps words from second language to first language. Another boolean vector to keep track of which words are in which language. For each word, print the smaller length vector. Both solutions are included ... The one I solved first(the harder problem) and the one in which the lecture is only in the first language. -------------------------------------------------------- int main() { int length_of_sentence, no_of_words; cin >> length_of_sentence >> no_of_words; map translated; for(int i = 1; i <= no_of_words; i++) { string word, translation; cin >> word >> translation; translated[word] = translation; } for(int i = 1; i <= length_of_sentence; i++) { string current_word; cin >> current_word; cout << (current_word.length() <= translated[current_word].length() ? current_word : translated[current_word]) << " "; } return 0; } ---------------------------------------------------------------------------------------- int main() { int length_of_sentence, no_of_words; cin >> length_of_sentence >> no_of_words; map dictionary_1_to_2; map dictionary_2_to_1; map is_in_language_1; for(int i = 1; i <= no_of_words; i++) { string word, translation; cin >> word >> translation; dictionary_1_to_2[word] = translation; dictionary_2_to_1[translation] = word; is_in_language_1[word] = true; is_in_language_1[translation] = false; } for(int i = 1; i <= length_of_sentence; i++) { string current_word; cin >> current_word; string language_1_word = is_in_language_1[current_word] ? current_word : dictionary_2_to_1[current_word]; string language_2_word = (is_in_language_1[current_word] ? dictionary_1_to_2[current_word] : current_word); cout << (language_1_word.length() <= language_2_word.length() ? language_1_word : language_2_word) << " "; } return 0; } ================================================ FILE: Explanations/Explanations 12/Little Girl and Maximum Sum.txt ================================================ The little girl loves the problems on array queries very much. One day she came across a rather well-known problem: you've got an array of n elements (the elements of the array are indexed starting from 1); also, there are q queries, each one is defined by a pair of integers li, ri (1 ≤ li ≤ ri ≤ n). You need to find for each query the sum of elements of the array with indexes from li to ri, inclusive. The little girl found the problem rather boring. She decided to reorder the array elements before replying to the queries in a way that makes the sum of query replies maximum possible. Your task is to find the value of this maximum sum. --------------------------------------------------------------- Keep track of the number of times each cell is called upon in a query. Place the largest number in the cell that is queried upon the most. Place the second largest number in the cell that is queried upon the second most ... and so on. This part was easy I got a TLE first. The trick was in deciding how to mark the number of times each cell was queried. for(int i = 1; i <= no_of_queries; i++) { int left_i, right_i; scanf("%d %d", &left_i, &right_i); for(int index = left_i; index <= right_i; index++) no_of_times_index_queried[index]++; } I initially did it by brute force ... Went from li to ri for every query and incremented no of times each cell is called upon ... This is O(n^2) and doesn't pass. A better solution is to mark only li and ri in a seperate vector ... For every index only store the number of queries starting there and ending there. Then in one pass, find the number of times each cell is queried in the following way - no_of_times_queried = 0 for(i = 0; i <= n; i++) no_of_times_queried += (no_of_queries_starting[i] - no_of_queries_ending[i]) no_of_times_queried[i] = no_of_times_queried This is similar to a problem asking about trains coming and going on platforms ... What is the maximum number of trains that will exist at the same time ? There too .. Keep track of the end points of arrival and leaving only and then no of trains at a given point of time changes by the number of trains that have arrived then and decreases by the number of trains that have left then. ------------------------------------------------------------------------- int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector element(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector no_of_queries_starting_here(no_of_elements + 1, 0); vector no_of_queries_ending_here(no_of_elements + 1, 0); for(int i = 1; i <= no_of_queries; i++) { int left_i, right_i; scanf("%d %d", &left_i, &right_i); no_of_queries_starting_here[left_i]++; if(right_i + 1 <= no_of_elements) no_of_queries_ending_here[right_i + 1]++; } int no_of_queries_on_this_index = 0; vector no_of_times_index_queried(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { no_of_queries_on_this_index += (no_of_queries_starting_here[i] - no_of_queries_ending_here[i]); no_of_times_index_queried[i] = no_of_queries_on_this_index; } sort(all(element)); sort(all(no_of_times_index_queried)); long long maximum_sum = 0; for(int i = 1; i <= no_of_elements; i++) maximum_sum += no_of_times_index_queried[i]*1LL*element[i]; printf("%I64d\n", maximum_sum); return 0; } ================================================ FILE: Explanations/Explanations 12/Santa Claus and Candies Explanation.txt ================================================ Santa Claus has n candies, he dreams to give them as gifts to children. What is the maximal number of children for whose he can give candies if Santa Claus want each kid should get distinct positive integer number of candies. Santa Class wants to give all n candies he has. ----------------------------------------------- The number of people who get gifts is equal to the greatest triangular number smaller than n. The strategy I used for distribution was for person i = 1 to p - 1, give p - 1 gifts and give all remaining gifts to the last person. -------------------------------- int main() { int no_of_gifts; scanf("%d", &no_of_gifts); int no_of_people = 1; while(no_of_people*(no_of_people + 1) <= 2*no_of_gifts) no_of_people++; no_of_people--; printf("%d\n", no_of_people); for(int i = 1; i < no_of_people; i++) { printf("%d ", i); no_of_gifts -= i; } printf("%d\n", no_of_gifts); //Last person gets all remaining gifts return 0; } ================================================ FILE: Explanations/Explanations 12/Sergey and Dima Explanation.txt ================================================ Sereja and Dima play a game. The rules of the game are very simple. The players have n cards in a row. Each card contains a number, all numbers on the cards are distinct. The players take turns, Sereja moves first. During his turn a player can take one card: either the leftmost card in a row, or the rightmost one. The game ends when there is no more cards. The player who has the maximum sum of numbers on his cards by the end of the game, wins. Sereja and Dima are being greedy. Each of them chooses the card with the larger number during his move. Inna is a friend of Sereja and Dima. She knows which strategy the guys are using, so she wants to determine the final score, given the initial state of the game. Help her. --------------------------------------- Use two pointers - one at the front and one at the end ... Add the greater card to whoever's turn it is and advance the pointer used. ------------------------------------------ int main() { int no_of_cards; scanf("%d", &no_of_cards); vector card(no_of_cards); for(int i = 0; i < no_of_cards; i++) scanf("%d", &card[i]); int sergey_sum = 0, dima_sum = 0; for(int front_i = 0, back_i = no_of_cards - 1, no_of_turns = 1; no_of_turns <= no_of_cards; no_of_turns++) { int greater_card = max(card[front_i], card[back_i]); if(card[front_i] >= card[back_i]) front_i++; else back_i--; if(no_of_turns%2 == 1) sergey_sum += greater_card; else dima_sum += greater_card; } printf("%d %d\n", sergey_sum, dima_sum); return 0; } ================================================ FILE: Explanations/Explanations 12/Sleuth Explanation.txt ================================================ Vasya plays the sleuth with his friends. The rules of the game are as follows: those who play for the first time, that is Vasya is the sleuth, he should investigate a "crime" and find out what is happening. He can ask any questions whatsoever that can be answered with "Yes" or "No". All the rest agree beforehand to answer the questions like that: if the questions last letter is a vowel, they answer "Yes" and if the last letter is a consonant, they answer "No". Of course, the sleuth knows nothing about it and his task is to understand that. Unfortunately, Vasya is not very smart. After 5 hours of endless stupid questions everybody except Vasya got bored. Thats why Vasyas friends ask you to write a program that would give answers instead of them. The English alphabet vowels are: A, E, I, O, U, Y The English alphabet consonants are: B, C, D, F, G, H, J, K, L, M, N, P, Q, R, S, T, V, W, X, Z ---------------------------------------- There are spaces so I used fgets ... Y is also a vowel here. ----------------------------------- int main() { char question[MAX_LENGTH]; fgets(question, MAX_LENGTH, stdin); bool last_letter_vowel = false; for(int i = strlen(question) - 1; i >= 0; i--) { if(is_alpha(question[i]) ) { if(is_vowel(question[i]) ) last_letter_vowel = true; break; } } printf(last_letter_vowel ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 12/The Festive Evening Explanation.txt ================================================ It's the end of July the time when a festive evening is held at Jelly Castle! Guests from all over the kingdom gather here to discuss new trends in the world of confectionery. Yet some of the things discussed here are not supposed to be disclosed to the general public: the information can cause discord in the kingdom of Sweetland in case it turns out to reach the wrong hands. So it's a necessity to not let any uninvited guests in. There are 26 entrances in Jelly Castle, enumerated with uppercase English letters from A to Z. Because of security measures, each guest is known to be assigned an entrance he should enter the castle through. The door of each entrance is opened right before the first guest's arrival and closed right after the arrival of the last guest that should enter the castle through this entrance. No two guests can enter the castle simultaneously. For an entrance to be protected from possible intrusion, a candy guard should be assigned to it. There are k such guards in the castle, so if there are more than k opened doors, one of them is going to be left unguarded! Notice that a guard can't leave his post until the door he is assigned to is closed. Slastyona had a suspicion that there could be uninvited guests at the evening. She knows the order in which the invited guests entered the castle, and wants you to help her check whether there was a moment when more than k doors were opened. ----------------------------------------- I learnt how to write a clean implementation for this problem. Initially, I used two vectors to keep track of the first and last appearance of each guest. And the number of doors open increases by 1 if a guest enters at position i and decreases by 1 at position i-1. (You must decrease the number of open doors 1 position after the last entry of a guest because the case where there's a single guest of a type - ABCDEF ... Here, the number of doors open will always be 0. The code was pretty ugly.) vector first_appearance(26, -1); vector first_entry_at(no_of_guests, false); for(int i = 0; guests[i] != '\0'; i++) if(first_appearance[guests[i] - 'A'] == -1) first_appearance[guests[i]- 'A'] = i, first_entry_at[i] = true; vector last_appearance(26, -1); vector last_entry_at(no_of_guests, false); for(int i = no_of_guests - 1; i >= 0; i--) if(last_appearance[guests[i] - 'A'] == -1) last_appearance[guests[i]- 'A'] = i, last_entry_at[i] = true; int maximum_doors_opened = 1, doors_open = 1; for(int i = 1; i < no_of_guests; i++) { doors_open += first_entry_at[i]; doors_open -= last_entry_at[i - 1]; maximum_doors_opened = max(maximum_doors_opened, doors_open); } printf(maximum_doors_opened > no_of_guards ? "YES\n" : "NO\n"); --------------------------------------------------------------------- I saw a better way to keep track of the last occurence of each character. Rather than start from the end, and pick up a character only if it is unmapped, start from the beginning and always mark each character to it's position. This way you don't have to check if a character is unmarked. Each character is always set to it's last position. and to keep track of number of guests in, use a set. Much cleaner. A set will always ensure distinctness (balanced tree). If i is the last position of a character, then delete that element from the set AFTER comparing the size of the set with the required amount. Otherwise one character guests will throw bugs. This problem was interesting because it's logic was simply but implementation seemed difficult. I learnt a lot. Using a map and a set and the right way to keep track of the last occurence of each character. (Go in the opposite direction). ------------------------------------------------------ vector first_appearance(26, -1); vector first_entry_at(no_of_guests, false); for(int i = 0; guests[i] != '\0'; i++) if(first_appearance[guests[i] - 'A'] == -1) first_appearance[guests[i]- 'A'] = i, first_entry_at[i] = true; vector last_appearance(26, -1); vector last_entry_at(no_of_guests, false); for(int i = no_of_guests - 1; i >= 0; i--) if(last_appearance[guests[i] - 'A'] == -1) last_appearance[guests[i]- 'A'] = i, last_entry_at[i] = true; int maximum_doors_opened = 1, doors_open = 1; for(int i = 1; i < no_of_guests; i++) { doors_open += first_entry_at[i]; doors_open -= last_entry_at[i - 1]; maximum_doors_opened = max(maximum_doors_opened, doors_open); } printf(maximum_doors_opened > no_of_guards ? "YES\n" : "NO\n"); ================================================ FILE: Explanations/Explanations 12/The Number on the Board Explanation.txt ================================================ Some natural number was written on the board. Its sum of digits was not less than k. But you were distracted a bit, and someone changed this number to n, replacing some digits with others. It's known that the length of the number didn't change. You have to find the minimum number of digits in which these two numbers can differ. ---------------------------------------------------------- Here's what I first did. Keep track of the sum initially .. Then go through the digits of the number on board and make each digit 9 if it isn't already 9 as long as the sum is less than k. This was wrong ... Consider the case 11 500. According to this algorithm, answer will be 2, since 5 becomes 9 and digit sum becomes 9. However, we can make one of the 0s 9 and achieve it in one move. So, then I sorted all the numbers and then made each digit 9, starting from 0. ------------------------------------------------------- int main() { int digit_sum; char number_on_board[MAX_LENGTH]; scanf("%d %s", &digit_sum, number_on_board); vector board_number; int board_digit_sum = 0; for(int i = 0; number_on_board[i] != '\0'; i++) { board_digit_sum += number_on_board[i] - '0'; board_number.push_back(number_on_board[i] - '0'); } sort(all(board_number)); int min_no_of_digit_changes = 0; for(unsigned int i = 0; i < board_number.size() && board_digit_sum < digit_sum; i++) { if(board_number[i] != 9) { board_digit_sum += 9 - board_number[i]; min_no_of_digit_changes++; } } printf("%d\n", min_no_of_digit_changes); return 0; } ================================================ FILE: Explanations/Explanations 13/A Good Contest Explanation.txt ================================================ ---------------------------------------------------- If there's any user for whom before >= 2400 and after >= before, then the contest was good. int main() { int no_of_users, good_contest = false; scanf("%d", &no_of_users); while(no_of_users--) { char name[MAX_SIZE]; int before_score, after_score; scanf("%s %d %d", name, &before_score, &after_score); if(before_score >= 2400 && after_score > before_score) good_contest = true; } printf(good_contest ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 13/Arpa's Obvious Problem and Mehrad's Terrible Solution Explanation.txt ================================================ There is an array ... Count the number of pairs for which A[i]XOR A[j] = x. There are upto 10^5 elements in the array. --------------------------------------------------------------------- So iterating through every pair in the array takes O(n^2) time and it won't pass the time limit. I was thinking of how to do it and then it suddenly hit me ! XOR(A[i], A[j]) = X XOR(A[i], A[i], A[j]) = XOR(A[i], X) XOR(0, A[j]) = XOR(A[i], X) A[j] = XOR(A[i], X) So, this is an easier operation. Instead of iterating through every pair of the array and then checking if it gives X on XOR. Build a frequency table of all elements. This takes O(n log n) time. Then go through each frequency bucket. Check what the frequency of XOR(A[i], X) is. Every element of A[i] will match with every element of A[j]. Multiply them to get the pairs. There are n elements and each such operation will take O(log n) time. One tricky thing to watch out for is when A[i]'s complement is itself ... in that case, each A[i] will be paired off with every other element in it's frequency bucket. Pair frequency in this case, will be frequency[A[i]^X] - 1. (It doesn't get paired with itself). Divide the number of pairs by 2 at the end since we have counted each pair twice. O(n log n). -------------------------------------------- int main() { int no_of_elements, target; scanf("%d %d", &no_of_elements, &target); map frequency; for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); frequency[element_i]++; } long long no_of_good_pairs = 0; for(map :: iterator i = frequency.begin(); i != frequency.end(); i++) { int element_i = i->first; int frequency_i = i->second; int pair_element = target^element_i; int pair_frequency = (element_i == pair_element ? frequency_i - 1 : frequency[pair_element]); no_of_good_pairs += pair_frequency*1LL*frequency_i; } no_of_good_pairs = no_of_good_pairs/2; printf("%I64d\n", no_of_good_pairs); return 0; } ================================================ FILE: Explanations/Explanations 13/Arrays Explanation.txt ================================================ You are given two arrays A and B consisting of integers, sorted in non-decreasing order. Check whether it is possible to choose k numbers in array A and choose m numbers in array B so that any number chosen in the first array is strictly less than any number chosen in the second array. -------------------------------------------- Compare the k-th element from the front in A to the m-th element from the back in B. int main() { int size_a, size_b; scanf("%d %d", &size_a, &size_b); int last_a, first_b, last_a_position, first_b_position; scanf("%d %d", &last_a_position, &first_b_position); int element_i; for(int i = 1; i <= size_a; i++) { scanf("%d", &element_i); if(i == last_a_position) last_a = element_i; } for(int i = size_b; i >= 1; i--) { scanf("%d", &element_i); if(i == first_b_position) first_b = element_i; } printf(last_a < first_b ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 13/Arya and Bran Explanation.txt ================================================ Bran and his older sister Arya are from the same house. Bran like candies so much, so Arya is going to give him some Candies. At first, Arya and Bran have 0 Candies. There are n days, at the i-th day, Arya finds ai candies in a box, that is given by the Many-Faced God. Every day she can give Bran at most 8 of her candies. If she don't give him the candies at the same day, they are saved for her and she can give them to him later. Your task is to find the minimum number of days Arya needs to give Bran k candies before the end of the n-th day. Formally, you need to output the minimum day index to the end of which k candies will be given out (the days are indexed from 1 to n). Print -1 if she can't give him k candies during n given days. -------------------------------------------- Keep track of the total candies Arya has. Every day give the min(8, total). Check if greater than k candies have been given any day. ------------------------------- int main() { int no_of_days, target_candies; scanf("%d %d", &no_of_days, &target_candies); const int one_day_limit = 8; int total_candies = 0, given_candies = 0, required_days = -1; for(int day_i = 1; day_i <= no_of_days; day_i++) { int box_i, given_on_day_i; scanf("%d", &box_i); total_candies += box_i; given_on_day_i = min(one_day_limit, total_candies); total_candies -= given_on_day_i; given_candies += given_on_day_i; if(given_candies >= target_candies) { required_days = day_i; break; } } printf("%d\n", required_days); return 0; } ================================================ FILE: Explanations/Explanations 13/Bear and Elections Explanation.txt ================================================ ------------------------------------- This was very interesting. First time I got to use the data structure priority queues practically ! I've learnt something new today. I tried coming up with an O(1) formula, but that doesn't work when there are multiple maxima. Rather than maintain a sorted array ... It's a lot more convenient to have a priority queue. We can get the largest element in O(1) time. Keep comparing limak with the maximum. If he isn't already the maximum, then increase his votes by 1, decrease maxima and put the maxima back in the priority queueu. --------------------------------- #include #include using namespace std; int main() { int no_of_candidates; scanf("%d", &no_of_candidates); int limak_votes; priority_queue votes; scanf("%d", &limak_votes); for(int i = 2; i <= no_of_candidates; i++) { int vote_i; scanf("%d", &vote_i); votes.push(vote_i); } int limak_bribes = 0; while(limak_votes + limak_bribes <= votes.top()) { int current_max = votes.top(); votes.pop(); current_max--; limak_bribes++; votes.push(current_max); } printf("%d\n", limak_bribes); return 0; } ================================================ FILE: Explanations/Explanations 13/Business Trip.txt ================================================ What joy! Petya's parents went on a business trip for the whole year and the playful kid is left all by himself. Petya got absolutely happy. He jumped on the bed and threw pillows all day long, until... Today Petya opened the cupboard and found a scary note there. His parents had left him with duties: he should water their favourite flower all year, each day, in the morning, in the afternoon and in the evening. "Wait a second!" — thought Petya. He know for a fact that if he fulfills the parents' task in the i-th (1 ≤ i ≤ 12) month of the year, then the flower will grow by ai centimeters, and if he doesn't water the flower in the i-th month, then the flower won't grow this month. Petya also knows that try as he might, his parents won't believe that he has been watering the flower if it grows strictly less than by k centimeters. Help Petya choose the minimum number of months when he will water the flower, given that the flower should grow no less than by k centimeters. ---------------------------------------------- Be greedy. Plant the months with the greatest amount of growth first. Sort the array in descending order. I got a beginner bug because I didn't do bound checking for the array ... I didn't check if the number of months was greater than the number of months at first. ------------------------------ int main() { int minimum_growth; scanf("%d", &minimum_growth); const int no_of_months = 12; vector growth(no_of_months); for(int i = 0; i < no_of_months; i++) scanf("%d", &growth[i]); sort(all(growth)); reverse(all(growth)); int month_i = 0, plant_growth = 0; while(plant_growth < minimum_growth && month_i < no_of_months) { plant_growth += growth[month_i++]; } printf("%d\n", plant_growth < minimum_growth ? -1 : month_i); return 0; } ================================================ FILE: Explanations/Explanations 13/Code Obfuscation Explanation.txt ================================================ Kostya likes Codeforces contests very much. However, he is very disappointed that his solutions are frequently hacked. That's why he decided to obfuscate (intentionally make less readable) his code before upcoming contest. To obfuscate the code, Kostya first looks at the first variable name used in his program and replaces all its occurrences with a single symbol a, then he looks at the second variable name that has not been replaced yet, and replaces all its occurrences with b, and so on. Kostya is well-mannered, so he doesn't use any one-letter names before obfuscation. Moreover, there are at most 26 unique identifiers in his programs. You are given a list of identifiers of some program with removed spaces and line breaks. Check if this program can be a result of Kostya's obfuscation. ------------------------------------------ My logic was simple. keep track of all alphabets used ... If a new alphabet is encountered at any point in the string, all alphabets smaller than it must already have been used. To keep track of all distinct alphabets, use a set data structure. First, check if the element is already inserted in the set (log n). If it is not, then check if the size of the set < ch - 'a' ... This means that all alphabets smaller than ch are not used which makes it an invalid string. If it is valid, insert the character into the string. ------------------------------- int main() { char code[MAX_LENGTH]; scanf("%s", code); set alphabets_used; int code_obfuscation = true; for(int i = 0; code[i] != '\0'; i++) { //Before inserting an alphabet, all alphabets smaller than it must already have been used if(alphabets_used.count(code[i]) == 0) { if(alphabets_used.size() < code[i] - 'a') { code_obfuscation = false; break; } } alphabets_used.insert(code[i]); } printf(code_obfuscation ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 13/Drinks Explanation.txt ================================================ Little Vasya loves orange juice very much. That's why any food and drink in his kitchen necessarily contains orange juice. There are n drinks in his fridge, the volume fraction of orange juice in the i-th drink equals pi percent. One day Vasya decided to make himself an orange cocktail. He took equal proportions of each of the n drinks and mixed them. Then he wondered, how much orange juice the cocktail has. Find the volume fraction of orange juice in the final drink. ---------------------------------------------- The numerator is the sum of all percentages. The denominator is n. Be careful about floating point precision errors. I typecasted everything to double before dividing. int main() { int no_of_drinks; scanf("%d", &no_of_drinks); double numerator = 0.0; for(int i = 1; i <= no_of_drinks; i++) { int percent_i; scanf("%d", &percent_i); numerator += percent_i; } double denominator = no_of_drinks*1.0; double fraction = numerator/denominator; printf("%lf\n", fraction); return 0; } ================================================ FILE: Explanations/Explanations 13/Epic Game Explanation.txt ================================================ gcd(a, b) <= min(a, b) ... This is when both a and b are positive integers. It only changes when one of them is 0. Keep decreasing n by the required amount until it reaches 0. Constraints are small. It will pass. ---------------------------------------------- int main() { int a, b, n; scanf("%d %d %d", &a, &b, &n); int winner; for(int turn_i = 0; n > 0; turn_i++) { int current_player = (turn_i%2 == 0 ? a : b) ; n -= gcd(current_player, n); if(n == 0) winner = turn_i%2; } printf("%d\n", winner); return 0; } ================================================ FILE: Explanations/Explanations 13/Functions Again Explanation.txt ================================================ There is a list of n integers, A function f(left, right) = sum(i = left to right - 1) |A[i] - A[i + 1]|. (-1)^{i + 1} Find the maximum value of this function. ---------------------------------------------------------------- Let's make some observations - Firstly, notice that f(i, r) = f(i, i + 1) - f(i + 1, r). This itself is enough to suggest optimal substructure. Now, every function must END at a certain index in the array. Let Answer(i, j) represent the maximum value of f ending at i, j has two states Representing whether the last difference i.e. - |A[i - 1] - A[i]| should be subtracted or added to f(i - 1, j). Notice that EVERY function ending at i must neccessarily include |A[i] - A[i - 1]|. There are two possibilities, either it is added or it is subtracted. 1. The difference is added, then Answer(i, LAST_DIFFERENCE_ADDED) = max{0, Answer(i - 1, LAST_DIFFERENCE_REMOVED)} + |A[i - 1] - A[i]| If the current difference ending at i is added, then the previous difference ending at i - 1 must be subtracted. Of course, subtracting the previous difference may have made the value of the function negative. IN that case, we don't build upon Answer(i - 1, LAST_DIFFERENCE_REMOVED), but start a new function from i-1 = |A[i - 1] - A[i]| 2. The difference is subtracted, then Answer(i, LAST_DIFFERENCE_REMOVED) = Answer(i - 1, LAST_DIFFERENCE_ADDED) - |A[i - 1] - A[i]| If the current difference ending at i is subtracted, the the previous difference ending at i - 1 must have been added. So, we just subtract it from Answer(i - 1, LAST_DIFFFERENCE_ADDED). Note - Here we do not check if the value of Answer at position i-1 is positive because it is not possible to start the function from i-1 and subtract the first term. By the definition of the function f, the first term MUST be added. So, here, we must build on what was done previously. Base case - Answer(2, LAST_DIFFERENCE_ADDED) = |A[2] - A[1]| Answer(2, LAST_DIFFERENCE_REMOVED) = 0 .... [We can't start a function from 1 and subtract the first term] SO, Answer(3, LAST_DIFFERENCE_REMOVED) = Answer(2, LAST_DIFFERENCE_ADDED) - |A[3] - A[2]| - Answer(3, LAST_DIFFERENCE_ADDED) = max{Answer(2, LAST_DIFFERENCE_REMOVED), 0} + |A[3] - A[2]| This is a 2-dimensional function, but notice for each state, we only need the previous state. So, it can be done in O(1) memory and O(n) time. Answer = max{Answer(i, j)} --------------------------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); long long maximum_value, maximum_with_last_difference_added, maximum_with_last_difference_removed; maximum_with_last_difference_added = abs(element[2] - element[1]); maximum_with_last_difference_removed = 0; maximum_value = maximum_with_last_difference_added; for(int i = 3; i <= no_of_elements; i++) { long long maximum_with_this_difference_added, maximum_with_this_difference_removed, maximum_value_ending_here; maximum_with_this_difference_added = max(0LL, maximum_with_last_difference_removed) + abs(element[i] - element[i - 1]); maximum_with_this_difference_removed = maximum_with_last_difference_added - abs(element[i] - element[i - 1]); maximum_value_ending_here = max(maximum_with_this_difference_added, maximum_with_this_difference_removed); maximum_value = max(maximum_value, maximum_value_ending_here); maximum_with_last_difference_added = maximum_with_this_difference_added; maximum_with_last_difference_removed = maximum_with_this_difference_removed; } printf("%I64d\n", maximum_value); return 0; } ================================================ FILE: Explanations/Explanations 13/Generous Kefa Explanation.txt ================================================ One day Kefa found n baloons. For convenience, we denote color of i-th baloon as si lowercase letter of the Latin alphabet. Also Kefa has k friends. Friend will be upset, If he get two baloons of the same color. Kefa want to give out all baloons to his friends. Help Kefa to find out, can he give out all his baloons, such that no one of his friens will be upset print YES, if he can, and NO, otherwise. Note, that Kefa's friend will not upset, if he doesn't get baloons at all. --------------------------------------------------------- The number of balloons of any colour should not exceed the number of people. That forces one person to get balloons of the same colour by the pigeonhole principle. ---------------------------------------- int main() { int no_of_balloons, no_of_people; char balloon_colours[MAX_LENGTH]; scanf("%d %d %s",&no_of_balloons, &no_of_people, balloon_colours); int no_of_balloons_of_colour[NO_OF_ALPHABETS] = {0}; for(int i = 0; i < no_of_balloons; i++) { no_of_balloons_of_colour[balloon_colours[i] - 'a']++; } int everyone_happy = true; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(no_of_balloons_of_colour[i] > no_of_people) { everyone_happy = false; break; } } printf(everyone_happy ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 13/George and Job Explanation.txt ================================================ There is an array of n numbers. Choose k intervals of size m each, to maximise the sum of all the elements in these k intervals. ------------------------------------------ Let f(i, t) be the maximum sum with the first i number, with t intervals used. We have two options - Either we include the interval ending at i or we do not. If an interval ends at i, then, f(i, t) = f(i - m, t - 1) + sum(i - m + 1 to i) If an interval does not end at i, then f(i, t) = f(i - 1, t). f(i, t) = max{f(i - m, t - 1) + sum[i] - sum[i - m], f(i - 1, t)} O(NK) -------------------------------------------------------- int main() { int no_of_numbers, no_of_intervals, max_interval_size; scanf("%d %d %d", &no_of_numbers, &max_interval_size, &no_of_intervals); vector sum_till(no_of_numbers + 1, 0); for(int i = 1; i <= no_of_numbers; i++) { int number_i; scanf("%d", &number_i); sum_till[i] = number_i + sum_till[i - 1]; } typedef vector v_long; vector maximum_sum_till(no_of_numbers + 1, v_long(no_of_intervals + 1, 0)); for(int interval_i = 1; interval_i <= no_of_intervals; interval_i++) { for(int number_i = max_interval_size; number_i <= no_of_numbers; number_i++) { int right = number_i, left = (number_i - max_interval_size) + 1; long long interval_ending_here_sum = sum_till[right] - sum_till[left - 1]; long long maximum_sum_with_interval_ending_here = maximum_sum_till[left - 1][interval_i - 1] + interval_ending_here_sum ; long long maximum_sum_with_interval_ending_before_here = maximum_sum_till[number_i - 1][interval_i]; maximum_sum_till[number_i][interval_i] = max(maximum_sum_with_interval_ending_here, maximum_sum_with_interval_ending_before_here); } } printf("%I64d\n", maximum_sum_till[no_of_numbers][no_of_intervals]); return 0; } ================================================ FILE: Explanations/Explanations 13/Godsend Explanation.txt ================================================ Leha somehow found an array consisting of n integers. Looking at it, he came up with a task. Two players play the game on the array. Players move one by one. The first player can choose for his move a subsegment of non-zero length with an odd sum of numbers and remove it from the array, after that the remaining parts are glued together into one array and the game continues. The second player can choose a subsegment of non-zero length with an even sum and remove it. Loses the one who can not make a move. Who will win if both play optimally? ------------------------------------------------------------ Case 1 - The array has only even numbers. The first player does not have a move since there is no subarray consisting of an odd sum. Case 2 - The array has at least one odd number. Case 2a - The array has an odd number of odd numbers. This forces the sum of the array to be odd. The first player takes all the array elements and wins. Case 2b - The array has an even number of odd numbers. Let the array have 2p odd numbers. The first player chooses a segment which has all numbers but one of these odd numbers. So, the first player chooses a segment that contains 2p - 1 odd numbers. Now, the second player cannot take this element, because any segment containing the left out odd number will have an odd sum, forcing the sum to be odd. Either the second player has no moves or he makes a move which gives the first player an array consisting of only one odd number, and this reduces to Case 2a. The first player wins by taking the entire array. The second player only wins if there are 0 odd numbers. ---------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); int only_even_numbers = true; for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); if(element_i%2 == 1) only_even_numbers = false; } printf(only_even_numbers ? "Second\n" : "First\n"); return 0; } ================================================ FILE: Explanations/Explanations 13/Kuriyama Mirai's Stones Explanation.txt ================================================ Just an implementation problem. ------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 1, 0); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &element[i]); sum_till[i] = element[i] + sum_till[i - 1]; } sort(all(element)); vector sorted_sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sorted_sum_till[i] = element[i] + sorted_sum_till[i - 1]; } int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int query_type, left, right; scanf("%d %d %d", &query_type, &left, &right); long long answer = (query_type == 1 ? sum_till[right] - sum_till[left - 1] : sorted_sum_till[right] - sorted_sum_till[left - 1]); printf("%I64d\n", answer); } return 0; } ================================================ FILE: Explanations/Explanations 13/Little Dima and Equation Explanation.txt ================================================ ------------------------------------------------- The trick for solving these kinds of questions is to brute force over the sum of digits rather than x. The sum of digits can go up to 81 in 1e9 -1. I got this far. But, I still didn't know how to do the last step. The idea is to simply keep evaluating the LHS and then checking if it is within the constraint. I used my own power function because I know pow returns double. --------------------- int main() { int a, b, c; scanf("%d %d %d", &a, &b, &c); vector solutions; for(int digit_sum = 1; digit_sum <= 81; digit_sum++) { long long x = b*int_power(digit_sum, a) + c; if(sum_of_digits(x) == digit_sum && x > 0 && x < 1e9) solutions.push_back(x); } printf("%d\n", solutions.size()); for(unsigned int i = 0; i < solutions.size(); i++) printf("%d ", solutions[i]); return 0; } ================================================ FILE: Explanations/Explanations 13/Little Elephant and Bits Explanation.txt ================================================ The Little Elephant has an integer a, written in the binary notation. He wants to write this number on a piece of paper. To make sure that the number a fits on the piece of paper, the Little Elephant ought to delete exactly one any digit from number a in the binary record. At that a new number appears. It consists of the remaining binary digits, written in the corresponding order (possible, with leading zeroes). The Little Elephant wants the number he is going to write on the paper to be as large as possible. Help him find the maximum number that he can obtain after deleting exactly one binary digit and print it in the binary notation. -------------------------------------------------- To keep the number as large as possible, we need to disturb as less of the set bits as possible. Notice that any deletion always shifts the position of the bits. To do this we delete the most significant bit that is set to 0. This doesn't affect any of the bits to right of this 0 and keeps the most number of bits intact. If there is no 0, then delete any of the digits. (The answer will be the same.) ----------------------------------- int main() { char number[MAX_SIZE]; scanf("%s", number); char new_number[MAX_SIZE]; int first_zero = -1, new_number_i = 0; for(int i = 0; number[i] != '\0'; i++) { if(number[i] == '0' && first_zero == -1) { first_zero = i; } else { new_number[new_number_i++] = number[i]; } } int last_digit_position = new_number_i; if(first_zero == -1) last_digit_position--; new_number[last_digit_position] = '\0'; printf("%s\n", new_number); return 0; } ================================================ FILE: Explanations/Explanations 13/New Skateboard Explanation.txt ================================================ --------------------------------------------------- A number is a multiple of 4 if it's last 2 digits are a multiple of 4. So go through every (s[i], s[i + 1]) ... IF they form a number divisible by 4, then every string ending there will be a multiple of 4. (All strings from 0 to i = i + 1 multiples of 4). Additionally a new string will be formed if s[i + 1] is also a multiple of 4, (on it's own). Be sure to check if the first character is a multiple of 4 before you begin. ------------------------------------ int main() { char calculator[MAX_LENGTH]; scanf("%s", calculator); long long no_of_multiples_of_4 = ( (calculator[0] - '0')%4 == 0); for(int i = 0; calculator[i + 1] != '\0'; i++) { int current_suffix = (calculator[i] - '0')*10 + (calculator[i + 1] - '0'); int no_of_strings_ending_with_this_suffix = i + 1; if(current_suffix%4 == 0) no_of_multiples_of_4 += no_of_strings_ending_with_this_suffix; no_of_multiples_of_4 += ( (calculator[i + 1] - '0')%4 == 0); } printf("%I64d\n", no_of_multiples_of_4); return 0; } ================================================ FILE: Explanations/Explanations 13/Oath of the Night's Watch Explanation.txt ================================================ With that begins the watch of Jon Snow. He is assigned the task to support the stewards. This time he has n stewards with him whom he has to provide support. Each steward has his own strength. Jon Snow likes to support a steward only if there exists at least one steward who has strength strictly less than him and at least one steward who has strength strictly greater than him. Can you find how many stewards will Jon support? -------------------------------------------- The minimum strength and the maximum cannot be supported. Keep track of their frequency. int main() { const int oo = 1e9 + 1; int no_of_people, min_strength = oo, max_strength = 0; scanf("%d", &no_of_people); map strength_frequency; for(int i = 1; i <= no_of_people; i++) { int strength_i; scanf("%d", &strength_i); strength_frequency[strength_i]++; min_strength = min(strength_i, min_strength); max_strength = max(strength_i, max_strength); } int number_of_people_supported = max(0, no_of_people - strength_frequency[max_strength] - strength_frequency[min_strength]); printf("%d\n", number_of_people_supported); return 0; } ================================================ FILE: Explanations/Explanations 13/Sort the Array Explanation.txt ================================================ Being a programmer, you like arrays a lot. For your birthday, your friends have given you an array a consisting of n distinct integers. Unfortunately, the size of a is too small. You want a bigger array! Your friends agree to give you a bigger array, but only if you are able to answer the following question correctly: is it possible to sort the array a (in increasing order) by reversing exactly one segment of a? See definitions of segment and reversing in the notes. ---------------------------------------------------- Count the number of descending segments. It should be at most 1. however, that isn't enough. Consider - 100 99 1 2 3 ... This has one descending segment, but it doesn't fit. Chech if A[start] < A[end + 1] ... I did this ... I forgot the case 1 2 100 99 3 4 5 You also need to check A[end] >= A[start - 1], If there is no descending segment, reverse any 1-element segment of the array. --------------------------------------------- int main() { int number_of_elements; scanf("%d", &number_of_elements); vector element(number_of_elements + 1); for(int i = 1; i <= number_of_elements; i++) scanf("%d", &element[i]); int descending_segments = 0, in_descending_segment = false, reversed_segment_fits = false; int segment_start = 1, segment_end = number_of_elements; for(int i = 2; i <= number_of_elements && descending_segments <= 1; i++) { if(in_descending_segment) { if(element[i] > element[i - 1]) { segment_end = i - 1; in_descending_segment = false; } } else { if(element[i] < element[i - 1]) { in_descending_segment = true; segment_start = i - 1; descending_segments++; } } } if(descending_segments == 0) segment_end = segment_start; if( (segment_end == number_of_elements || element[segment_start] <= element[segment_end + 1] ) && (segment_start == 1 || element[segment_end] >= element[segment_start - 1]) ) { reversed_segment_fits = true; } if(descending_segments <= 1 && reversed_segment_fits) printf("yes\n%d %d\n", segment_start, segment_end); else printf("no\n"); return 0; } ================================================ FILE: Explanations/Explanations 13/Star Sky Explanation.txt ================================================ Precompputation must be used to speeden this. Let f(b, x, y) hold the number of stars of brightness b (initially) in the rectangle from (1, 1) ending at (x, y). Clearly, f(b, x, y) = f(b, x - 1, y) + f(b, x, y - 1) - f(b, x - 1, y - 1) + (no of stars of brightness b at (x, y)) Answer to each query is (b + t)%(MAximum brightness + 1) * no of stars of brightness b. The number of stars of brightness b inside the query rectangle is f(b, x2, y2) - f(b, x2, y1 - 1) - f(b, x1 - 1, y2) + f(b, x1 - 1, y1 - 1) By the principle of exclusion and inclusion. ------------------------------------------------ Complexity of this approach for queries is O(qc) + O(cX^2) for precomputation. O(n) for reading input. Now, for every query, we only need to go over every brightness, which is small. However, if for every query, we go over the entire rectangle, then it is O(qX^2) ... Since q can be 10^5 and X can be 100 ... This may take roughly 10^9 iterations. Whereas, O(qc) is 10^5 . 10 = 10^6 operations. Precomputation takes (10. 10^4 = 10^5 operations roughly, as does input ... Overall precomputation and input will take 2. 10^5 operations ... This is done in one second and all queries are answered in one second). If the queries were answered individually by going over the entire rectangle, it would take 10^9 operations which is 1000 seconds. ------------------------------------------------------------------------------ int main() { int no_of_stars, no_of_views, maximum_brightness; scanf("%d %d %d", &no_of_stars, &no_of_views, &maximum_brightness); int no_of_stars_of_initial_brightness_in[MAX_BRIGHTNESS + 1][MAX_LENGTH + 1][MAX_LENGTH + 1] = {{{0}}}; for(int star_i = 1; star_i <= no_of_stars; star_i++) { int brightness_i, x_i, y_i; scanf("%d %d %d", &x_i, &y_i, &brightness_i); no_of_stars_of_initial_brightness_in[brightness_i][x_i][y_i]++; } for(int brightness_i = 0; brightness_i <= maximum_brightness; brightness_i++) { for(int x_i = 1; x_i <= MAX_LENGTH; x_i++) { for(int y_i = 1; y_i <= MAX_LENGTH; y_i++) { no_of_stars_of_initial_brightness_in[brightness_i][x_i][y_i] += no_of_stars_of_initial_brightness_in[brightness_i][x_i][y_i - 1] + no_of_stars_of_initial_brightness_in[brightness_i][x_i - 1][y_i] - no_of_stars_of_initial_brightness_in[brightness_i][x_i - 1][y_i - 1]; } } } while(no_of_views--) { int time, x_1,y_1, x_2, y_2; scanf("%d %d %d %d %d", &time, &x_1, &y_1, &x_2, &y_2); int sum_of_brightness = 0; for(int brightness_i = 0; brightness_i <= maximum_brightness; brightness_i++) { int no_of_stars_of_this_brightness = no_of_stars_of_initial_brightness_in[brightness_i][x_2][y_2] - no_of_stars_of_initial_brightness_in[brightness_i][x_2][y_1 - 1] - no_of_stars_of_initial_brightness_in[brightness_i][x_1 - 1][y_2] + no_of_stars_of_initial_brightness_in[brightness_i][x_1 - 1][y_1 - 1]; int final_brightness = (brightness_i + time)%(maximum_brightness + 1); sum_of_brightness += no_of_stars_of_this_brightness*final_brightness; } printf("%d\n", sum_of_brightness); } return 0; } ================================================ FILE: Explanations/Explanations 13/Vanya and Books Explanation.txt ================================================ -------------------------------------- Every page contributes 1 digit to the total. Every page greater than 10 contributes 2 to the total Every page greater than 10^2 contributes 3 to the total. Every page greater than 10^r contributes r+1 to the total So, for every power of 10 smaller then n, add n - (10^i - 1) to the total. (Because 10^i is the point from which an additional digit is contributed). This is O(log n) complexity ------------------------------------ int main() { int no_of_pages; scanf("%d", &no_of_pages); long long no_of_digits_used = 0; long long power_of_10 = 1; while(power_of_10 <= no_of_pages) { no_of_digits_used += no_of_pages - (power_of_10 - 1); power_of_10 *= 10; } printf("%I64d\n", no_of_digits_used); return 0; } ================================================ FILE: Explanations/Explanations 13/Vasya and Digital Root Explanation.txt ================================================ Now Vasya wants to quickly find numbers with the given digital root. The problem is, he hasn't learned how to do that and he asked you to help him. You task is, given numbers k and d, find the number consisting of exactly k digits (the leading zeroes are not allowed), with digital root equal to d, or else state that such number does not exist. --------------------------------------------------- Pad the number with k-1 9s and then put a d ... S(n) = S(n + 9). I missed the case where d = 0 and k > 1 no solution ------------------------- int main() { int digital_root, no_of_digits; scanf("%d %d", &no_of_digits, &digital_root); if(digital_root == 0 && no_of_digits > 1) printf("No solution\n"); else { for(int i =no_of_digits; i >= 2; i--) printf("9"); printf("%d\n", digital_root); } return 0; } ================================================ FILE: Explanations/Explanations 14/Borze Explanation.txt ================================================ Ternary numeric notation is quite popular in Berland. To telegraph the ternary number the Borze alphabet is used. Digit 0 is transmitted as ., 1 as -. and 2 as --. You are to decode the Borze code, i.e. to find out the ternary number given its representation in Borze alphabet. ------------------------------- The coding is like Huffman coding. No code is the prefix of another code. ----------------------------------- int main() { string borze_code, translation; cin >> borze_code; for(unsigned int i = 0; i < borze_code.size(); i++) { if(borze_code[i] == '.') translation += '0'; else if(borze_code[i] == '-') { if(borze_code[i + 1] == '.') translation += '1'; else if(borze_code[i + 1] == '-') translation += '2'; i++; } } cout << translation; return 0; } ================================================ FILE: Explanations/Explanations 14/Chess Tourney Explanation.txt ================================================ Berland annual chess tournament is coming! Organizers have gathered 2n chess players who should be divided into two teams with n people each. The first team is sponsored by BerOil and the second team is sponsored by BerMobile. Obviously, organizers should guarantee the win for the team of BerOil. Thus, organizers should divide all 2n players into two teams with n people each in such a way that the first team always wins. Every chess player has its rating ri. It is known that chess player with the greater rating always wins the player with the lower rating. If their ratings are equal then any of the players can win. After teams assignment there will come a drawing to form n pairs of opponents: in each pair there is a player from the first team and a player from the second team. Every chess player should be in exactly one pair. Every pair plays once. The drawing is totally random. Is it possible to divide all 2n players into two teams with n people each so that the player from the first team in every pair wins regardless of the results of the drawing? -------------------------------------------------------- Have two divisions - consisting of the first and second half of players according to ratings. If the greatest rated player of second division is weaker than the weakest player of first division, then answer is yes. Else it is no. ------------------------------------------------------------- int main() { int no_of_pairs; scanf("%d", &no_of_pairs); vector player_rating(2*no_of_pairs + 1, 0); for(int i = 1; i <= 2*no_of_pairs; i++) scanf("%d", &player_rating[i]); sort(all(player_rating)); printf(player_rating[no_of_pairs] < player_rating[no_of_pairs + 1] ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 14/Dragons Explanation.txt ================================================ Kirito is stuck on a level of the MMORPG he is playing now. To move on in the game, he's got to defeat all n dragons that live on this level. Kirito and the dragons have strength, which is represented by an integer. In the duel between two opponents the duel's outcome is determined by their strength. Initially, Kirito's strength equals s. If Kirito starts duelling with the i-th dragon and Kirito's strength is not greater than the dragon's strength xi, then Kirito loses the duel and dies. But if Kirito's strength is greater than the dragon's strength, then he defeats the dragon and gets a bonus strength increase by yi. Kirito can fight the dragons in any order. Determine whether he can move on to the next level of the game, that is, defeat all dragons without a single loss. ------------------------------------------------- Fight the weakest dragon available. If you can't beat him, you can't beat anyone else either. ------------------------------------------------------ int main() { int strength, no_of_dragons; scanf("%d %d", &strength, &no_of_dragons); vector < pair > dragon(no_of_dragons); for(int i = 0; i < no_of_dragons; i++) scanf("%d %d", &dragon[i].first, &dragon[i].second); sort(all(dragon)); int can_defeat_all_dragons = true; for(int i = 0; i < no_of_dragons; i++) { int strength_of_dragon = dragon[i].first; int bonus = dragon[i].second; if(strength <= strength_of_dragon) { can_defeat_all_dragons = false; break; } else { strength += bonus; } } printf(can_defeat_all_dragons ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 14/Drazil and Factorial Explanation.txt ================================================ F(x) = product of factorials of all digits in decimal representation of x. F(135) = 1!.3!.5! For a given a, print the maximum x such that - 1. x has no 0s and 1s 2. F(x) = F(a) It is guaranteed that a has at least one digit that is not 0 or 1. ---------------------------------------------------- To get the maximum possible x, we generate the x with the most number of digits and then print the digits in descending order. 2, 3, 5, 7 are prime numbers ... they need to be present for their factorials. 4! = 2!.2!.3! 6! = 3!.5! 8! = 2!.2!.2!.7! 9! = 2!.3!.3!.7! Replace each digit accordingly, sort and then print the answer. ------------------------------------------------------- int main() { int no_of_digits; scanf("%d", &no_of_digits); vector number; for(int i = 1; i <= no_of_digits; i++) { int digit_i; scanf("%1d", &digit_i); switch(digit_i) { case 2: case 3: case 5: case 7: number.push_back(digit_i); break; case 4: number.push_back(2); number.push_back(2); number.push_back(3); break; case 6: number.push_back(3); number.push_back(5); break; case 8: number.push_back(2); number.push_back(2); number.push_back(2); number.push_back(7); break; case 9: number.push_back(2); number.push_back(3); number.push_back(3); number.push_back(7); break; } } sort(all(number)); for(int i = number.size() - 1; i >= 0; i--) printf("%d", number[i]); return 0; } ================================================ FILE: Explanations/Explanations 14/Football Explanation.txt ================================================ One day Vasya decided to have a look at the results of Berland 1910 Football Championships finals. Unfortunately he didn't find the overall score of the match; however, he got hold of a profound description of the match's process. On the whole there are n lines in that description each of which described one goal. Every goal was marked with the name of the team that had scored it. Help Vasya, learn the name of the team that won the finals. It is guaranteed that the match did not end in a tie. --------------------------------------- Maintain a map of the no of goals scored by each team. int main() { int no_of_lines; cin >> no_of_lines; map no_of_goals; while(no_of_lines--) { string team; cin >> team; no_of_goals[team]++; } string winner; int max_goals = 0; for(map :: iterator i = no_of_goals.begin(); i != no_of_goals.end(); i++) { int no_of_goals = i->second; if(no_of_goals > max_goals) { max_goals = no_of_goals; winner = i->first; } } cout << winner; return 0; } ================================================ FILE: Explanations/Explanations 14/Helpful Maths Explanation.txt ================================================ Xenia the beginner mathematician is a third year student at elementary school. She is now learning the addition operation. The teacher has written down the sum of multiple numbers. Pupils should calculate the sum. To make the calculation easier, the sum only contains numbers 1, 2 and 3. Still, that isn't enough for Xenia. She is only beginning to count, so she can calculate a sum only if the summands follow in non-decreasing order. For example, she can't calculate sum 1+3+2+1 but she can calculate sums 1+1+2 and 3+3. You've got the sum that was written on the board. Rearrange the summans and print the sum in such a way that Xenia can calculate the sum. ----------------------------------------------- Sort the digits and print them one by one seperated by '+' signs. ------------------------------------------ int main() { string expression; cin >> expression; typedef unsigned int u_int; vector number; for(u_int i = 0; i < expression.size(); i++) { if(expression[i] != '+') number.push_back(expression[i]); } sort(all(number)); for(u_int i = 0; i < number.size() - 1; i++) { printf("%c+", number[i]); } printf("%c\n", number.back()); return 0; } ================================================ FILE: Explanations/Explanations 14/Jeff and Digits Explanation.txt ================================================ Jeff's got n cards, each card contains either digit 0, or digit 5. Jeff can choose several cards and put them in a line so that he gets some number. What is the largest possible number divisible by 90 Jeff can make from the cards he's got? Jeff must make the number without leading zero. At that, we assume that number 0 doesn't contain any leading zeroes. Jeff doesn't have to use all the cards. ------------------------------------------------- If there are no 0s, you can never construct a multiple of 90. If there is atleast one 0, then check if there are less than 9 5s. In that case the answer is 0. Else the answer is 5 (printed to the greatest possible multiple of 9 possible) followed by all the zeroes. -------------------------------------------- int main() { int no_of_digits; scanf("%d", &no_of_digits); int no_of_5s = 0, no_of_0s = 0; for(int i = 1; i <= no_of_digits; i++) { int digit; scanf("%d", &digit); no_of_5s += (digit == 5); no_of_0s += (digit == 0); } if(no_of_0s == 0) { printf("-1\n"); } else if(no_of_5s < 9) { printf("0\n"); } else { int no_of_5s_in_number = (no_of_5s/9)*9; for(int i = 1; i <= no_of_5s_in_number; i++) printf("5"); for(int i = 1; i <= no_of_0s; i++) printf("0"); } return 0; } ================================================ FILE: Explanations/Explanations 14/Jzzhu and Children Explanation.txt ================================================ There are n children in Jzzhu's school. Jzzhu is going to give some candies to them. Let's number all the children from 1 to n. The i-th child wants to get at least ai candies. Jzzhu asks children to line up. Initially, the i-th child stands at the i-th place of the line. Then Jzzhu start distribution of the candies. He follows the algorithm: Give m candies to the first child of the line. If this child still haven't got enough candies, then the child goes to the end of the line, else the child go home. Repeat the first two steps while the line is not empty. Consider all the children in the order they go home. Jzzhu wants to know, which child will be the last in this order? --------------------------------------------- The number of times a child stands in line = ceil(a_i/m) Keep track of which i has the maximum number of i, if there is a tie, award it to the greater i. ------------------------------- int main() { int no_of_children, no_of_candies_given; scanf("%d %d", &no_of_children, &no_of_candies_given); int maximum_turns = 0, last_child = 0; for(int i = 1; i <= no_of_children; i++) { int candy_i; scanf("%d", &candy_i); int no_of_turns = candy_i/no_of_candies_given + (candy_i%no_of_candies_given != 0); if(no_of_turns >= maximum_turns) { maximum_turns = no_of_turns; last_child = i; } } printf("%d\n", last_child); return 0; } ================================================ FILE: Explanations/Explanations 14/Panoramix's Prediction Explanation.txt ================================================ One cold April morning Panoramix predicted that soon Kakofonix will break free from his straitjacket, and this will be a black day for the residents of the Gallic countryside. Panoramix's prophecy tells that if some day Asterix and Obelix beat exactly x Roman soldiers, where x is a prime number, and next day they beat exactly y Roman soldiers, where y is the next prime number after x, then it's time to wait for Armageddon, for nothing can shut Kakofonix up while he sings his infernal song. ----------------------------------------------------------------- Just check if there's no primes in between and y is also a prime. int main() { int x, y; scanf("%d %d", &x, &y); int prime_in_middle = false; for(int i = x + 1; i < y; i++) { if(is_prime(i)) { prime_in_middle = true; break; } } printf(!prime_in_middle && is_prime(y) ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 14/Powers of Two.txt ================================================ Find all pairs of elemnets (A[i], A[j]) that sum up to x in a given array. ---------------------------------- The naive solution is to iterate through every pair of elements in the array. This is O(n^2). There's a better solution. Keep track of the frequency of each element. Then pick up every frequency bucket and then see if (2^x - A[i]) exists and what it's frequency is. Note - FOr practical reasons, checking map[2^x - A[i]] == 0, inserts another node into the frequency table. So, before inserting check if 2^x - A[i] is positive, and then if it is present in the original array. If it is present in the original array, then multiply the frequency of the element with the frequency of the pair element. (If an element is it's own pair, then pair frequency = frequency_i - 1) O(n log n) to take the input, and O(n log n) to find the answer. ----------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); set original_array; map frequency; for(int i = 0; i < no_of_elements; i++) { int element_i; scanf("%d", &element_i); frequency[element_i]++; original_array.insert(element_i); } long long no_of_pairs = 0; for(map :: iterator i = frequency.begin(); i != frequency.end(); i++) { int element_i = i->first; int frequency_i = i->second; for(int power = 0; power <= 31; power++) { int power_of_2 = (1 << power); int pair_element = power_of_2 - element_i; int pair_frequency = 0; if(pair_element > 0 && original_array.count(pair_element) == 1) pair_frequency = (element_i == pair_element ? frequency_i - 1 : frequency[pair_element]); no_of_pairs += frequency_i*1LL*pair_frequency; } } no_of_pairs = no_of_pairs/2; printf("%I64d\n", no_of_pairs); return 0; } ================================================ FILE: Explanations/Explanations 14/Tram Explanation.txt ================================================ Linear Kingdom has exactly one tram line. It has n stops, numbered from 1 to n in the order of tram's movement. At the i-th stop ai passengers exit the tram, while bi passengers enter it. The tram is empty before it arrives at the first stop. Also, when the tram arrives at the last stop, all passengers exit so that it becomes empty. Your task is to calculate the tram's minimum capacity such that the number of people inside the tram at any time never exceeds this capacity. Note that at each stop all exiting passengers exit before any entering passenger enters the tram. ---------------------------------------- The minimum capacity is the maximum number of people on the train at any given point of time. ----------------------------------- int main() { int no_of_stops; scanf("%d", &no_of_stops); int minimum_capacity = 0, no_of_people_on_train = 0; for(int i = 1; i <= no_of_stops; i++) { int no_of_entries, no_of_exits; scanf("%d %d",&no_of_exits, &no_of_entries); no_of_people_on_train += (no_of_entries - no_of_exits); minimum_capacity = max(minimum_capacity, no_of_people_on_train); } printf("%d\n", minimum_capacity); return 0; } ================================================ FILE: Explanations/Explanations 14/Vasya and String Explanation.txt ================================================ High school student Vasya got a string of length n as a birthday present. This string consists of letters 'a' and 'b' only. Vasya denotes beauty of the string as the maximum length of a substring (consecutive subsequence) consisting of equal letters. Vasya can change no more than k characters of the original string. What is the maximum beauty of the string he can achieve? ------------------------------------------ We need to find the maximum length substring that has k characters of one kind and any number of characters of the other kind. I learnt some cool tricks from a red person's code. One way to 'flip' the string is to write, a[i] = a^b^a[i]. This flips every position of the string. I maintained a window with two pointers and kept track of the number of changes. The number of changes increases whenever we encounter the type of character we want to change. As soon as the number of changes is greater than the maximum number of changes, change the position of window start. For example, |bbabbbabbaba|... and k = 3, we now have 3 a's inside the window bba|bbbabbaba|. Put the start one position ahead of the first 'a' you find. Find the maximum window length with k a's and any number of b's, and then do the same thing for k b's and any number of a's. ------------------------------------------------------- int get_max_window_length(char string[], char changed_char, int max_changes) { int max_window_length = 0, window_length = 0, no_of_changes = 0; for(int window_end = 0, window_start = 0; string[window_end] != '\0'; window_end++) { no_of_changes += (string[window_end] == changed_char); while(no_of_changes > max_changes) { no_of_changes -= (string[window_start++] == changed_char); } window_length = window_end - (window_start - 1); max_window_length = max(max_window_length, window_length); } return max_window_length; } int main() { int length, max_changes; char string[MAX_LENGTH]; scanf("%d %d %s", &length, &max_changes, string); int beauty = max(get_max_window_length(string, 'a', max_changes), get_max_window_length(string, 'b', max_changes)); printf("%d\n", beauty); return 0; } ================================================ FILE: Explanations/Explanations 15/Between the Offices Explanation.txt ================================================ As you may know, MemSQL has American offices in both San Francisco and Seattle. Being a manager in the company, you travel a lot between the two cities, always by plane. You prefer flying from Seattle to San Francisco than in the other direction, because it's warmer in San Francisco. You are so busy that you don't remember the number of flights you have made in either direction. However, for each of the last n days you know whether you were in San Francisco office or in Seattle office. You always fly at nights, so you never were at both offices on the same day. Given this information, determine if you flew more times from Seattle to San Francisco during the last n days, or not. -------------------------------------------------- Count the number of flights to both cities and compare which one is greater. -------------------------------------- int main() { int no_of_days; const int MAX_DAYS = 102; char flights[MAX_DAYS]; scanf("%d %s", &no_of_days, flights); int flights_from_seattle = 0, flights_to_seattle = 0; for(int i = 1; i < no_of_days; i++) { flights_to_seattle += (flights[i - 1] == 'F' && flights[i] == 'S'); flights_from_seattle += (flights[i - 1] == 'S' && flights[i] == 'F'); } printf("%s\n", flights_from_seattle > flights_to_seattle ? "YES" : "NO"); return 0; } ================================================ FILE: Explanations/Explanations 15/Cableway Explanation.txt ================================================ A group of university students wants to get to the top of a mountain to have a picnic there. For that they decided to use a cableway. A cableway is represented by some cablecars, hanged onto some cable stations by a cable. A cable is scrolled cyclically between the first and the last cable stations (the first of them is located at the bottom of the mountain and the last one is located at the top). As the cable moves, the cablecar attached to it move as well. The number of cablecars is divisible by three and they are painted three colors: red, green and blue, in such manner that after each red cablecar goes a green one, after each green cablecar goes a blue one and after each blue cablecar goes a red one. Each cablecar can transport no more than two people, the cablecars arrive with the periodicity of one minute (i. e. every minute) and it takes exactly 30 minutes for a cablecar to get to the top. All students are divided into three groups: r of them like to ascend only in the red cablecars, g of them prefer only the green ones and b of them prefer only the blue ones. A student never gets on a cablecar painted a color that he doesn't like, The first cablecar to arrive (at the moment of time 0) is painted red. Determine the least time it will take all students to ascend to the mountain top. ------------------------------------------------------------ First of all find the last ride. If the last ride happens at time t, then the answer is t + 30. Calculate the number of rides of each colour. The last ride is red if, - it is greater than the number of blue and green rides. The last ride is green if - it is >= red and > blue The last ride is blue if >= red and >= blue This is because if there's a tie, the rightmost element wins. The arrival time is calculated by 3*(no_of_rides of that colour - 1) + offset. The offset = 0 for red, 1 for green and 2 for blue. -------------------------------------------------------- int main() { int red, blue, green; scanf("%d %d %d", &red, &green, &blue); int red_rides = red/2 + red%2; int blue_rides = blue/2 + blue%2; int green_rides = green/2 + green%2; const int ONE_RIDE_DURATION = 30; int no_of_minutes, last_ride_arrival; if(red_rides > blue_rides && red_rides > green_rides) { last_ride_arrival = 3*(red_rides - 1); no_of_minutes = last_ride_arrival + ONE_RIDE_DURATION; } else if(green_rides >= red_rides && green_rides > blue_rides) { last_ride_arrival = 3*(green_rides - 1) + 1; no_of_minutes = last_ride_arrival + ONE_RIDE_DURATION; } else if(blue_rides >= red_rides && blue_rides >= green_rides) { last_ride_arrival = 3*(blue_rides - 1) + 2; no_of_minutes = last_ride_arrival + ONE_RIDE_DURATION; } printf("%d\n", no_of_minutes); return 0; } ================================================ FILE: Explanations/Explanations 15/Ciferia Explanation.txt ================================================ --------------------------------------------- Check if n is a power of k. If n = k^p, print p-1 ------------------------------------ int main() { int k, n; scanf("%d %d", &k, &n); int power = 0; while(n%k == 0) { n = n/k; power++; } printf(n > 1 ? "NO\n" : "YES\n%d\n", power - 1); return 0; } ================================================ FILE: Explanations/Explanations 15/Coins Explanation.txt ================================================ In Berland a money reform is being prepared. New coins are being introduced. After long economic calculations was decided that the most expensive coin should possess the denomination of exactly n Berland dollars. Also the following restriction has been introduced for comfort: the denomination of each coin should be divisible by the denomination of any cheaper coin. It is known that among all the possible variants the variant with the largest number of new coins will be chosen. Find this variant. Print in the order of decreasing of the coins' denominations. ----------------------------------- Have a look at the prime factorisation of n n = (p.p.p.p ... p). (q.q. .. q). (r.r. ... r) The number of numbers in the sequence can't be more than the number of prime numbers in n's prime factorisation. Because each term must have at least one term less than it's predecessor. We construct a sequence in which each term will have exactly one less prime number in it's prime factorisation. Divide n by each prime and insert the new n into the sequence till n becomes 1. -------------------------------------------- int main() { int n; scanf("%d", &n); vector denominations; denominations.push_back(n); for(int i = 2; n > 1; i++) { while(n%i == 0) { n = n/i; denominations.push_back(n); } } for(int i = 0; i < denominations.size(); i++) printf("%d ", denominations[i]); return 0; } ================================================ FILE: Explanations/Explanations 15/Divisibility by Eight Explanation.txt ================================================ You are given a non-negative integer n, its decimal representation consists of at most 100 digits and doesn't contain leading zeroes. Your task is to determine if it is possible in this case to remove some of the digits (possibly not remove any digit at all) so that the result contains at least one digit, forms a non-negative integer, doesn't have leading zeroes and is divisible by 8. After the removing, it is forbidden to rearrange the digits. If a solution exists, you should print it. ---------------------------------------------- The number of digits is only 100. So, I used a very simple algorithm. Iterate over all 1-digit, 2-digit and 3-digit numbers possible in the array. And check if any of them are multiples of 8. No need to check for 4 digits. Because if a number is 4 digit multiple, it will have a 3-digit suffix which will also be a multiple of 8. ------------------------------------------------------ int main() { string number; cin >> number; int found = false; int answer; typedef unsigned int u_int; for(u_int i = 0; i < number.size() && !found; i++) { if(number[i] == '8' || number[i] == '0') found = true, answer = number[i] - '0'; } for(u_int i = 0; i < number.size() && !found; i++) { for(u_int j = i + 1; j < number.size() && !found; j++) { int first_digit = number[i] - '0', second_digit = number[j] - '0'; int number_formed = 10*first_digit + second_digit; if(number_formed%8 == 0) found = true, answer = number_formed; } } for(u_int i = 0; i < number.size() && !found; i++) { for(u_int j = i + 1; j < number.size() && !found; j++) { for(u_int k = j + 1; k < number.size() && !found; k++) { int first_digit = number[i] - '0', second_digit = number[j]- '0', third_digit = number[k] - '0'; int number_formed = 100*first_digit + 10*second_digit + third_digit; if(number_formed%8 == 0) { answer = number_formed; found = true; } } } } if(found) printf("YES\n%d\n", answer); else printf("NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 15/Given Length and Sum of Digits.txt ================================================ You have a positive integer m and a non-negative integer s. Your task is to find the smallest and the largest of the numbers that have length m and sum of digits s. The required numbers should be non-negative integers written in the decimal base without leading zeroes. ------------------------------------------- How do we get the maximum number ? Use as many 9s as possible in the most significant digits and once we have no longer 9s left, we write whichever number we need to make up the sum and pad it with 0s. How do we get the minimum number ? Put a 1 in the first digit and put as many 0s after the 1 as possible. In other words, put as many 9s as possible from the back. And then put a 1 in the first digit. Number not posssible if sum = 0, and digits > 0. Number possible if sum = 0, d = 1, Answer = 0 -------------------------------------------------- int main() { int sum, no_of_digits; scanf("%d %d", &no_of_digits, &sum); if(sum == 0 && no_of_digits == 1) { printf("0 0\n"); return 0; } else if(sum == 0 || sum > 9*no_of_digits) { printf("-1 -1\n"); return 0; } vector minimum_number(no_of_digits + 1, 0); int remaining_sum = sum - 1, i; for(i = no_of_digits; i > 0 && remaining_sum > 0; i--) { if(remaining_sum >= 9) { minimum_number[i] = 9; remaining_sum -= 9; } else { minimum_number[i] = remaining_sum; remaining_sum = 0; } } minimum_number[1] = (minimum_number[1] == 0 ? 1 : minimum_number[1] + 1); vector maximum_number(no_of_digits + 1, 0); remaining_sum = sum; for(i = 1; i <= no_of_digits && remaining_sum > 0; i++) { if(remaining_sum >= 9) { maximum_number[i] = 9; remaining_sum -= 9; } else { maximum_number[i] = remaining_sum; remaining_sum = 0; } } for(int i = 1; i <= no_of_digits; i++) printf("%d", minimum_number[i]); printf(" "); for(int i = 1; i <= no_of_digits; i++) printf("%d", maximum_number[i]); return 0; } ================================================ FILE: Explanations/Explanations 15/Kefa and Park Explanation.txt ================================================ Kefa decided to celebrate his first big salary by going to the restaurant. He lives by an unusual park. The park is a rooted tree consisting of n vertices with the root at vertex 1. Vertex 1 also contains Kefa's house. Unfortunaely for our hero, the park also contains cats. Kefa has already found out what are the vertices with cats in them. The leaf vertices of the park contain restaurants. Kefa wants to choose a restaurant where he will go, but unfortunately he is very afraid of cats, so there is no way he will go to the restaurant if the path from the restaurant to his house contains more than m consecutive vertices with cats. Your task is to help Kefa count the number of restaurants where he can go. ------------------------------------------- This was my first ever DFS problem. In addition to the visited vector, keep a vector that keeps track of the number of consecutive cats ending at the current park. Go to the next park only if the number of consecutive cats <= m. It is a tree. So a leaf node will have only one edge (and we would have already visited that edge). So, the criteria for checking a leaf is (length == 1 && visited[tree[v][0]]) Increment the number of paths by 1 every time a leaf is encountered. (We are sure that if we have reached a leaf, no of consecutive cats never crossed m) Don't forget to initalise the number of cats at the root, and mark the root as visited before embarking on Depth First Search. For every park that is visited, go to all unvisited parks from there. ----------------------------------------------------------------------------- void dfs(int current_park, int &no_of_paths) { if(tree[current_park].size() == 1 && visited[tree[current_park][0]]) no_of_paths++; for(int i = 0; i < tree[current_park].size(); i++) { int next_park = tree[current_park][i]; if(!visited[next_park]) { visited[next_park] = true; no_of_consecutive_cats_till[next_park] = (has_cat[next_park] ? no_of_consecutive_cats_till[current_park] + 1 : 0); if(no_of_consecutive_cats_till[next_park] <= max_cats) dfs(next_park, no_of_paths); } } } int main() { int no_of_vertices; scanf("%d %d", &no_of_vertices, &max_cats); for(int i = 1; i <= no_of_vertices; i++) scanf("%d", &has_cat[i]); for(int i = 1; i <= no_of_vertices - 1; i++) { int x, y; scanf("%d %d", &x, &y); tree[x].push_back(y); tree[y].push_back(x); } no_of_consecutive_cats_till[1] = has_cat[1]; visited[1] = true; int no_of_paths = 0; dfs(1, no_of_paths); printf("%d\n", no_of_paths); return 0; } ================================================ FILE: Explanations/Explanations 15/Mahmoud and Ehab and the xor Explanation.txt ================================================ Mahmoud and Ehab are on the third stage of their adventures now. As you know, Dr. Evil likes sets. This time he won't show them any set from his large collection, but will ask them to create a new set to replenish his beautiful collection of sets. Dr. Evil has his favorite evil integer x. He asks Mahmoud and Ehab to find a set of n distinct non-negative integers such the bitwise-xor sum of the integers in it is exactly x. Dr. Evil doesn't like big numbers, so any number in the set shouldn't be greater than 106. ----------------------------------------------------- It was an interesting problem. If there wasn't a constraint of distinct numbers, then the answer could be x followed by n-1 0s. There was some connection to the fact that the nim-sum of three numbers can be 0. Here are the cases. Case 1 - n = 1 Ans = x Case 2 - n = 2 Ans = {0, x}, If x is 0, then there is no possible answer. It turns out, this the only time when there is no answer. Case 3 - n >= 3 First print all the numbers up to n - 3. Case 3a. XOR(1, 2, ..., n-3) = x In that case, we have to print 3 more numbers which are distinct and who's xor sum is 0. this can be done quite easily. One possible way is (2^n, 2^{n - 1}, 2^n|2^{n - 1}) Ensure 2^n is really large and not <= n - 2 Case 3b. b = XOR(1, 2, ... , n - 3) =/= x Now, we need three numbers, such that it neutralises b, and gives x and is not in that list. (XOR(2^n, b, x), 2^{n - 1}, 2^n|2^{n - 1}) is one such triplet. This leaves the answer = x --------------------------------------------------------- int main() { int no_of_numbers, x; scanf("%d %d", &no_of_numbers, &x); if(no_of_numbers == 1) { printf("YES\n%d\n", x); } else if(no_of_numbers == 2) { if(x == 0) printf("NO\n"); else printf("YES\n0 %d\n", x); } else { const int POWER_2 = 1 << 19, PREVIOUS_POWER_2 = 1 << 18; int bitwise_xor = 0; printf("YES\n"); for(int i = 1; i <= no_of_numbers - 3; i++) { bitwise_xor ^= i; printf("%d ", i); } if(bitwise_xor == x) printf("%d %d %d\n", POWER_2, PREVIOUS_POWER_2, (POWER_2|PREVIOUS_POWER_2)); else printf("%d %d %d\n", PREVIOUS_POWER_2, (POWER_2^bitwise_xor^x), (POWER_2|PREVIOUS_POWER_2)); } return 0; } ================================================ FILE: Explanations/Explanations 15/Number of Ways Explanation.txt ================================================ ----------------------------------------------------- Each part of the array must have sum = S/3. One naive way to implement this is for each i, such that S[i] = S/3, Count the number of j, such that S[j] - S[i] = S/3 and j < n. This works in O(n^2) time. There is a faster way to do this. Precompute suffix sums. Maintain a new function, where f(i) = the number of j's such that i <=j <= n, S[n] - S[j - 1] = S/3 Then, for each i such that S[i] = S/3, ans += f(i + 2) [Because the parts must be seperated] This works in O(n) time. f(n + 1) = 0 f(i) = f(i + 1) + (S[n] - S[i - 1] == S/3) -------------------------------------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { int element_i; scanf("%d", &element_i); sum_till[i] = sum_till[i - 1] + element_i; } vector sum_from(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { sum_from[i] = sum_till[no_of_elements] - sum_till[i - 1]; } long long no_of_ways = 0, total_sum = sum_till[no_of_elements]; if(total_sum%3 != 0) { printf("%I64d\n", no_of_ways); return 0; } vector no_of_places_that_sum_to_a_third_from(no_of_elements + 2, 0); for(int i = no_of_elements; i >= 1; i--) { no_of_places_that_sum_to_a_third_from[i] = no_of_places_that_sum_to_a_third_from[i + 1] + (3*sum_from[i] == total_sum); } for(int i = 1; i <= no_of_elements - 2; i++) { if(3*sum_till[i] == total_sum) { no_of_ways += no_of_places_that_sum_to_a_third_from[i + 2]; } } printf("%I64d\n", no_of_ways); return 0; } ================================================ FILE: Explanations/Explanations 15/Pearls in a Row Explanation.txt ================================================ There are n pearls in a row. Let's enumerate them with integers from 1 to n from the left to the right. The pearl number i has the type ai. Let's call a sequence of consecutive pearls a segment. Let's call a segment good if it contains two pearls of the same type. Split the row of the pearls to the maximal number of good segments. Note that each pearl should appear in exactly one segment of the partition. ----------------------------------------------------------------- Be greedy about the arrangement. Set the first boundary as soon as you find an element occuring twice. If at the end, we have k segments and there are some elements at the end that don't belong to any segment, add them to the k-th segment. The k-th segment anyway has an element that occurs at least twice. Adding more elements to this segment doesn't change this property. Hence, the segment remains good. --------------------------------------------- int main() { int no_of_pearls; scanf("%d", &no_of_pearls); set current_segment_pearls; vector > segment; int left = 1; for(int right = 1; right <= no_of_pearls; right++) { int pearl_type; scanf("%d", &pearl_type); if(current_segment_pearls.count(pearl_type) == 1) { segment.push_back(make_pair(left, right)); current_segment_pearls.clear(); left = right + 1; } else { current_segment_pearls.insert(pearl_type); } } if(segment.size() == 0) printf("-1\n"); else { segment.back().second = max(segment.back().second, no_of_pearls); printf("%u\n", segment.size()); for(int i = 0; i < segment.size(); i++) printf("%d %d\n", segment[i].first, segment[i].second); } return 0; } ================================================ FILE: Explanations/Explanations 15/Pie Rules Explanation.txt ================================================ You may have heard of the pie rule before. It states that if two people wish to fairly share a slice of pie, one person should cut the slice in half, and the other person should choose who gets which slice. Alice and Bob have many slices of pie, and rather than cutting the slices in half, each individual slice will be eaten by just one person. The way Alice and Bob decide who eats each slice is as follows. First, the order in which the pies are to be handed out is decided. There is a special token called the "decider" token, initially held by Bob. Until all the pie is handed out, whoever has the decider token will give the next slice of pie to one of the participants, and the decider token to the other participant. They continue until no slices of pie are left. All of the slices are of excellent quality, so each participant obviously wants to maximize the total amount of pie they get to eat. Assuming both players make their decisions optimally, how much pie will each participant receive? --------------------------------------------- Let A(i) denote the maximum amount of pie Alice can get starting from the i-th piece if she has the decided token at piece i. Let B(i) denote the same thing for Bob. So, at each piece there are two choices - either you take the piece and give the other person the decider token - this is = pie[i] + total_sum_from[i + 1] - B(i + 1) or you keep the decider token and keep the piece = A(i + 1). So, A(i) = max{A(i + 1), pie[i] + (sum_from[i + 1] - B(i + 1) )} [Alice gets the remainder of whatever Bob takes when Bob starts with decider token from (i + 1). B(i) = max{B(i + 1), pie[i] + (sum_from[i + 1] - A(i + 1) )} Answer = B(1), and Sum From[1] - Bob(1) ----------------------------------------------- int main() { int no_of_pieces; scanf("%d", &no_of_pieces); vector pie(no_of_pieces + 1); for(int i = 1; i <= no_of_pieces; i++) scanf("%d", &pie[i]); vector sum_from(no_of_pieces + 3, 0); const int NO_OF_PLAYERS = 2, ALICE = 0, BOB = 1; int maximum_from[no_of_pieces + 1][NO_OF_PLAYERS]; for(int i = no_of_pieces; i >= 1; i--) { sum_from[i] = pie[i] + sum_from[i + 1]; if(i == no_of_pieces) { maximum_from[i][ALICE] = maximum_from[i][BOB] = pie[i]; } else { maximum_from[i][ALICE] = max(maximum_from[i + 1][ALICE], pie[i] + sum_from[i + 1] - maximum_from[i + 1][BOB]); maximum_from[i][BOB] = max(maximum_from[i + 1][BOB], pie[i] + sum_from[i + 1] - maximum_from[i + 1][BOB]); } } int maximum_for_alice = sum_from[1] - maximum_from[1][BOB]; printf("%d %d\n", maximum_for_alice, maximum_from[1][BOB]); return 0; } ================================================ FILE: Explanations/Explanations 15/Quasi-palindrome Explanation.txt ================================================ --------------------------------------------- Check if n is a palindrome without trailing 0s. ------------------------------------ int is_palindrome(int n) { int reverse_n = 0, original_n = n; while(n > 0) { reverse_n = reverse_n*10 + n%10; n = n/10; } return (reverse_n == original_n); } int palindrome_without_trailing_zeroes(int n) { while(n%10 == 0) n = n/10; return is_palindrome(n); } int main() { int n; scanf("%d", &n); printf("%s\n", palindrome_without_trailing_zeroes(n) ? "YES" : "NO"); return 0; } ================================================ FILE: Explanations/Explanations 15/Team Explanation.txt ================================================ Now it's time of Olympiads. Vanya and Egor decided to make his own team to take part in a programming Olympiad. They've been best friends ever since primary school and hopefully, that can somehow help them in teamwork. For each team Olympiad, Vanya takes his play cards with numbers. He takes only the cards containing numbers 1 and 0. The boys are very superstitious. They think that they can do well at the Olympiad if they begin with laying all the cards in a row so that: there wouldn't be a pair of any side-adjacent cards with zeroes in a row; there wouldn't be a group of three consecutive cards containing numbers one. Today Vanya brought n cards with zeroes and m cards with numbers one. The number of cards was so much that the friends do not know how to put all those cards in the described way. Help them find the required arrangement of the cards or else tell the guys that it is impossible to arrange cards in such a way. -------------------------------------------------------- If the number of 1s are far more than the number of 0s, we can arrange them like this. 11 0 11 0 11 0 .. .0 .. 0 Basically the 0s act like dividers. If there are z zeroes, then there are z+1 boxes for the 1s. If the number of 1s, o > 2*(z + 1), One of the boxes will have more than 2 1s by the Pigeonhole Principle. What about the bound on the number of 0s ? If we look at the string and think of the 1s as seperators, then there can be at most o + 1 boxes. z > o + 1, cannot satisfy the equation. Now, how do we print such a string ? Trick is to be greedy. If the number of 1s is greater than the number of 0s, print 110, If the number of 1s are equal to the number of 0s, print 10. If the number of 1s is less than the number of 0s, print Do this as long as both o AND z are > 0. Once one of them becomes 0, print the other character to the required frequency. ------------------------------------------ int main() { int no_of_1s, no_of_0s; scanf("%d %d", &no_of_0s, &no_of_1s); if(no_of_1s > 2*(no_of_0s + 1) || no_of_0s > no_of_1s + 1) { printf("-1\n"); return 0; } while(no_of_0s > 0 && no_of_1s > 0) { if(no_of_1s > no_of_0s) { printf("110"); no_of_1s -= 2, no_of_0s--; } else if(no_of_1s == no_of_0s) { printf("10"); no_of_0s--, no_of_1s--; } else if(no_of_1s < no_of_0s) { printf("01"); no_of_0s--, no_of_1s--; } } for(int i = 1; i <= no_of_0s; i++) printf("0"); for(int i = 1; i <= no_of_1s; i++) printf("1"); return 0; } ================================================ FILE: Explanations/Explanations 15/Triangle Explanation.txt ================================================ Johnny has a younger sister Anne, who is very clever and smart. As she came home from the kindergarten, she told his brother about the task that her kindergartener asked her to solve. The task was just to construct a triangle out of four sticks of different colours. Naturally, one of the sticks is extra. It is not allowed to break the sticks or use their partial length. Anne has perfectly solved this task, now she is asking Johnny to do the same. The boy answered that he would cope with it without any difficulty. However, after a while he found out that different tricky things can occur. It can happen that it is impossible to construct a triangle of a positive area, but it is possible to construct a degenerate triangle. It can be so, that it is impossible to construct a degenerate triangle even. As Johnny is very lazy, he does not want to consider such a big amount of cases, he asks you to help him. -------------------------------------- Check if it's possible to form a triangle, then check if it's possible to form a segment. -------------------------------------------- int triangle(int side_a, int side_b, int side_c) { return ( (side_a + side_b > side_c) && (side_b + side_c > side_a) && (side_c + side_a > side_b) ); } int segment(int side_a, int side_b, int side_c) { return ( (side_a + side_b == side_c) || (side_b + side_c == side_a) || (side_c + side_a == side_b) ); } int main() { int side_a, side_b, side_c, side_d; scanf("%d %d %d %d", &side_a, &side_b, &side_c, &side_d); if(triangle(side_a, side_b, side_c) || triangle(side_b, side_c, side_d) || triangle(side_c, side_d, side_a) || triangle(side_b, side_a, side_d) ) printf("TRIANGLE\n"); else if(segment(side_a, side_b, side_c) || segment(side_b, side_c, side_d) || segment(side_c, side_d, side_a) || segment(side_b, side_a, side_d) ) printf("SEGMENT\n"); else printf("IMPOSSIBLE\n"); return 0; } ================================================ FILE: Explanations/Explanations 15/USB Flash Drives Explanation.txt ================================================ ---------------------------------------------- Use the largest files first. ---------------------------------- int main() { int no_of_drives, file_size; scanf("%d %d", &no_of_drives, &file_size); vector capacity(no_of_drives); for(int i = 0; i < no_of_drives; i++) scanf("%d", &capacity[i]); sort(all(capacity)); int no_of_drives_used = 0; for(int drive_i = no_of_drives - 1; file_size > 0 && drive_i >= 0; drive_i--, no_of_drives_used++) file_size -= capacity[drive_i]; printf("%d\n", no_of_drives_used); return 0; } ================================================ FILE: Explanations/Explanations 16/Amusing Joke Explanation.txt ================================================ The sum of frequencies of each letter in the first two names = frequency in third name. So, I incremented frequency in first two strings and decremented in third string and checked if it is 0 at the end. ------------------------------------------------ int main() { const int NO_OF_ALPHABETS = 26; int frequency[NO_OF_ALPHABETS] = {0}; for(int i = 1; i <= 3; i++) { const int MAX_LENGTH = 103; char name[MAX_LENGTH]; scanf("%s", name); for(int j = 0; name[j] != '\0'; j++) frequency[name[j] - 'A'] += (i == 3 ? -1 : 1); } int is_possible = true; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(frequency[i] != 0) is_possible = false; printf(is_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 16/Anton and Letters Explanation.txt ================================================ Read a line with white spaces. int main() { string line; getline(cin, line); set letters; for(int i = 0; i < line.size(); i++) { if(is_alpha(line[i])) letters.insert(line[i]); } cout << letters.size(); return 0; } ================================================ FILE: Explanations/Explanations 16/Cards with Numbers Explanation.txt ================================================ Easy question. The tricky part is the files. -------------------------------- struct card { int index, value; }; bool sort_by_value(const card &A, const card &B) { return (A.value < B.value); } int main() { FILE *input = fopen("input.txt", "r"); int no_of_cards; fscanf(input, "%d", &no_of_cards); vector cards(2*no_of_cards); for(int i = 0; i < 2*no_of_cards; i++) { fscanf(input, "%d", &cards[i].value); cards[i].index = i + 1; } sort(all(cards), sort_by_value); FILE *output = fopen("output.txt", "w"); vector > solution; for(int i = 0; i < 2*no_of_cards; i += 2) { if(cards[i].value == cards[i + 1].value) solution.push_back(make_pair(cards[i].index, cards[i + 1].index)); else { fprintf(output, "-1\n"); return 0; } } for(int i = 0; i < no_of_cards; i++) fprintf(output, "%d %d\n", solution[i].first, solution[i].second); fclose(input); fclose(output); return 0; } ================================================ FILE: Explanations/Explanations 16/Classroom Watch Explanation.txt ================================================ Eighth-grader Vova is on duty today in the class. After classes, he went into the office to wash the board, and found on it the number n. He asked what is this number and the teacher of mathematics Inna Petrovna answered Vova that n is the answer to the arithmetic task for first-graders. In the textbook, a certain positive integer x was given. The task was to add x to the sum of the digits of the number x written in decimal numeral system. Since the number n on the board was small, Vova quickly guessed which x could be in the textbook. Now he wants to get a program which will search for arbitrary values of the number n for all suitable values of x or determine that such x does not exist. Write such a program for Vova. ---------------------------------------------- The maximum sum of digits of any number within the range is 81. So, for any n, we only need to check from (n - 81) to see if any number satisfies the condition. ---------------------------------------------------------------- int main() { int n; scanf("%d", &n); const int MAX_DIGIT_SUM = 81; int x = max(0, n - MAX_DIGIT_SUM); vector answer; while(x <= n) { if(x + digit_sum(x) == n) answer.push_back(x); x++; } printf("%d\n", answer.size()); for(int i = 0; i < answer.size(); i++) printf("%d ", answer[i]); return 0; } ================================================ FILE: Explanations/Explanations 16/Cupboards Explanation.txt ================================================ Keep track of the open doors on the left and right. The number of operations on either side is whichever position occurs less times. The answer is the sum of the right and left. int main() { const int OPEN = 1, CLOSED = 0; int no_of_cupboards; scanf("%d", &no_of_cupboards); int left_open_doors = 0, left_closed_doors = 0; int right_open_doors = 0, right_closed_doors = 0; while(no_of_cupboards--) { int left, right; scanf("%d %d", &left, &right); left_open_doors += (left == OPEN); left_closed_doors += (left == CLOSED); right_open_doors += (right == OPEN); right_closed_doors += (right == CLOSED); } int minimum_left_operations = min(left_closed_doors, left_open_doors); int minimum_right_operations = min(right_open_doors, right_closed_doors); printf("%d\n", minimum_left_operations + minimum_right_operations); return 0; } ================================================ FILE: Explanations/Explanations 16/Dishonest Sellers Explanation.txt ================================================ Here's the main idea - If we did not have the restriction of buying k from now, we'd buy every item whenever it is cheaper. So, we buy k items from now greedily and the REMAINING n - k items, we choose from whichever day is cheaper. How do we choose these k items ? It's not the k items who's cost now is the cheapest. Let's say we buy every item on second day, Cost = C = B1 + B2 + B3 + ... + Bn. Now, we HAVE TO buy some of these on day 1. How do we choose this ? Let's say we buy item 1 now. Cost increases by (A1 - B1). [This may be negative]. i.e. C' = C + (A1 - B1) Now, our task is to choose k items to buy now such that we MINIMISE the rise in C. So, what we do is we choose k items from now such that (A1 - B1) is minimum. In short, 1. Buy k items who's difference (A1 - B1) is minimum. 2. From K+1 to N, buy the item whenever it is cheaper - now or one week later. min{Ai, Bi} Important to note that the difference should NOT be in terms of absolute value. We want to buy the ones with the negative difference now, because it means it will be more expensive next week. --------------------------------------------------------------------------------------------------------------- #define all(v) (v).begin(), (v).end() struct prices { int now, discount, difference; }; bool sort_By_Difference(const prices &A, const prices &B) { return (A.difference < B.difference); } int main() { int no_of_days, minimum_now_buys; scanf("%d %d", &no_of_days, &minimum_now_buys); vector price(no_of_days); for(int i = 0; i < no_of_days; i++) scanf("%d", &price[i].now); for(int i = 0; i < no_of_days; i++) scanf("%d", &price[i].discount); for(int i = 0; i < no_of_days; i++) price[i].difference = price[i].now - price[i].discount; sort(all(price), sort_By_Difference); int money_used = 0; for(int i = 0; i < no_of_days; i++) { if(i < minimum_now_buys) money_used += price[i].now; else money_used += min(price[i].now, price[i].discount); } printf("%d\n", money_used); return 0; } ================================================ FILE: Explanations/Explanations 16/Dubstep Explanation.txt ================================================ String implementation problem. If you get a WUB at any point of time, Check if word is not empty, if it isn't, then print it and clear it. Otherwise, add the current letter to word. Print the word at the end if it is empty ---------------------------------------------------- int main() { string song; cin >> song; string word; for(int i = 0; i < song.length(); i++) { if(i + 2 < song.length() && song[i] == 'W' && song[i + 1] == 'U' && song[i + 2] == 'B') { i += 2; if(!word.empty()) { cout << word << " "; word.clear(); } } else { word += song[i]; } } if(!word.empty()) cout << word << " "; return 0; } ================================================ FILE: Explanations/Explanations 16/Easy Number Challenge Explanation.txt ================================================ Note - the constraints are pretty small, Since, a, b, c <= 100. O(abc) solution will be accepted. Precompute d(n) for all n <= 10^6. The precomputation can be done using a sieve. It is a multiplicative function. If n = p^a n', where gcd(p, n) = 1, Then d(n) = (a + 1). d(n'). Use this to compute d(n). ---------------------------------------------------- void precompute(vector &number_of_divisors, int LIMIT) { number_of_divisors[1] = 1; vector largest_prime_factor(LIMIT + 1, 0); for(int i = 2; i <= LIMIT; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple <= LIMIT; multiple += i) largest_prime_factor[multiple] = i; } int exponent = 0; int reduced_i = i; while(reduced_i%largest_prime_factor[i] == 0) { reduced_i /= largest_prime_factor[i]; exponent++; } number_of_divisors[i] = (exponent + 1)*number_of_divisors[reduced_i]; } } int main() { const int LIMIT = 1e6; vector number_of_divisors(LIMIT + 1, 0); precompute(number_of_divisors, LIMIT); int a, b, c; scanf("%d %d %d", &a, &b, &c); int sum = 0; for(int i = 1; i <= a; i++) { for(int j = 1; j <= b; j++) { for(int k = 1; k <= c; k++) { sum += number_of_divisors[i*j*k]; } } } printf("%d\n", sum); return 0; } ================================================ FILE: Explanations/Explanations 16/Fox and Snake Explanation.txt ================================================ Implementation problem int main() { int rows, columns; scanf("%d %d", &rows, &columns); for(int i = 1; i <= rows; i++) { int different_cell = -1; char default_char = (i%2 == 0 ? '.' : '#'); if(i%2 == 0) different_cell = (i%4 == 0 ? 1 : columns); for(int j = 1; j <= columns; j++) printf("%c", (j != different_cell ? default_char : '#')); printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 16/Greg and Array Explanation.txt ================================================ A very interesting concept. Suppose you have an array of n elements. And Q queries, each characterised by - left and right. In one query, you must add 1 to every number from left to right. Print the array after all the queries The naive way of doing this. for(int i = 1; i <= Q; i++) { for(int j = l; j <= R; j++) A[j]++; } This is O(NQ) If N and Q are both 10^5, then you will 10^10 operations (or thereabouts) --- that's months of time. There's a better way. Have an array C, that keeps track of the number of operations that start at C for(int i = 1; i <= Q; i++) { C[l]++; C[r + 1]--; } for(int i = 1; i <= N; i++) A[i] = A[i - 1] + C[i] In other words, the number of queries affecting previous term plus the number of queries starting at that position. Of course, if there's a query affecting (i - 1) but not i, then C[i] will accordingly reduce it. This is O(N + Q). Can be done in under a second with the same constraints. This question is interersting because this logic has to be applied twice. 1. Apply it on the operations so that you know the number of times each operation is used. 2. After it is known the number of times each operation is used. for(i = 1 to no of operations) { Updates[operations[i].left] += use[i]*operations[i].value Updates[operations[i].right + 1] -= use[i]*operations[i].value } for(i = 1 to no of elements) { amount to be added[i] = amount to be added[i - 1] + Udates[i] } And then for(i = 1 to no of elements) element[i] += amount to be added[i] ---------------------------------------------------------------------------------------------------------- struct operation { int left, right, value; }; int main() { int no_of_elements, no_of_operations, no_of_queries; scanf("%d %d %d", &no_of_elements, &no_of_operations, &no_of_queries); vector element(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &element[i]); vector operations(no_of_operations + 1); for(int i = 1; i <= no_of_operations; i++) scanf("%d %d %d", &operations[i].left, &operations[i].right, &operations[i].value); vector no_of_operations_starting(no_of_operations + 2, 0); while(no_of_queries--) { int left_operation, right_operation; scanf("%d %d", &left_operation, &right_operation); no_of_operations_starting[left_operation]++; no_of_operations_starting[right_operation + 1]--; } vector no_of_uses(no_of_operations + 1, 0); for(int i = 1; i <= no_of_operations; i++) no_of_uses[i] = no_of_uses[i - 1] + no_of_operations_starting[i]; vector no_of_updates_starting(no_of_elements + 2, 0); for(int i = 1; i <= no_of_operations; i++) { int start_point = operations[i].left, end_point = operations[i].right, d = operations[i].value; no_of_updates_starting[start_point] += no_of_uses[i]*1LL*d; no_of_updates_starting[end_point + 1]-= no_of_uses[i]*1LL*d; } vector amount_to_be_added(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) amount_to_be_added[i] = amount_to_be_added[i - 1] + no_of_updates_starting[i]; for(int i = 1; i <= no_of_elements; i++) element[i] += amount_to_be_added[i]; for(int i = 1; i <= no_of_elements; i++) printf("%I64d ", element[i]); return 0; } ================================================ FILE: Explanations/Explanations 16/Hacking Cypher Explanation.txt ================================================ I was very proud of myself for being able to do this one. Firstly, how do you brute force such a thing ? Well, break the string at every possible point and see if the prefix is divisible by a and suffix by b. Now, since this is a string of numbers and not a single number, this takes O(n^2). Using Horner's Method, find p(i), where p(i) denotes the remainder of the prefix ending at i with a. And s(i) = suffix of string starting from b with i. Check if there's a point where p(i) = 0, s(i + 1) = 0 and i+1 th digit is not 0. Also ensure the first digit is not 0. Now, calculating p(i) is easy p(1) = N(1)%a p(i) = { 10*p(i - 1) + N(i) }%a s(last digit) = N(last digit)%b s(i) = { 10^l *N(i) + s(i + 1) }%b, where l is the numbre of digits from i+1 to the end. -------------------------------------------------- int main() { int a, b; string number; cin >> number >> a >> b; int no_of_numbers = number.size(); vector remainder_a_till(no_of_numbers); remainder_a_till[0] = (number[0] - '0')%a; for(int i = 1 ; number[i] != '\0'; i++) { remainder_a_till[i] = (10*remainder_a_till[i - 1] + number[i] - '0')%a; } vector remainder_b_from(no_of_numbers); remainder_b_from[no_of_numbers - 1] = (number[no_of_numbers - 1] - '0')%b; for(int i = no_of_numbers - 2, ten_power = 10; i >= 0; i--) { remainder_b_from[i] = (ten_power*(number[i] - '0') + remainder_b_from[i + 1])%b; ten_power = (ten_power*10)%b; } int end_of_a = -1; for(int i = 0; i + 1 < no_of_numbers; i++) { if(remainder_a_till[i] == 0 && remainder_b_from[i + 1] == 0 && number[i + 1] != '0') end_of_a = i; } if(end_of_a == -1 || number[0] == '0') { printf("NO\n"); return 0; } printf("YES\n"); for(int i = 0; i <= end_of_a; i++) printf("%c", number[i]); printf("\n"); for(int i = end_of_a + 1; i < no_of_numbers; i++) printf("%c", number[i]); return 0; } ================================================ FILE: Explanations/Explanations 16/I Wanna Be The Guy Explanation.txt ================================================ Just keep track of the number of levels that have been crossed and check if there's any level not covered. int main() { int no_of_levels; scanf("%d", &no_of_levels); int crossed_levels[no_of_levels + 1] = {false}; int x_levels; scanf("%d", &x_levels); while(x_levels--) { int level; scanf("%d", &level); crossed_levels[level] = true; } int y_levels; scanf("%d", &y_levels); while(y_levels--) { int level; scanf("%d", &level); crossed_levels[level] = true; } int possible = true; for(int i = 1; i <= no_of_levels; i++) if(!crossed_levels[i]) possible = false; printf(possible ? "I become the guy." : "Oh, my keyboard!"); return 0; } ================================================ FILE: Explanations/Explanations 16/IQ Test Explanation.txt ================================================ Just check every 2x2 square if the frequency of either colour >= 3. int possible_to_make_square(char square[][5], int x, int y) { int black = (square[x][y] == '#') + (square[x - 1][y] == '#') + (square[x - 1][y - 1] == '#') + (square[x][y - 1] == '#'); int white = (square[x][y] == '.') + (square[x - 1][y] == '.') + (square[x - 1][y - 1] == '.') + (square[x][y - 1] == '.'); return (black >= 3 || white >= 3); } int main() { const int N = 4; char square[N + 1][N + 1]; for(int i = 0; i < N; i++) scanf("%s", square[i]); int is_possible = false; for(int i = 1; i < 4; i++) { for(int j = 1; j < 4; j++) { if(possible_to_make_square(square, i, j)) is_possible = true; } } printf(is_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 16/Jeff and Periods Explanation.txt ================================================ For every number, maintain the following information - The last index it occurs, The second last index it occurs, The difference of it's AP. Whenever a new occurence occurs at i, check if i - last = last - second_last If not, then an AP is not possible. Be careful about the first and second occurence of the number. ------------------------------------------------------------------------- const int NOT_POSSIBLE = -1, MAX_ELEMENTS = 1e5 + 1; struct number { int last_index, second_last_index, difference; number(){ last_index = second_last_index = 0; difference = NOT_POSSIBLE;} }; int main() { number elements[MAX_ELEMENTS]; int no_of_elements; scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) { int n; scanf("%d", &n); if(elements[n].last_index == 0) { elements[n].last_index = i; elements[n].difference = 0; } else if(elements[n].second_last_index == 0) { elements[n].second_last_index = elements[n].last_index; elements[n].last_index = i; elements[n].difference = elements[n].last_index - elements[n].second_last_index; } else { if(i - elements[n].last_index == elements[n].difference) { elements[n].second_last_index = elements[n].last_index; elements[n].last_index = i; } else { elements[n].difference = NOT_POSSIBLE; } } } int no_of_aps = 0; for(int i = 1; i < MAX_ELEMENTS; i++) no_of_aps += (elements[i].difference != NOT_POSSIBLE); printf("%d\n", no_of_aps); for(int i = 1; i < MAX_ELEMENTS; i++) if(elements[i].difference != NOT_POSSIBLE) printf("%d %d\n", i, elements[i].difference); return 0; } ================================================ FILE: Explanations/Explanations 16/Pashmak and Garden Explanation.txt ================================================ Okay, if the x1 = x2, then it means we have a side parallel to y-axis. x3 = x1 + d, y3 = y1 x4 = x2 + 3, y4 = y2 Similar reasoning if y1 = y2, now, what happens if we have two diagonally opposite points ? Then, |x1 - x2| = |y1 - y2| This quantity is the same in squares. We are taking absolute values because it might be anti-diagonal as well. int main() { int x_1, x_2, y_1, y_2; scanf("%d %d %d %d", &x_1, &y_1, &x_2, &y_2); int x_3, y_3, x_4, y_4; if(x_1 == x_2) { int distance = abs(y_1 - y_2); x_3 = x_1 + distance; y_3 = y_1; x_4 = x_2 + distance; y_4 = y_2; } else if(y_1 == y_2) { int distance = abs(x_1 - x_2); y_3 = y_1 + distance; x_3 = x_1; y_4 = y_2 + distance; x_4 = x_2; } else if(abs(x_1 - x_2) == abs(y_1 - y_2)) { x_3 = x_1; y_3 = y_2; x_4 = x_2; y_4 = y_1; } else { printf("-1\n"); return 0; } printf("%d %d %d %d\n", x_3, y_3, x_4, y_4); return 0; } ================================================ FILE: Explanations/Explanations 16/Primes or Palindromes Explanation.txt ================================================ Okay, the problem is hard because of analysing the limits. I couldn't do that. But, I saw the editorial and it said two things 1. There is always an answer in the specified range. 2. The answer is always less than 2 million. From there, it was easy. Precompute pi(n) using a sieve. Precompute the palindromes too. This happens in roughly three linear scans. Since, there's only one query, answer it using another linear scan. ---------------------------------------------------------------------- int reverse(int n) { int rev = 0; while(n) { rev = rev*10 + n%10; n /= 10; } return rev; } int is_palindrome(int n) { return (n == reverse(n)); } void precompute(vector &no_of_primes_till, vector &no_of_palindromes_till, int LIMIT) { vector is_prime(LIMIT + 1, true); is_prime[0] = is_prime[1] = false; vector primes; for(int i = 2; i <= LIMIT; i++) { if(is_prime[i]) primes.push_back(i); for(int j = 0; j < primes.size() && i*primes[j] < LIMIT; j++) { is_prime[i*primes[j]] = false; if(i%primes[j] == 0) break; } } for(int i = 1; i <= LIMIT; i++) no_of_primes_till[i] = no_of_primes_till[i - 1] + is_prime[i]; for(int i = 1; i <= LIMIT; i++) no_of_palindromes_till[i] = no_of_palindromes_till[i - 1] + is_palindrome(i); } int main() { const int LIMIT = 2e6; vector no_of_primes_till(LIMIT + 1, 0); vector no_of_palindromes_till(LIMIT + 1, 0); precompute(no_of_primes_till, no_of_palindromes_till, LIMIT); int p, q; scanf("%d %d", &p, &q); for(int n = LIMIT; n >= 1; n--) { if(q*no_of_primes_till[n] <= p*no_of_palindromes_till[n]) { printf("%d\n", n); break; } } return 0; } ================================================ FILE: Explanations/Explanations 16/Quasi Binary Explanation.txt ================================================ Here's the idea ... Imagine, towers of height - a1, a2, a3, ... an Need to be built. In one move, you are allowed to place exactly one brick in one or more towers at the same level. Proceed greedily. The number of moves = max{a1, a2, ... , an} If it is 345 111, 11, 1 Keep placing bricks in a certain tower till the height is reached. ------------------------------------------------------------------------- int main() { int n; scanf("%d", &n); const int MAX_SIZE = 7; vector no_of_bits(MAX_SIZE + 1, 0); int greatest_bit = 0; for(int i = 0; n > 0; i++) { no_of_bits[i] = n%10; n /= 10; greatest_bit = max(greatest_bit, no_of_bits[i]); } printf("%d\n", greatest_bit); for(int i = 1; i <= greatest_bit; i++) { int number = 0; for(int j = no_of_bits.size() - 1; j >= 0; j--) { number *= 10; if(no_of_bits[j] > 0) number++; no_of_bits[j]--; } printf("%d ", number); } return 0; } ================================================ FILE: Explanations/Explanations 16/Sereja and Bottles Explanation.txt ================================================ I kept trying to come up with an O(n) solution but it had lots of bugs. Here's an O(n) solution. int main() { int no_of_bottles; scanf("%d", &no_of_bottles); vector brand(no_of_bottles + 1, 0); vector can_open(no_of_bottles + 1, 0); for(int i = 1; i <= no_of_bottles; i++) scanf("%d %d", &brand[i], &can_open[i]); int impossible_bottles = 0; for(int i = 1; i <= no_of_bottles; i++) { int openable = false; for(int j = 1; j <= no_of_bottles; j++) { if(can_open[j] == brand[i] && i != j) openable = true; } impossible_bottles += (!openable); } printf("%d\n", impossible_bottles); return 0; } ================================================ FILE: Explanations/Explanations 16/Team Olympiad Explanation.txt ================================================ Simple implementation The number of teams is the minimum of the three categories. int main() { vector mathematician; vector programmer; vector sportsperson; int no_of_players; scanf("%d", &no_of_players); for(int i = 1; i <= no_of_players; i++) { int activity; scanf("%d", &activity); switch(activity) { case 1: mathematician.push_back(i); break; case 2: programmer.push_back(i); break; case 3: sportsperson.push_back(i); break; } } int no_of_teams = min_3(mathematician.size(), programmer.size(), sportsperson.size()); printf("%d\n", no_of_teams); for(int i = 1; i <= no_of_teams; i++) printf("%d %d %d\n", mathematician[i - 1], programmer[i - 1], sportsperson[i - 1]); return 0; } ================================================ FILE: Explanations/Explanations 16/The Fibonacci Segment Explanation.txt ================================================ It's a longest increasing subsequence problem. Quite interesting. Let f(i) denote the longest increasing segement ending at i. f(1) = 1, f(i) = (A[i] == A[i - 1] + A[i - 2] ? f(i - 1) + 1 : 2) Ans = max{f(i)} ------------------------------------------------------------------ int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); vector longest_segment_ending(no_of_elements + 1, 1); int longest_segment = 1; for(int i = 2; i <= no_of_elements; i++) { if(i == 2) longest_segment_ending[i] = 2; else longest_segment_ending[i] = (element[i] == element[i - 1] + element[i - 2] ? longest_segment_ending[i - 1] + 1 : 2); longest_segment = max(longest_segment, longest_segment_ending[i]); } printf("%d\n", longest_segment); return 0; } ================================================ FILE: Explanations/Explanations 16/Twins Explanation.txt ================================================ Sort the array and choose the largest elements until the sum of the coins taken, is greater than the remaining sum. int main() { int no_of_coins; scanf("%d", &no_of_coins); int total = 0; vector coin(no_of_coins); for(int i = 0; i < no_of_coins; i++) { scanf("%d", &coin[i]); total += coin[i]; } sort(all(coin)); int no_of_coins_taken = 0, sum_of_taken = 0; for(int i = no_of_coins - 1; i >= 0 && sum_of_taken <= total ; i--) { sum_of_taken += coin[i]; total -= coin[i]; no_of_coins_taken++; } printf("%d\n", no_of_coins_taken); return 0; } ================================================ FILE: Explanations/Explanations 16/Valera and Tubes Explanation.txt ================================================ Here was my idea - Each tube has exactly 2 cells and the last tube has all the remaining cells. Crawl around the cell like a snake. If you're at a corner, change the row. Don't visit a visited square twice. -------------------------------------------- const int MAX_ROWS = 301, MAX_COLUMNS = 301; int visited[MAX_ROWS][MAX_COLUMNS] = {{false}}; void get_next(int &x, int &y, int columns) { if( (y == 1 && visited[x][y + 1]) || (y == columns && visited[x][y - 1]) ) x++; else if(y < columns && !visited[x][y + 1]) y++; else y--; } int main() { int rows, columns, no_of_tubes; scanf("%d %d %d", &rows, &columns, &no_of_tubes); vector > >tubes(no_of_tubes + 1); int x = 1, y = 1, i = 1; while(x <= rows) { tubes[i].push_back(make_pair(x, y)); if(i != no_of_tubes && tubes[i].size() == 2) i++; visited[x][y] = true; get_next(x, y, columns); } for(int i = 1; i <= no_of_tubes; i++) { printf("%d ", tubes[i].size()); for(int j = 0; j < tubes[i].size(); j++) printf("%d %d ", tubes[i][j].first, tubes[i][j].second); printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 16/Xenia and Bit Operations.txt ================================================ Xenia the beginner programmer has a sequence a, consisting of 2n non-negative integers: a1, a2, ..., a2n. Xenia is currently studying bit operations. To better understand how they work, Xenia decided to calculate some value v for a. Namely, it takes several iterations to calculate value v. At the first iteration, Xenia writes a new sequence a1 or a2, a3 or a4, ..., a2n - 1 or a2n, consisting of 2n - 1 elements. In other words, she writes down the bit-wise OR of adjacent elements of sequence a. At the second iteration, Xenia writes the bitwise exclusive OR of adjacent elements of the sequence obtained after the first iteration. At the third iteration Xenia writes the bitwise OR of the adjacent elements of the sequence obtained after the second iteration. And so on; the operations of bitwise exclusive OR and bitwise OR alternate. In the end, she obtains a sequence consisting of one element, and that element is v. Let's consider an example. Suppose that sequence a = (1, 2, 3, 4). Then let's write down all the transformations (1, 2, 3, 4)  →  (1 or 2 = 3, 3 or 4 = 7)  →  (3 xor 7 = 4). The result is v = 4. You are given Xenia's initial sequence. But to calculate value v for a given sequence would be too easy, so you are given additional m queries. Each query is a pair of integers p, b. Query p, b means that you need to perform the assignment ap = b. After each query, you need to print the new value v for the new sequence a. ----------------------------------------------- Build a segment trees. The leaves are the elements themselves. Each level we do either OR or XOR on the children nodes. If there are an even number of levels, the first operation is XOR ... Else it is OR. To do an update, we must trace a path from the root to the leaf. This is O(n), where n is the number of levels. Or O(log n), if n is the number of elements. -------------------------------------------- int tree[3*MAX_SIZE]; int element[MAX_SIZE]; int perform(int a, int operation, int b) { switch(operation) { case OR : return (a|b); case XOR : return (a^b); } } int other(int operation) { return (operation^1); } void build(int node, int start, int end, int operation) { if(start == end) { tree[node] = element[start]; return; } int mid = (start + end)/2; build(2*node, start, mid, other(operation)); build(2*node + 1, mid + 1, end, other(operation)); tree[node] = perform(tree[2*node], operation, tree[2*node + 1]); } void update(int node, int start, int end, int index, int value, int operation) { if(start == end) { tree[node] = element[index] = value; return; } int mid = (start + end)/2; if(index >= start && index <= mid) { update(2*node, start, mid, index, value, other(operation)); } else if(index > mid && index <= end) { update(2*node + 1, mid + 1, end, index, value, other(operation)); } tree[node] = perform(tree[2*node], operation, tree[2*node + 1]); } int main() { int n, no_of_queries; scanf("%d %d", &n, &no_of_queries); int no_of_elements = (1 << n); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); int first_operation = (n%2 == 0 ? XOR : OR); build(1, 1, no_of_elements, first_operation); while(no_of_queries--) { int index, value; scanf("%d %d", &index, &value); update(1, 1, no_of_elements, index, value, first_operation); printf("%d\n", tree[1]); } return 0; } ================================================ FILE: Explanations/Explanations 16/Xenia and Ringroad Explanation.txt ================================================ Simple implementation int get_travel_time(int previous, int current, int no_of_houses) { return (previous <= current ? current - previous : no_of_houses - previous + current); } int main() { int no_of_houses, no_of_tasks; scanf("%d %d", &no_of_houses, &no_of_tasks); int previous_house = 1; long long total_time = 0; while(no_of_tasks--) { int current_house; scanf("%d", ¤t_house); total_time += get_travel_time(previous_house, current_house, no_of_houses); previous_house = current_house; } printf("%I64d\n", total_time); return 0; } ================================================ FILE: Explanations/Explanations 16/k-String Explanation.txt ================================================ The frequency of every letter must be a multiple of k. Put frequency[i]/k copies of every alphabet onto the answer string. int main() { int k; string input; cin >> k >> input; const int NO_OF_ALPHABETS = 26; int frequency[NO_OF_ALPHABETS] = {0}; for(int i = 0; i < input.length(); i++) frequency[input[i] - 'a']++; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(frequency[i]%k != 0) { cout << "-1"; return 0; } string smaller_string; for(int i = 0; i < NO_OF_ALPHABETS; i++) { for(int j = 0; j < frequency[i]/k; j++) smaller_string += ('a' + i); } for(int i = 1; i <= k; i++) cout << smaller_string; return 0; } ================================================ FILE: Explanations/Explanations 17/Adding Digits Explanation.txt ================================================ Check if any single digit from 0 to 9 can be appended at the end of a, to make a = 0 (mod b) If you get such a digit, pad it with 0s afterwards. ----------------------------------------------------- int main() { int a, b, no_of_operations; scanf("%d %d %d", &a, &b, &no_of_operations); int appended_digit = -1; for(int digit = 0; digit <= 9; digit++) { if((a*10 + digit)%b == 0) { appended_digit = digit; break; } } if(appended_digit == -1) { printf("-1\n"); } else { printf("%d%d", a, appended_digit); for(int i = 2; i <= no_of_operations; i++) printf("0"); } return 0; } ================================================ FILE: Explanations/Explanations 17/Christmas Spruce Explanation.txt ================================================ Keep track of the number of children of each vertex. no of children[parent[i]]++ Then go through all the vertices again. If it has 0 children, then increase the number of leaf children of it's parent. no of leaf children[parent[i]]++ Now, check if there's any non-leaf vertex that has fewer than 3 leaf children. --------------------------------------------------------- int main() { int no_of_vertices; scanf("%d", &no_of_vertices); int no_of_children[no_of_vertices + 1] = {0}; int parent[no_of_vertices + 1]; for(int i = 2; i <= no_of_vertices; i++) { scanf("%d", &parent[i]); no_of_children[parent[i]]++; } int no_of_leaf_children[no_of_vertices + 1] = {0}; for(int i = 1; i <= no_of_vertices; i++) { if(no_of_children[i] == 0) { no_of_leaf_children[parent[i]]++; } } int is_spruce = true; for(int i = 1; i<= no_of_vertices; i++) { if(no_of_children[i] > 0 && no_of_leaf_children[i] < 3) { is_spruce = false; break; } } printf(is_spruce ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Explanations/Explanations 17/Dreamoon and Wi-Fi Explanation.txt ================================================ Calculate the final destination you're supposed to be at. Calculate the steps you will take for sure (The one's that aren't question mark.) Let the actual destination be D, let the current position be x. Remaining steps = D - x Now let's say there are Q question marks. FOr all i, from 1 to Q, Check if i(+) + (Q - i)(-) takes you to the destination. Let's say r plus signs and Q-r minus signs take you to the destination. Now, the question is how many strings of length Q have exactly r plus signs. This = Choose(Q, r) Total number of strings = 2^Q Probability = Choose(Q, r)/2^Q -------------------------------------------------------------------- int choose(int n, int r) { if(r > n) return 0; int answer = 1; for(int i = 0; i < r; i++) answer = (answer*(n - i))/(i + 1); return answer; } int main() { const int MAX_LENGTH = 11; char sent_commands[MAX_LENGTH], received_commands[MAX_LENGTH]; scanf("%s %s", sent_commands, received_commands); int destination = 0; for(int i = 0; sent_commands[i] != '\0'; i++) destination += (sent_commands[i] == '+' ? 1 : -1); int reached = 0, unrecognised_symbols = 0; for(int i = 0; received_commands[i] != '\0'; i++) { if(received_commands[i] == '?') unrecognised_symbols++; else reached += (received_commands[i] == '+' ? 1 : -1); } int remaining = destination - reached; int no_of_plus = 0, no_of_minus = unrecognised_symbols; while(no_of_plus - no_of_minus != remaining) { no_of_plus++; no_of_minus--; } int no_of_ways = choose(unrecognised_symbols, no_of_plus); int total_ways = (1 << unrecognised_symbols); double probability = (no_of_ways*1.0f)/(total_ways*1.0f); printf("%.9lf", probability); return 0; } ================================================ FILE: Explanations/Explanations 17/Exams Explanation.txt ================================================ Be greedy. Score 2 marks on all the exams. And then there will be k - 2n marks left to score. If (k - 2n) >= n, then every exam gets more than 2 marks. Else, give 1 mark to (k - 2n) exams and n - (k - 2n) will remain with only 2 marks. ---------------------------------------------------- int main() { int no_of_exams, minimum_marks; scanf("%d %d", &no_of_exams, &minimum_marks); int marks_scored = 2*no_of_exams; int remaining_marks = minimum_marks - marks_scored; int exams_with_2_marks = (remaining_marks >= no_of_exams ? 0 : no_of_exams - remaining_marks); printf("%d\n", exams_with_2_marks); return 0; } ================================================ FILE: Explanations/Explanations 17/Garden Explanation.txt ================================================ int main() { int n, length; scanf("%d %d", &n, &length); int ans = 1e9; for(int i = 1; i <= n; i++) { int a_i; scanf("%d", &a_i); if(length%a_i == 0) ans = min(ans, length/a_i); } printf("%d\n", ans); return 0; } ================================================ FILE: Explanations/Explanations 17/Jamie and Alarm Snooze Explanation.txt ================================================ Decrement by x till you get a lucky number. While decrementing, check if minutes has < 0. If it is, then add 60 to the number of minutes, because 60 = 0 in a clock. SO 0 - x, = 60 - x If hour < 0, then add 24, because 24 = 0 ... So 0 - x hours = 24 - x hours ------------------------------------------------- int is_lucky(int n) { while(n) { if(n%10 == 7) return true; n = n/10; } return false; } int main() { int decrement_time, hour, minute; scanf("%d %d %d", &decrement_time, &hour, &minute); int no_of_hits = 0; while(!is_lucky(hour) && !is_lucky(minute)) { const int NO_OF_MINUTES_IN_HOUR = 60, NO_OF_HOURS_IN_DAY = 24; minute -= decrement_time; if(minute < 0) { minute += NO_OF_MINUTES_IN_HOUR; hour--; } if(hour < 0) { hour += NO_OF_HOURS_IN_DAY; } no_of_hits++; } printf("%d\n", no_of_hits); return 0; } ================================================ FILE: Explanations/Explanations 17/Jamie and Interesting Graph Explanation.txt ================================================ Here was my idea ... The number of edges has to be at least n-1 to ensure it's connected so do this first . 1 -> 2 -> 3 -> ... n-1 -> n Make these n-1 edges first. Make each edge = 1, from (1, 2) to (n - 2, n - 1). The sum of all edges till here = n - 2. The final (n - 1, n) edge has the minimum integer w, such that w + (n - 2) is prime. I want to ensure that is the MST too. So, till here I have ensured the graph is connected, path from 1 to n is prime, MST weight is prime. Now, all I have to do is add the remaining edges ensuring there's no multi edges and no shorter path or no lighter MST. for(u = 1 to n - 2) for(v = u + 2 to n) add(u, v, MST) till the number of edges is the required number. After constructing the MST, every pair of vertices has a weight = MST to ensure there's no shorter path. v starts from u + 2, because the path from (u, u + 1) has already been constructed while making the MST. --------------------------------------------------- int is_prime(int n) { if(n <= 1) return false; for(int i = 2; i*i <= n; i++) if(n%i == 0) return false; return true; } int find_nearest_prime(int n) { int ans = n + 1; while(!is_prime(ans)) ans++; return ans; } int main() { int n, no_of_edges; scanf("%d %d", &n, &no_of_edges); int cost_to_n = find_nearest_prime(n - 2) - (n - 2); int mst_cost = cost_to_n + (n - 2); int min_path = mst_cost; printf("%d %d\n", mst_cost, min_path); for(int i = 1; i < n - 1; i++) printf("%d %d %d\n", i, i + 1, 1); printf("%d %d %d\n", n - 1, n, cost_to_n); int edges = n - 1; for(int u = 1; u <= n - 1 && edges < no_of_edges; u++) { for(int v = u + 2; v <= n && edges < no_of_edges; v++) { printf("%d %d %d\n", u, v, mst_cost); edges++; } } return 0; } ================================================ FILE: Explanations/Explanations 17/Kolya and Tanya Explanation.txt ================================================ There are 20 good arrangements, 7 bad arrangements. Now, there are n triplets. A triplet may be either good or bad.... We are interested in configurations where at least one triplet is good. C(n, 1) 20^1 7^(n - 1) + C(n, 2) 20^2 7^(n - 2) + ... + C(n, n) 20^n This = (20 + 7)^n - C(n, 0) 7^n = 27^n - 7^n 7^n is when all triplets have a bad arrangement Since the whole thing happens via mod Ans = 27^n + MOD - 7^n ---------------------------------------------------------- long long power_mod(long long x, int power, int MOD) { long long result = 1; while(power) { if(power%2 == 1) result = (result*x)%MOD; x = (x*x)%MOD; power = power >> 1; } return result; } int main() { int n; scanf("%d", &n); const int MOD = 1e9 + 7; long long no_of_ways = power_mod(27, n, MOD) + (MOD - power_mod(7, n, MOD)); no_of_ways %= MOD; printf("%I64d\n", no_of_ways); return 0; } ================================================ FILE: Explanations/Explanations 17/Mashmokh and ACM Explanation.txt ================================================ Let f(x, k) be the number of good sequences of length k where the first number is x. Now if the first element is x, then the second element can be {x, 2x, 3x, .... (n/x) x } f(x, k) = f(x, k - 1) + f(2x, k - 1) + f(3x, k - 1) + f(4x, k - 1) + .... f((n/x).x, k - 1) And f(x, 1) = 1, for all x, However, I didn't know how to do it iteratively so I did it recursively. Important to note that for(int i = 1; x*i <= n; i++) //This loop runs in O(log n) time f(x, k) += f(x*i, k - 1) So over all complexity is O(nk log n) Important to note that if you fix an element x, and want to find the PREVIOUS element and go through all divisors of x, it would be O(nk sqrt(n)), which isn't enough to pass the time limit. O(log n) is better than O(sqrt n) Answer = f(1, k) + f(2, k) + ... + f(n, k) [The first number can be anything from 1 to n] -------------------------------------------------------------- Recursive implementation - const int N = 2001, MOD = 1e9 + 7; int no_of_sequences[N][N], max_number; long long get(int first_number, int length) { if(length == 1) no_of_sequences[first_number][1] = 1; if(no_of_sequences[first_number][length] != -1) return no_of_sequences[first_number][length]; no_of_sequences[first_number][length] = 0; for(int i = 1; first_number*i <= max_number; i++) { no_of_sequences[first_number][length] += get(first_number*i, length - 1); no_of_sequences[first_number][length] %= MOD; } return no_of_sequences[first_number][length]; } int main() { memset(no_of_sequences, -1, sizeof(no_of_sequences)); int length; scanf("%d %d", &max_number, &length); long long answer = 0; for(int first_number = 1; first_number <= max_number; first_number++) answer = (answer + get(first_number, length) )%MOD; printf("%I64d\n", answer); return 0; } ------------------------------------------------ Iterative implementation - int main() { const int MOD = 1e9 + 7; int max_number, length; scanf("%d %d", &max_number, &length); for(int first_number = 1; first_number <= max_number; first_number++) no_of_sequences[first_number][1] = 1; for(int l = 2; l <= length; l++) { for(int first_number = 1; first_number <= max_number; first_number++) { no_of_sequences[first_number][l] = 0; for(int i = 1; first_number*i <= max_number; i++) { no_of_sequences[first_number][l] += no_of_sequences[first_number*i][l - 1]; } no_of_sequences[first_number][l] %= MOD; } } long long answer = 0; for(int first_number = 1; first_number <= max_number; first_number++) answer += no_of_sequences[first_number][length]; answer %= MOD; printf("%I64d\n", answer); return 0; } ---------------------------------------------------- ================================================ FILE: Explanations/Explanations 17/Maxmium Splitting Explanation.txt ================================================ The smallest composite number is 4. If a number is a multiple of 4, then we can write it as a series of 4. We can't do better since if we used another composite number, we'd have to reduce the number of summands What if n = 1 (mod 4) What is the smallest number = 1 (mod 4) that is composite ? 9 1 and 5 cannot be written as sum of composites. n = 1 (mod 4) So, we write it as 9 + (n - 9), (n - 9) can be written as a series of 4s. n = 2 (mod 4) Similarly, 6 + (n - 6) n = 3 (mod 4) And 15 + (n - 15) = (9 + 6) + (n - 15) Now, this completes our proof that every composite number can be written as n = 4a + 6b + 9c. Fact 1 - Every composite integer can be written as n = 4a + 6b + 9c Now, we want to maximise the number of summands. Let's say for sum n, we use a composite number m, other than 4, 6 and 9. Using the same process for m, we can replace m with 4s, 6s and 9s and do better. Fact 2 - This proves that the maximum summands of n will have ONLY 4s, 6s and 9s. Fact 3 - When n has the maximum number of summands, there will be at most one 6 and one 9. 6 + 6 = 4 + 4 + 4 9 + 9 = 6 + 6 + 6 = 4 + 4 + 4 + 6 It is never optimal to use more than one 6 or one 9 in the summation. ------------------------------------------------------ int main() { int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int n; scanf("%d", &n); int no_of_parts = -1; if( !(n <= 3 || n == 5 || n == 7 || n == 11) ) { switch(n%4) { case 0: no_of_parts = n/4; break; case 1: no_of_parts = (n - 9)/4 + 1; break; case 2: no_of_parts = (n - 6)/4 + 1; break; case 3: no_of_parts = (n - 15)/4 + 2; break; } } printf("%d\n", no_of_parts); } return 0; } ================================================ FILE: Explanations/Explanations 17/Minimum Sum Explanation.txt ================================================ This problem can be solved by looking at the sum in a different way. Find the contribution of each of the 10 digits. For example, 345 = 3 x 100 + 4 x 10 + 5 We know the contribution of each of the digits. Keep track of the contribution of each digit in all the numbers together. Also, keep track each digit whether it is a first digit or not. Now, the biggest coefficient gets assigned the smallest legal value it can take. And so on. ------------------------------------------------------------------------ struct code { int is_first_digit, coefficient; code(){ is_first_digit = false, coefficient = 0; } }; int compare(const code &A, const code &B) { return (A.coefficient < B.coefficient); } int main() { const int NO_OF_DIGITS = 10; vector letter(NO_OF_DIGITS); int no_of_numbers; scanf("%d", &no_of_numbers); while(no_of_numbers--) { string number; cin >> number; letter[number[0] - 'a'].is_first_digit = true; int power_of_10 = 1; for(int i = number.size() - 1; i >= 0; i--) { letter[number[i] - 'a'].coefficient += power_of_10; power_of_10 *= 10; } } sort(all(letter), compare); vector assigned(NO_OF_DIGITS, false); int sum = 0; for(int i = NO_OF_DIGITS - 1; i >= 0; i--) { int digit = (letter[i].is_first_digit ? 1 : 0); while(assigned[digit]) digit++; assigned[digit] = true; sum += letter[i].coefficient*digit; } printf("%d\n", sum); return 0; } ================================================ FILE: Explanations/Explanations 17/Modular Exponentiation Explanation.txt ================================================ If x < y, then x (mod y) = x itself. Now, in this problem m (mod 2^n) m and n can be upto 10^8, 2^n overflows integer data type at value 32. All we need to notice that if 2^n > 10^8, then the answer will always be m as m is never greater than 10^8. This happens quite quickly. (At n = 28 itself). ---------------------------------------------------- #include int main() { int n, m; scanf("%d %d", &n, &m); int answer = (n > 31 ? m : m%(1 << n)); printf("%d ", answer); return 0; } ================================================ FILE: Explanations/Explanations 17/New Year and Domino Explanation.txt ================================================ Blog Link - http://qr.ae/TUTjxl Very neat problem ... Let f(i, j) be the number of dominos that can be placed from (1, 1) to (i, j) The main insight is that the horizontal and vertical dominos should be handled seperately. Using the principle of inclusion and exclusion, v(i, j) = v(i - 1, j) + v(i, j - 1) - v(i - 1, j - 1) h(i, j) = h(i - 1, j) + h(i, j - 1) - h(i - 1, j - 1) Now, to answer a query H = H(r2, c2) - H(r2, c1) - H(r1 - 1, c2) + H(r1 - 1, c1) V = V(r2, c2) - V(r2, c1 - 1) - V(r1, c2) + V(r1, c1 - 1) Ans = H + V ------------------------------------------------------------ int main() { int rows, columns; scanf("%d %d", &rows, &columns); char cell[rows + 1][columns + 2]; for(int i = 1; i <= rows; i++) scanf("%s", cell[i] + 1); int horizontal_dominos[rows + 1][columns + 2] = {{0}}; int vertical_dominos[rows + 1][columns + 2] = {{0}}; memset(vertical_dominos, 0, sizeof(vertical_dominos)); memset(horizontal_dominos, 0, sizeof(horizontal_dominos)); for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns + 1; j++) { horizontal_dominos[i][j] = (cell[i][j] == '.' && cell[i][j - 1] == '.'); horizontal_dominos[i][j] += horizontal_dominos[i - 1][j] + horizontal_dominos[i][j - 1] - horizontal_dominos[i - 1][j - 1]; vertical_dominos[i][j] = (cell[i][j] == '.' && cell[i - 1][j] == '.'); vertical_dominos[i][j] += vertical_dominos[i][j - 1] + vertical_dominos[i - 1][j] - vertical_dominos[i - 1][j - 1]; } } int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int row_1, column_1, row_2, column_2; scanf("%d %d %d %d", &row_1, &column_1, &row_2, &column_2); int total_horizontal = horizontal_dominos[row_2][column_2] - horizontal_dominos[row_2][column_1] - horizontal_dominos[row_1 - 1][column_2] +horizontal_dominos[row_1 - 1][column_1]; int total_vertical = vertical_dominos[row_2][column_2] - vertical_dominos[row_2][column_1 - 1] - vertical_dominos[row_1][column_2] + vertical_dominos[row_1][column_1 - 1]; int total_dominos = total_horizontal + total_vertical; printf("%d\n", total_dominos); } return 0; } ================================================ FILE: Explanations/Explanations 17/New Year's Eve Explanation.txt ================================================ There are only two cases that matter. k = 1, k > 1. Case 1 : If k = 1, then any number we choose in the set will be the XOR. We want to maximise the XOR, so we choose the maximum number we can. We choose n. Case 2: Now, notice that if we take XOR(a, b, c .... , n) The answer can never have more bits than the largest number in the set since XOR never creates new bits. So, any XOR we take will not have more bits than n, as n is the largest number we have. Let n = 10000111001... 0 The first bit is forced to be 1. Now, since the maximum number of bits is fixed, the maximum answer we can get is 111111 ... 1 (As many 1s as the number of bits in n) The question is can we always get this number ? Answer is yes. We need a number x, such that n^x = 1111 ... 1 For this, we only need a number x with a 1 in whichever position n has a 0, and a 0 in whichever position n has a 1. So, if n = 10000111001... 0, x = 01111000110.... 1 Now, notice that the first bit of n has to be 1. So, the first bit of x has to be 0. If the first bit of x is 0, then it means x < n. If x < n, then we can always choose x and n as the question allows us to choose any number less than n. k = 1, answer = n k > 1, answer = 1111...1 = 1 0...0000000 - 1 = 2^(no of bits in n) - 1 ================================================ FILE: Explanations/Explanations 17/Palindrome Pairs Explanation.txt ================================================ Keep track of the number of palindromes ending exactly at i, and all the palindromes that start from i onwards. Ans = sum(PE(i)*(PS(i + 1) + PS(i + 2) + ... + PS(n)) Where PE(i) is the number of palindromes ending exactly at i, PS(i) is the number of palindromes starting exactly at i Now, the suffix sums of PS can be precomputed so that it can be done in O(n) time. Find all palindromic substrings in O(n^2) time If A[i] = A[j], AND (i + 1 == j OR P[i + 1][j - 1] = true) Then P[i][j] = true Use this and compute all palindromes and keep track of PE and PS. ---------------------------------------------------- int main() { string A; cin >> A; int length = A.size(); int is_palindrome[length + 1][length + 1] = {{false}}; vector palindrome_starts(length + 1, 0); vector palindrome_ends(length + 1, 0); for(int i = 0; i < length; i++) { is_palindrome[i][i] = true; palindrome_starts[i] = palindrome_ends[i] = 1; } for(int substring_length = 2; substring_length < length; substring_length++) { for(int start = 0, end = start + substring_length - 1; end < length; start++, end++) { if(A[start] == A[end] && (substring_length == 2 || is_palindrome[start + 1][end - 1])) { is_palindrome[start][end] = true; palindrome_starts[start]++; palindrome_ends[end]++; } } } vector palindromes_from(length + 1, 0); for(int i = length - 1; i >= 0; i--) palindromes_from[i] = palindromes_from[i + 1] + palindrome_starts[i]; long long palindromic_pairs = 0; for(int i = 0; i < length; i++) palindromic_pairs += palindrome_ends[i]*1LL*palindromes_from[i + 1]; printf("%I64d\n", palindromic_pairs); return 0; } ================================================ FILE: Explanations/Explanations 17/Perfect Number Explanation.txt ================================================ I brute forced it. Number of operations comes to about 1e7, which passes in this case. I optimised it a little bit by only checking numbers = 1 (mod 9). ---------------------------------------- int sum_of_digits(int n) { int sum = 0; while(n) { sum += n%10; n /= 10; } return sum; } int main() { vector perfect_number; for(int i = 19; perfect_number.size() <= 1e4; i+=9) { if(sum_of_digits(i) == 10) perfect_number.push_back(i); } int k; scanf("%d", &k); printf("%d\n", perfect_number[k - 1]); return 0; } ================================================ FILE: Explanations/Explanations 17/QAQ Explanation.txt ================================================ Let P[i] denote the number of Q's till position i Let S[i] denote the number of Q's from position i For every A in the string the answer increases by P[i]*S[i] ---------------------------------------------- int main() { const int N = 101; char input[N]; scanf("%s", input); int length = strlen(input); int no_of_Q_till[length] = {0}; no_of_Q_till[0] = (input[0] == 'Q'); for(int i = 1; i < length; i++) no_of_Q_till[i] = no_of_Q_till[i - 1] + (input[i] == 'Q'); int no_of_Q_after[length] = {0}; no_of_Q_after[length - 1] = (input[length - 1] == 'Q'); for(int i = length - 2; i >= 0; i--) no_of_Q_after[i] = no_of_Q_after[i + 1] + (input[i] == 'Q'); int no_of_QAQ = 0; for(int i = 0; i < length; i++) if(input[i] == 'A') no_of_QAQ += no_of_Q_till[i]*no_of_Q_after[i]; printf("%d\n", no_of_QAQ); return 0; } ================================================ FILE: Explanations/Explanations 17/Seat Arrangements Explanation.txt ================================================ Let up(i, j) represent the consecutive dots up ending at (i, j) Let left(i, j) represent the consecutive dots left ending at(i, j) Let f(i, j) represent the number of ways to do this from (1, 1) to (i, j) f(i, j) = (up(i, j) >= k) + (left(i, j) >= k) + f(i - 1, j) + f(i, j - 1) - f(i - 1, j - 1) Using the principle of inclusion and exclusion. K = 1 is a special case, because it is overcounting. For k = 1, the answer is the number of dots in the grid. I got WA in the contest because I gave the array insufficient memory and didn't allocate memory for the null character. Actually, after the contest I realised that the rectangle DP is unnecessary. It is enough to count the number of points where the number of consecutive seats is >= k, in both the up and left direction. First, I learnt from the editorial that if strings are involved, as much as possible, try to deal with numbers instead to avoid the nasty mistake due to the null character. Then, I learnt that instead of handling k = 1 seperately, just divide by 2 in the end. Then, I learnt that it's better to not use a DP and just count the points. Three very important things (Use numbers instead of strings whenever possible, handle k = 1 elegantly and no need of rectangular DP) ------------------------------------------------------------------ #include #include int main() { int no_of_rows, no_of_columns, k; scanf("%d %d %d", &no_of_rows, &no_of_columns, &k); char seat[no_of_rows + 1][no_of_columns + 2]; for(int row = 1; row <= no_of_rows; row++) scanf("%s", seat[row] + 1); int up_empty_seats[no_of_rows + 1][no_of_columns + 1]; memset(up_empty_seats, 0, sizeof(up_empty_seats)); int left_empty_seats[no_of_rows + 1][no_of_columns + 1]; memset(left_empty_seats, 0, sizeof(left_empty_seats)); int total_seatings = 0; for(int row = 1; row <= no_of_rows; row++) { for(int column = 1; column <= no_of_columns; column++) { up_empty_seats[row][column] = (seat[row][column] == '.' ? 1 + up_empty_seats[row - 1][column] : 0); left_empty_seats[row][column] = (seat[row][column] == '.' ? 1 + left_empty_seats[row][column - 1] : 0); total_seatings += (up_empty_seats[row][column] >= k) + (left_empty_seats[row][column] >= k); } } if(k == 1) total_seatings = total_seatings >> 1; printf("%d\n", total_seatings); return 0; } ================================================ FILE: Explanations/Explanations 17/Supermarket Explanation.txt ================================================ It costs a/b to buy one. It costs am/b to buy m. Find the minimum. It is always optimal to buy all apples from the same market. Be careful for type casting. -------------------------------------- int main() { int n, m; scanf("%d %d", &n, &m); double ans = 1E9; while(n--) { int a, b; scanf("%d %d", &a, &b); ans = min(ans, (a*1.0*m)/(b*1.0)); } printf("%lf\n", ans); return 0; } ================================================ FILE: Explanations/Explanations 17/Swap Adjacent Elements Explanation.txt ================================================ Claim - It is possible to sort the permutation if and only if, for every i such that p(i) =/= i, there exists a series of consecutive 1s in between i and p(i) allowing the element p(i) to be swapped one-by-one and placed at position p(i) from position i. Proof - We can easily see that if i =/= p(i) and there is no stream of one's in between i and p(i), we can never get an array in order as there will always be some element p(i) that can never travel to position p(i). For example, Consider this 1 2 7 4 5 6 3 0 0 1 1 0 1 Since 7 is not in it's place and there is no continuous stream of 1s from 3 to 7, it is impossible for 7 to travel all the way to 3. ---------------------------------------------------- Now, to prove the other way around - i.e. it is always possible to sort an array if there exists a stream of 1s in between every i and p(i) where i =/= p(i) I will prove that if the condition of stream of 1s in between every i and p(i) is satisfied, then it is always possible to place the SMALLEST out of order element in it's right place. Choose the smallest element x, such that for all y < x, p(y) = y. In other words, pick the smallest element that is not in it's right position. {This means that the array is sorted from A[1, 2, .... x - 1]} Let x be located at position i. (P(x) = i). Now, we can conclude that x < i. Because all y < x, P(y) = y, so P(x) can't be < x. It has to be > x. Based on the condition, it means there is a string of consecutive 1s from x to (i - 1), allowing the travel. Since it is already established that there is a stream of 1s in between x and (i - 1). We perform the swaps one by one, till x moves all the way from position i to position x A[1, 2, ... x] The unsorted array is from A[x + 1, ... n]. Now, the smallest element that is out of order either lies in between x and i or it doesn't. Either way, the condition of it having a string of 1s in between it's current and true position remains invariant. Because if it lies outside [x, i), then it was never disturbed. If it did, then it still remains somewhere in the stream of 1s in between x and i. If it had a string of 1s in the beginning, it still does now, because it is still connected So, we keep placing the minimum element out-of-order in it's right place till the entire array is sorted. --------------------------------------------------------------- Here's what I did - Maintain a prefix sum of the number of 1s till i. For every i, such that p(i) != i Right = Max{p(i), i} Left = Min{p(i), i} Now, there should be continuous 1s from Left to (Right - 1). The expected number of 1s = (Right - 1) - (Left - 1) The number of 1s present = Prefix(Right - 1) - Prefix(Left - 1) If these two numbers are not equal, then it means there is some element which can't go it's true position. If these two numbers are equal for all i, such that i =/= p(i), then it means that the array can always be sorted by placing the minimum out-of-order element in it's right place. ------------------------------------------------------------------------------ int main() { int n; scanf("%d", &n); vector permutation(n + 1, 0); for(int i = 1; i <= n; i++) scanf("%d", &permutation[i]); vector ones_till(n + 1, 0); for(int i = 1; i <= n - 1; i++) { int digit; scanf("%1d", &digit); ones_till[i] = (digit == 1) + ones_till[i - 1]; } int is_sortable = true; for(int i = 1; i <= n; i++) { if(permutation[i] != i) { int right = max(i, permutation[i]); int left = min(i, permutation[i]); int distance = (right - 1) - (left - 1); if(ones_till[right - 1] - ones_till[left - 1] != distance) is_sortable = false; } } printf(is_sortable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 17/Tea Queue Explanation.txt ================================================ This problem is made a lot easier, because the inputs are sorted in terms of their l_i's Otherwise, we'd need to use structures and call a custom sort. Here's what we do, First initial time = left[1] For each person that arrives, set current time to max{current time, left[i]} [If current time < left[i], then the current customer will be served. He'll just have to wait till left[i]. So, directly set the current time to left[i]. If current time > left[i], let it be.] (check if current time <= right[i]) if it is, then service time[i] = current time, current time++ Note - I made the mistake of increasing service time regardless of whether the person was served. That was a mistake. Incrememnt time only if he has been served. For example, 1 4 1 1 The first person is served at moment 1. Now, the time is 2. The second person is not served. This means that he has left the queue. the time REMAINS 2 for the third customer It does NOT increase to 3 even if he didn't take the tea. Only the serviced customers increment the current time. --------------------------------------------------------------------- void solve() { int number_of_students; scanf("%d", &number_of_students); vector left(number_of_students + 1); vector right(number_of_students + 1); for(int i = 1; i <= number_of_students; i++) scanf("%d %d", &left[i], &right[i]); vector served_time(number_of_students + 1, 0); for(int current_time = left[1], student = 1; student <= number_of_students; student++) { current_time = max(current_time, left[student]); if(current_time <= right[student]) { served_time[student] = current_time++; } } for(int i = 1; i <= number_of_students; i++) printf("%d ", served_time[i]); printf("\n"); } ================================================ FILE: Explanations/Explanations 17/Testing Pants for Sadness Explanation.txt ================================================ Let's say we have crossed x levels, how many clicks to we make on level x+1 with k options ? We have already crossed x levels, so we make 1 click, which will be wrong in the worst case. Now, after that to reach level x + 1, we will need to make x clicks. So, for each of the remaining k - 1 options, we will need x clicks to get there and one more click for the option itself. So, number of clicks at level x + 1 = 1 + (x + 1)(k - 1) First option requires one click and all remaining options require x + 1 clicks. So, if we are now at level i, Clicks += 1 + i(k - 1) --------------------------------------------------------------------------------- int main() { int no_of_questions; scanf("%d", &no_of_questions); long long no_of_clicks = 0; for(int i = 1; i <= no_of_questions; i++) { int no_of_options; scanf("%d", &no_of_options); no_of_clicks += 1 + i*1LL*(no_of_options - 1); } printf("%I64d\n", no_of_clicks); return 0; } ================================================ FILE: Explanations/Explanations 17/The World is a Theatre Explanation.txt ================================================ Answer is sum( C(boys, i)* C(girls, actors - i) ), i = 4 to actors - 1 Precompute using Pascal's triangle. ------------------------------------------------- int main() { const int N = 60; long long combinations[N + 1][N + 1]; combinations[0][0] = 1; for(int n = 1; n <= N; n++) { for(int r = 0; r <= n; r++) { if(r == 0 || r == n) combinations[n][r] = 1; else combinations[n][r] = combinations[n - 1][r] + combinations[n - 1][r - 1]; } } int no_of_actors, boys, girls; scanf("%d %d %d", &boys, &girls, &no_of_actors); long long no_of_ways = 0; for(int i = 4; i < no_of_actors; i++) no_of_ways += combinations[boys][i]*combinations[girls][no_of_actors - i]; printf("%I64d\n", no_of_ways); return 0; } ================================================ FILE: Explanations/Explanations 17/Tricky Alchemy Explanation.txt ================================================ Count the number of required yellow crystals and required green crystals. If we have more than required, it's 0. ---------------------------------------------- int main() { int yellow, blue; scanf("%d %d", &yellow, &blue); int x, y, z; scanf("%d %d %d", &x, &y, &z); long long required_yellow = 2LL*x + y; long long required_blue = y + 3LL*z; long long required = max(0LL, required_yellow - yellow) + max(0LL, required_blue - blue); printf("%I64d\n", required); return 0; } ================================================ FILE: Explanations/Explanations 17/Water the Gardens Explanation.txt ================================================ Now, the time taken to water the patch of grass in between 1 and tap[1] is tap[1] - 1 = tap[1]. The time taken to water the patch of grass from the last tap to the end is = N - (tap.back() - 1); The time taken to water the patch of grass in between tap[i] and tap[i + 1] is ceil[distance/2], where distance = tap[i + 1] - (tap[i] - 1) This is because the number of unwatered patches of grass in between tap[i] and tap[i + 1] reduces by 2 each second. So, the distance shrinks by 2 each second. If this number is odd, add one more second. The time taken = max{First patch, all middle patches, Last patch} (It's already sorted) --------------------------------------------------------------------- void solve() { int number_of_taps, number_of_beds; scanf("%d %d", &number_of_beds, &number_of_taps); vector tap(number_of_taps + 1, 0); for(int i = 1; i <= number_of_taps; i++) scanf("%d", &tap[i]); int time = tap[1]; for(int i = 1; i < number_of_taps; i++) { int distance = tap[i + 1] - tap[i] + 1; int time_for_this_patch = distance/2 + distance%2 ; time = max(time, time_for_this_patch); } time = max(time, number_of_beds - tap.back() + 1); printf("%d\n", time); } ================================================ FILE: Explanations/Explanations 18/Art Union Explanation.txt ================================================ Let f(i, j) denote the time at which painting i is finished by painter j. Note that a painting can only start by a painter, provided, that painter j has finished painting i - 1, and painter j - 1 has finished painter j So, f(i, j) = max{ f(i - 1, j), f(i, j - 1) } + time[i][j] ------------------------------------------------------------------- int main() { int number_of_paintings, number_of_painters; scanf("%d %d", &number_of_paintings, &number_of_painters); int time[number_of_paintings + 1][number_of_painters + 1]; for(int i = 1; i <= number_of_paintings; i++) for(int j = 1; j <= number_of_painters; j++) scanf("%d", &time[i][j]); int time_for[number_of_paintings + 1][number_of_painters + 1]; memset(time_for, 0, sizeof(time_for)); for(int painter_i = 1; painter_i <= number_of_painters; painter_i++) { for(int painting = 1; painting <= number_of_paintings; painting++) { time_for[painting][painter_i] = max(time_for[painting - 1][painter_i], time_for[painting][painter_i - 1]) + time[painting][painter_i]; } } int all_painters = number_of_painters; for(int i = 1; i <= number_of_paintings; i++) printf("%d ", time_for[i][all_painters]); return 0; } ================================================ FILE: Explanations/Explanations 18/Bear and Colours Explanation.txt ================================================ Quite interesting question. I read it yesterday and the solution and was surprised to see O(n^2) pass. Let's say the question said find the number of intervals, starting from 1, where each colour is winning, How to do this ? keep frequency of each ball, whenevver you update frequency of a ball, check if it is now greater than the maximum frequency int winner = 0; for(int i = 1; i <= N; i++) frequency[colour[i]]++ if(frequency[colour[i]] > frequency[winner]) winner = colour[i] winning_intervals[winner]++ -> This line is important Now, just do this for every possible start, not just 1. The elegant trick here is to update winning interval every time and the realisation that you only need to compare the frequency of the updated colour with the winner. ------------------------------------------------------------------- int main() { int no_of_balls; scanf("%d", &no_of_balls); vector colour(no_of_balls + 1, 0); for(int i = 1; i <= no_of_balls; i++) scanf("%d", &colour[i]); vector no_of_winning_intervals(no_of_balls + 1); for(int start = 1; start <= no_of_balls; start++) { vector frequency(no_of_balls + 1, 0); int winner = 0; for(int i = start; i <= no_of_balls; i++) { frequency[colour[i]]++; if(frequency[colour[i]] > frequency[winner] || (frequency[colour[i]] == frequency[winner] && colour[i] < winner)) winner = colour[i]; no_of_winning_intervals[winner]++; } } for(int ball_i = 1; ball_i <= no_of_balls; ball_i++) printf("%d ", no_of_winning_intervals[ball_i]); return 0; } ================================================ FILE: Explanations/Explanations 18/Cave Painting Explanation.txt ================================================ Let us try to examine the properties of n, if it had a different remainder with every number from 1 to k. n = 0 (mod 1) This means n = 1 (mod 2) No other option. Similarly, n = 2 (mod 3) n = 3 (mod 4) And so on. At every stage, n = -1 (mod i) This means, (n + 1) = 0 (mod i) This means that (n + 1) must be divisible by every number from 1 to i. I made the mistake of thinking that it means (n + 1) should be i!, and then a multiple of i!, but that's incorrect. It's a common mistake. If you mark multiples of A and B, multiples of LCM(A, B) will be marked twice, not AB. LCM(A, B) = AB, when they are coprime. So, actually (n + 1) should be a multiple of all numbers from 1 to i, means it should be divisibly by LCM(1, ... , i) I checked how fast the sequence grows and when i = 43, it is > 10^18. So in the contest, I precomputed all LCM's from 1 to 42, and then if k < 43 and (n + 1)%lcm(43) == 0, Answer is yes ------------------------------------------------------------------------------ #include int main() { long long n, k; scanf("%I64d %I64d", &n, &k); long long lcm_1_till[45]; lcm_1_till[1] = 1; for(int i = 2; i < 43; i++) { int ii = i; long long extra = 1, lcm_i_minus_1 = lcm_1_till[i - 1]; for(int j = 2; j <= ii; j++) { while(ii%j == 0) { ii /= j; if(lcm_i_minus_1%j == 0) lcm_i_minus_1 /= j; else extra *= j; } } lcm_1_till[i] = lcm_1_till[i - 1]*extra; } printf( k < 43 && (n + 1)%lcm_1_till[k] == 0 ? "Yes\n" : "No\n"); return 0; } ------------------------------------------------------------------------------- After the contest, and reading the editorial, I made it cleaner by realising that no need of precomputing, k < 43, so you can check every number from 1 to 42, provided k < 43 int main() { long long n, k; scanf("%I64d %I64d", &n, &k); const int LIMIT = 43; int divisible_by_lcm = true; if(k < LIMIT) { for(int i = 1; i <= k; i++) { if( (n + 1)%i != 0) { divisible_by_lcm = false; break; } } } printf(k < LIMIT && divisible_by_lcm ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Explanations/Explanations 18/Cloning Toys Explanation.txt ================================================ Slightly tricky problem and the case of 0 originals needs to be handled seperately. So, if you want to have Y originals, then it means you have to create Y - 1 new originals. When you do this, you are forced to make Y - 1 new copies as well. There is no other way of generating originals. Then you may make new copies, each new copy gives you two new pieces. So, here are the conditions - 1. At least one new original 2. Copies >= Original 3. (Copies - originals) is even. I got this in the contest, however I missed out on the case where originals = 0 ? When you don't want any new originals, what do you do ? Is the answer always no ? Actually, this is what the above algorithm says, but it's wrong. If you make 0 originals, the answer is no, EXCEPT when you want 0 copies as well. For example, if you want 1 original and 0 copies, that means you don't have to do anything. I missed this trick during the contest. 0 originals is a special case. 1. Yes, if copies = 0 2. No, otherwise. ------------------------------------------------------------------------------------------------------- int main() { int originals, copies; scanf("%d %d", &copies, &originals); originals--; printf( (originals == 0 && copies == 0) || (originals >= 1 && copies >= originals && (copies - originals)%2 == 0) ? "Yes\n" : "No\n"); return 0; } ================================================ FILE: Explanations/Explanations 18/Eternal Victory Explanation.txt ================================================ Think of the path travelled in terms of the edges travelled. What if we had only one vertex and all of it's children were leafs ? Then cost = w1 + w2 + ... + wn .... Now, all except one of these leaves are visited twice. So, the best we can do is visit the maximum weight only once. Cost = 2(w1 + w2 + ... + wn) - wmax Now, we don't necessarily have all children as leaves. But, notice that from the root, we must visit every leaf. The cost to one leaf is f(L) f(L1) + f(L2) + ... + f(Ln) All except one leaf is visited twice. Let us visit the leaf with the maximum cost once. Total cost = 2*sum of edges - f(max) This is an elegant way of putting it. A very important corner case, which fortunately is elaborated in the example itself - What if there is only one leaf ? Then, no edge will be visited twice as we don't need to come back to any vertex and visit the other vertices and the answer is merely the sum of all edges. -------------------------------------------------------------------------------------------------------- void dfs(int v, int parent_v) { max_distance[v] = 0; for(int i = 0; i < tree[v].size(); i++) { int child_v = tree[v][i].first; int child_distance = tree[v][i].second; if(child_v == parent_v) continue; dfs(child_v, v); max_distance[v] = max(max_distance[v], child_distance + max_distance[child_v]); } } int main() { int no_of_cities; scanf("%d", &no_of_cities); long long sum_of_edges = 0; for(int i = 1; i < no_of_cities; i++) { int x, y, weight; scanf("%d %d %d", &x, &y, &weight); tree[x].push_back(make_pair(y, weight)); tree[y].push_back(make_pair(x, weight)); sum_of_edges += weight; } dfs(1, 0); long long total_travel_distance = (sum_of_edges == max_distance[1] ? sum_of_edges : 2*sum_of_edges - max_distance[1]); printf("%I64d\n", total_travel_distance); return 0; } ================================================ FILE: Explanations/Explanations 18/Hard Problem Explanation.txt ================================================ ----------------------------------------- Here's the main idea. Assume the first i elements of the list are already sorted. How can you place string (i + 1) at the end of this list ? There are two options - Either you place it reversed, or un-reversed. f(i, R) = Minimum cost for the first i strings with last string reversed. f(i, U) = Minimum cost for the first i strings with last string unreversed. if(s[i] >= s[i - 1]) f(i, U) = f(i - 1, U) if(s[i] >= R(s[i - 1]) f(i, U) = min{f(i, U), f(i - 1, R)} if(R(s[i]) >= s[i - 1]) f(i, R) = c[i] + f(i - 1, U) if(R(s[i]) >= R(s[i - 1])) f(i, R) = min{f(i, R), c[i] + f(i - 1, R)} Answer = min{f(N, R), f(N, U)} Check if answer >= oo, in which case it's not possible. ------------------------------------------------------------------------------ string rev(string s) { reverse(all(s)); return s; } int main() { int no_of_strings; scanf("%d", &no_of_strings); vector cost(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) scanf("%d", &cost[i]); vector s(no_of_strings + 1); for(int i = 1; i <= no_of_strings; i++) cin >> s[i]; const long long oo = 1e16; const int WITHOUT_REVERSING = 0, REVERSING = 1; long long minimum_till[no_of_strings + 1][2]; minimum_till[0][REVERSING] = minimum_till[0][WITHOUT_REVERSING] = 0; for(int i = 1; i <= no_of_strings; i++) { minimum_till[i][REVERSING] = minimum_till[i][WITHOUT_REVERSING] = oo; if(s[i] >= s[i - 1]) minimum_till[i][WITHOUT_REVERSING] = minimum_till[i - 1][WITHOUT_REVERSING]; if(s[i] >= rev(s[i - 1])) minimum_till[i][WITHOUT_REVERSING] = min(minimum_till[i][WITHOUT_REVERSING], minimum_till[i - 1][REVERSING]); if(rev(s[i]) >= s[i - 1]) minimum_till[i][REVERSING] = cost[i] + minimum_till[i - 1][WITHOUT_REVERSING]; if(rev(s[i]) >= rev(s[i - 1])) minimum_till[i][REVERSING] = min(minimum_till[i][REVERSING], cost[i] + minimum_till[i - 1][REVERSING]); } long long answer = min(minimum_till[no_of_strings][REVERSING], minimum_till[no_of_strings][WITHOUT_REVERSING]); printf("%I64d\n", answer >= oo ? -1 : answer); return 0; } ================================================ FILE: Explanations/Explanations 18/Joystick Explanation.txt ================================================ At each point charge the joystick with smaller charge. Stop when the smaller charge is <= 0 and the larger charge <= 1 For it to continue, one of them must be > 1 and the other >= 1 int main() { int charge_a, charge_b; scanf("%d %d", &charge_a, &charge_b); int no_of_minutes = 0; while(max(charge_a, charge_b) > 1 && min(charge_a, charge_b) > 0) { if(charge_a < charge_b) charge_a++, charge_b -= 2; else charge_a -= 2, charge_b++; no_of_minutes++; } printf("%d\n", no_of_minutes); return 0; } ================================================ FILE: Explanations/Explanations 18/K-Special Tables Explanation.txt ================================================ I was going to give up on this problem and then I told myself that if I can't solve it, I should at least come up with a bad heuristic or a brute force. And, then I got it ! Simple, I will fill the largest elements from the end till I reach A[k], A[k] < A[k + 1] < A[k + 2] < A[n] A[k] is the largest element possible, but there are enough elements left over. So, now theres two dimensions and a matrix. What to do now ? Same thing, fill in the largest elements from the end of the row till you reach the k-th column. Now, I want the next row k to be the maximum possible. For this, I want to save my large elements. So, I will fill columns 1 to k-1 from the beginning of the list. Next column, again I will start from the greatest unused element from N to K, and then smallest unused elements from 1 to K - 1. In short, use two pointers - one to the front, other to the back. Fill in each row greedily. Fill from the back pointer from A[N] to A[k] and with the front pointer from A[1] to A[k - 1]. I was delighted to find N = 500, the solution will pass, and it did ! -------------------------------- ----------------------------------------------------------------------------------------------------------------------------------- int main() { int N, k; scanf("%d %d", &N, &k); int special_table[N + 1][N + 1]; int front_ptr = 1, back_ptr = N*N; for(int row = 1; row <= N; row++) { for(int column = N; column >= k; column--) special_table[row][column] = back_ptr--; for(int column = 1; column < k; column++) special_table[row][column] = front_ptr++; } int k_column_sum = 0; for(int row = 1; row <= N; row++) k_column_sum += special_table[row][k]; printf("%d\n", k_column_sum); for(int row = 1; row <= N; row++) { for(int column = 1; column <= N; column++) { printf("%d ", special_table[row][column]); } printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 18/Lucky Sum Explanation.txt ================================================ Let us consider lucky numbers of at most 10 digits. Each digit can have either 4 or 7. So fill up each of the 10 digits in 2 ways. There are 2^10 = 1024 lucky numbers. Precompute all of them, and sort them. This won't take too much time. Then, find the sum of next_lucky(i) till i = R, and i = L - 1, and then subtract the two values. For convenience, let 0 also be a lucky number, If x and y are consecutive lucky numbers, then each term from x to y-1, contributes y to the sum. If y and z are consecutive lucky numbers, then each term from y to z - 1, contributes z to the sum. The trick is when we have reached limit. In that case, the range = limit - last lucky SO, in general range = min(limit, next lucky) - last lucky Each member of this range contributes (next lucky) to the sum. ----------------------------------------------------------------------------------------------------------- void compute(vector &lucky_numbers, long long last_lucky_number) { lucky_numbers.push_back(last_lucky_number); if(last_lucky_number > 1e10) return ; compute(lucky_numbers, last_lucky_number*10 + 4); compute(lucky_numbers, last_lucky_number*10 + 7); } long long get_answer(vector &lucky_numbers, int limit) { long long answer = 0; for(int i = 1; i < lucky_numbers.size() && lucky_numbers[i - 1] < limit; i++) { long long next_lucky_number = lucky_numbers[i]; long long range = min(limit, lucky_numbers[i]) - lucky_numbers[i - 1]; answer += next_lucky_number*range; } return answer; } int main() { vector lucky_numbers; compute(lucky_numbers, 0); sort(all(lucky_numbers)); int left, right; scanf("%d %d", &left, &right); long long answer = get_answer(lucky_numbers, right) - get_answer(lucky_numbers, left - 1); printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 18/Magic Forest Explanation.txt ================================================ A common technique in going over triples is in trying to go over doubles and then force the third variable. a^b^c = 0 a^a^b^c = a^0 b^0^b^c = b^a^0 c = b^a So, we fix (a, b) and find c, and then check if a non-degenerate triangle is possible. To avoid overcounting, make sure c >= b >= a ------------------------------------ int is_nondegenerate_triangle(int a, int b, int c) { return (a + b > c); } int main() { int n; scanf("%d", &n); int no_of_triangles = 0; for(int a = 1; a <= n; a++) { for(int b = a; b <= n; b++) { int c = a^b; if(c >= b && c <= n && is_nondegenerate_triangle(a, b, c)) no_of_triangles++; } } printf("%d\n", no_of_triangles); } ================================================ FILE: Explanations/Explanations 18/Marvolo Gaunt's Ring Alternate Solution Explanation.txt ================================================ Now, this is a different DP from the previous one. Fix q on a certain i, then p can take any value <= i and r can take any value >= i. What is the best possible match for both ? if p is maximum, then match it with the largest number in that range. Else with the smallest number in that range. --------------------------------------------------------------------------------- int main() { int no_of_elements; long long p, q, r; scanf("%d %I64d %I64d %I64d", &no_of_elements, &p, &q, &r); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector left_min(no_of_elements + 1); vector left_max(no_of_elements + 1); left_min[1] = left_max[1] = A[1]; for(int i = 2; i <= no_of_elements; i++) { left_min[i] = min(left_min[i - 1], A[i]); left_max[i] = max(left_max[i - 1], A[i]); } vector right_min(no_of_elements + 1); vector right_max(no_of_elements + 1); right_min[no_of_elements] = right_max[no_of_elements] = A[no_of_elements]; for(int i = no_of_elements - 1; i >= 1; i--) { right_max[i] = max(right_max[i + 1], A[i]); right_min[i] = min(right_min[i + 1], A[i]); } long long ans = p*A[1] + q*A[1] + r*A[1]; for(int i = 1; i <= no_of_elements; i++) { long long y = q*A[i]; long long x = (p > 0 ? p*left_max[i] : p*left_min[i]); long long z = (r > 0 ? r*right_max[i] : r*right_min[i]); ans = max(ans, x + y + z); } printf("%I64d\n", ans); return 0; } ================================================ FILE: Explanations/Explanations 18/Marvolo Gaunt's Ring Explanation.txt ================================================ Let f(i, P) represent the greatest value p*a[i] can take if you're allowed to choose till i f(i, Q) represent the greatest value of q*a[i]. f(i, Q) = max{f(i - 1, Q), q*a[i] + f(i, P)} f(i, R) represent the greatest value of r*a[i]. f(i, R) = max{f(i - 1, R), r*a[i] + f(i, q)} ------------------------------------------------------ int main() { int no_of_elements; long long p, q, r; scanf("%d %I64d %I64d %I64d", &no_of_elements, &p, &q, &r); vector a(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &a[i]); vector max_P(no_of_elements); max_P[0] = p*a[0]; for(int i = 1; i < no_of_elements; i++) max_P[i] = max(max_P[i - 1], p*a[i]); vector max_Q(no_of_elements); max_Q[0] = q*a[0] + p*a[0]; for(int i = 1; i < no_of_elements; i++) max_Q[i] = max(max_Q[i - 1], q*a[i] + max_P[i]); vector max_R(no_of_elements); max_R[0] = r*a[0] + q*a[0] + p*a[0]; for(int i = 1; i < no_of_elements; i++) max_R[i] = max(max_R[i - 1], r*a[i] + max_Q[i]); printf("%I64d\n", max_R[no_of_elements - 1]); return 0; } ================================================ FILE: Explanations/Explanations 18/Not Equal on a Segment Explanation.txt ================================================ Very powerful idea. For every i, let f(i) denote the first index on the left such that A[f(i)] =/= A[i], (un equal element) f(i) = (A[i - 1] =/= A[i] ? i - 1: f(i - 1)) Now, in a query, either x = r, or not If x =/= r, then r is the answer If x = r, then check if f(r) >= l, then f(r) is the answer. Otherwise, -1 is the answer. The above can be precomputed in one pass. --------------------------------------------------------------------------------------------------------------- int main() { int number_of_elements, number_of_queries; scanf("%d %d", &number_of_elements, &number_of_queries); vector A(number_of_elements + 1, 0); for(int i = 1; i <= number_of_elements; i++) scanf("%d", &A[i]); vector first_unequal_position_left(number_of_elements + 1, 0); for(int i = 1; i <= number_of_elements; i++) first_unequal_position_left[i] = (A[i] != A[i - 1] ? i - 1 : first_unequal_position_left[i - 1]); while(number_of_queries--) { int left, right, x; scanf("%d %d %d", &left, &right, &x); int answer; if(A[right] != x) answer = right; else if(A[right] == x) answer = (first_unequal_position_left[right] >= left ? first_unequal_position_left[right] : -1); printf("%d\n", answer); } return 0; } ================================================ FILE: Explanations/Explanations 18/Perfect Squares Explanation.txt ================================================ Keep a boolean vector of all squares. Sort the array given and then find the first element that is either negative or not a square. 0 is a square. Forgot to include this in the contest. int main() { int n; scanf("%d", &n); vector A(n); for(int i = 0; i < n; i++) scanf("%d", &A[i]); sort(all(A)); vector is_square(1e6 + 1, false); for(int i = 0; i*i <= 1e6; i++) is_square[i*i] = true; int answer; for(int i = n - 1; i >= 0; i--) { if(A[i] < 0 || !is_square[A[i]]) { answer = A[i]; break; } } printf("%d ", answer); return 0; } ================================================ FILE: Explanations/Explanations 18/Petya and Inequiations Explanation.txt ================================================ Try to find the maximum value of the sum of squares - Turns out this happens when all the elements except one = 1, and the last element = Y - (n - 1) Let us say there is another arrangement where we have at most (n - 2) ones. I will show that you can always do better by making it (n - 1) 1's Choose the largest and second largest element - Let it be a and b. Without loss of generality, a < b, and a > b > 1 Sum of squares = a^2 + b^2 = X Now, let us make the two numbers 1, (b + a - 1) Keeping the sum invariant. Let us examine the sum of squares now 1^2 + (b + a - 1)^2 = 1 + a^2 + b^2 + 1 - 2a - 2b + 2ab = (a^2 + b^2) + 2(1 + ab - a - b) = X + 2( 1 + ab - a - b) Now, all I have to do is show that (1 + ab - a - b) is positive When a and b are two positive integers > 1, their product is always greater than their sum. xy - x - y + 1 = x(y - 1) - y + 1 = (x - 1)(y - 1), both terms are positive, so (x - 1)(y - 1) > 0 This completes the proof --------- Now, get the maximum possible sum of squares for a given sum = 1^2 + 1^2 + ... + (Y - (N - 1))^2 Test cases I missed - What happens when N > Y. -------------------------------------------------------------------------------------------------------- int main() { int n, sum_limit; long long square_sum_lower_bound; scanf("%d %I64d %d", &n, &square_sum_lower_bound, &sum_limit); long long largest_element = sum_limit - (n - 1); long long max_square_sum = (n - 1) + largest_element*largest_element; if(max_square_sum < square_sum_lower_bound || n > sum_limit) { printf("-1\n"); return 0; } for(int i = 1; i <= n; i++) printf("%I64d\n", (i == n ? largest_element : 1)); return 0; } ================================================ FILE: Explanations/Explanations 18/Polo the Penguin and Matrix Explanation.txt ================================================ First, I thought of binary search where try to find the minimum number of moves all elements can be equalised. But, then that was not so easy. It's not easy to answer the question, - "Can the matrix be equalised in at most x moves ?" It's easier to answer the question - "Can the matrix be equalised to element x ?" Then, I thought of taking the frequency of all elements, and then the answer is yes, if (frequency[x - d] + frequency[x] + frequency[x + d]) = N*M But then I realised that the you can add D any number of times to a number, not just once. Then, I realised the remainder with D is invariant under the operation of adding or subtracting D x = x + D = x - D (mod D) If all the numbers are not congruent mod D, then we can never equalise them. Now, the question is that you have 10^4 elements ... Which element do they have the least distance. Turns out this is the median. If we equalise all elements to something other than the median, then there are more elements from one side than the other. We can do better by setting it to the median. (Let the other element by x, and let us say it takes s steps to go from x to the median.) Now, if x < m, then there are more elements to the right of x (R) than to the left (L) If we now set the equal point to the median, we add L(s) steps and reduce R(s) steps. So total new steps = s(L - R) L < R, so this is a negative number. Which means we have reduced the steps. ----------------------------------------------------------------------------------------- int main() { int no_of_rows, no_of_columns, difference; scanf("%d %d %d", &no_of_rows, &no_of_columns, &difference); vector A(no_of_rows*no_of_columns, 0); set remainder; int possible = true; for(int i = 0; i < no_of_rows*no_of_columns; i++) { scanf("%d", &A[i]); remainder.insert(A[i]%difference); } if(remainder.size() > 1) possible = false; sort(all(A)); int middle = A.size()/2; int median = A[middle]; int minimum_no_of_moves = 0; for(int i = 0; i < A.size(); i++) minimum_no_of_moves += abs(A[i] - median)/difference; printf("%d\n", possible ? minimum_no_of_moves : -1); return 0; } ================================================ FILE: Explanations/Explanations 18/Polo the Penguin and Strings Explanation.txt ================================================ What's the smallest answer of length 1 ? - a Length 2 ? has to be ab. Length 3 ? Answer should be either aba or abc, depending on whether you want 3 distinct characters. The answer can be constructed in the following way - First, fill it up with alternating a's and b's. ababababa....aba Then, from the back start putting the largest letters in the end in alphabetical order. For example, N = 7, K = 4 ababacd This is the smallest string, because if we put c or d in any other position where we have a or b, we get a larger string. In fact, if we swap any two characters of this string, we will either get a larger string or violate the condition S[i] =/= S[i - 1] Now, when is it not possible ? When N < K and when K = 1, and N > 1. I missed the second case. If N > 1, then we are forced to put the same character in multiple positions and will violate the condition. ----------------------------------------------------------------------------------------------------------------- int main() { int length, distinct_letters; scanf("%d %d", &length, &distinct_letters); if(length < distinct_letters || (length > 1 && distinct_letters == 1)) { printf("-1\n"); return 0; } string answer; for(int i = 0; i < length; i++) answer += ('a' + i%2); for(int i = length - 1, letter = distinct_letters - 1; letter >= 2; i--, letter--) answer[i] = ('a' + letter); cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 18/Replacement Explanation.txt ================================================ N = 1, is a special case. Let us solve it first. If N = 1, then if A[i] = 1, then Answer = 2 else, Answer = 1 ------------------------------------------------------- Now, let N > 1 The smallest digit that can occupy the first position = 1. Let us consider the sorted array. For all other positions k, There must be k-1 smaller numbers ... A[1], A[2], ... , A[k - 1]. If A[k] > A[k - 1], then we can replace A[k] with another copy of A[k - 1] No element smaller than A[k - 1] can occupy the position K. If A[k] = A[k - 1], then we replace any number from (k + 1 to N) or from (1, k - 2) to maintain the order. It doesn't matter which. Since nothing smaller than A[k - 1] can occupy A[k], we are done. However, there's a special case here - What if A[n] = 1 ? Then, we can't replace any other number, and A[n] =/= A[n - 1] as the array would remain unchanged. If the array consists of all 1's then the last 1, will become = 2 ---------------------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector element(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &element[i]); sort(all(element)); if(no_of_elements == 1) { printf("%d", element[0] == 1 ? 2 : 1); return 0; } printf("1 "); for(int i = 1; i < no_of_elements - 1; i++) printf("%d ", element[i - 1]); if(element[no_of_elements - 1] == 1) printf("2"); else printf("%d", element[no_of_elements - 2]); return 0; } ---------------------------------------------------------------------------- ================================================ FILE: Explanations/Explanations 18/Robot Vaccuum Cleaner Explanation.txt ================================================ This is a custom sorting question Let f(A) denote the number of sh subsquences in A. This question requires a similar approach to segment trees. How do we calculate f(A + B) if we know f(A) and f(B) ? What information do we need ? Any sh subsequence will either be completely in A, or completely in B or start in A and end in B. Then, f(A + B) = f(A) + f(B) + s[A]*h[B] We put A before B, if we get more sh sequences than if we put B before A. This is determined by s[A]*h[B] > S[B]*h[A]. If in the final order, the strings are concatenated in an order and there's a string A before B, where f(A + B) < f(B + A), swapping A and B can give us a higher number of subsequences. --------------------------------------------------------------------------------- struct info { long long no_of_s, no_of_h; string text; }; int compare(const info &A, const info &B) { long long no_of_new_sh_if_A_front = A.no_of_s*B.no_of_h; long long no_of_new_sh_if_B_front = B.no_of_s*A.no_of_h; if(no_of_new_sh_if_A_front > no_of_new_sh_if_B_front) return true; else return false; } int main() { int no_of_strings; cin >> no_of_strings; vector A(no_of_strings); for(int i = 0; i < no_of_strings; i++) { cin >> A[i].text; A[i].no_of_s = 0; A[i].no_of_h = 0; for(int j = 0; j < A[i].text.size(); j++) { A[i].no_of_s += (A[i].text[j] == 's'); A[i].no_of_h += (A[i].text[j] == 'h'); } } sort(all(A), compare); string final_text; for(int i = 0; i < no_of_strings; i++) final_text += A[i].text; long long no_of_s_till_here = 0, no_of_sh = 0; for(int i = 0; i < final_text.size(); i++) { no_of_s_till_here += (final_text[i] == 's'); if(final_text[i] == 'h') no_of_sh += no_of_s_till_here; } cout << no_of_sh; return 0; } ================================================ FILE: Explanations/Explanations 18/Rumour Explanation.txt ================================================ What I did was took each connected component of a graph and put it inside a vector. Then, I found the minimum of each connected component. Do DFS to mark all the connected components. ---------------------------------------------------------------------------------------------- void dfs_and_mark_component(int v, int component_no) { visited[v] = true; component[component_no].push_back(v); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) dfs_and_mark_component(child, component_no); } } int main() { int no_of_people, no_of_friendships; scanf("%d %d", &no_of_people, &no_of_friendships); vector gold(no_of_people + 1, 0); for(int i = 1; i <= no_of_people; i++) scanf("%d", &gold[i]); for(int i = 1; i <= no_of_friendships; i++) { int person_1, person_2; scanf("%d %d", &person_1, &person_2); graph[person_1].push_back(person_2); graph[person_2].push_back(person_1); } memset(visited, false, sizeof(visited)); int component_no = 1; for(int i = 1; i <= no_of_people; i++) { if(!visited[i]) { dfs_and_mark_component(i, component_no++); } } long long total_cost = 0; for(int component_i = 1; component_i < component_no; component_i++) { long long min_cost_for_this_component = 1e15; for(int v = 0; v < component[component_i].size(); v++) { int person = component[component_i][v]; min_cost_for_this_component = min(min_cost_for_this_component, gold[person]); } total_cost += min_cost_for_this_component; } printf("%I64d\n", total_cost); return 0; } ================================================ FILE: Explanations/Explanations 18/Search for Pretty Integers Explanation.txt ================================================ If there's a single digit that occurs in both lists, then the answer is the smallest such number. Else it is the smallest single digit number that occurs in A with the smallest single digit with B or the other way around. -------------------------------------------------------------------------------------------------------------------------------- int main() { int list_1_size, list_2_size; scanf("%d %d", &list_1_size, &list_2_size); vector in_A(10, false); for(int i = 1; i <= list_1_size; i++) { int a_i; scanf("%d", &a_i); in_A[a_i] = true; } vector in_B(10, false); for(int i = 1; i <= list_2_size; i++) { int b_i; scanf("%d", &b_i); in_B[b_i] = true; } int answer = -1; for(int i = 1; i <= 9; i++) { if(in_A[i] && in_B[i]) { answer = i; break; } } if(answer != -1) { printf("%d\n", answer); return 0; } for(int i = 1; i <= 9 && answer == -1; i++) { for(int j = i + 1; j <= 9; j++) { if( (in_A[i] && in_B[j]) || (in_A[j] && in_B[i]) ) { answer = 10*i + j; break; } } } printf("%d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 18/Tom Riddle's Diary Explanation.txt ================================================ Put all the names in a set. ------------------------------------------------- int main() { int no_of_people; scanf("%d", &no_of_people); set people; while(no_of_people--) { string current_possesser; cin >> current_possesser; printf(people.count(current_possesser) == 1 ? "YES\n" : "NO\n"); people.insert(current_possesser); } return 0; } ================================================ FILE: Explanations/Explanations 18/Two Substrings Explanation.txt ================================================ Store the positions where AB and BA occur. Try to compare the further AB and BA Check if the last AB and the first BA overlap And if the first BA and the last AB overlap. If they don't, we are done. If the first AB overlaps with the last BA - ABA And the first BA overlaps with the last AB, then that would mean the first BA comes after the last BA which is not possible. The only possibility is if it's like - ABAB There's only one BA. And it overlaps so it's not possible. ------------------------------------------------------------------ int main() { string A; cin >> A; vector ab; vector ba; for(int i = 0; i < A.size() - 1; i++) { if(A[i] == 'A' && A[i + 1] == 'B') ab.push_back(i); if(A[i] == 'B' && A[i + 1] == 'A') ba.push_back(i); } if(ab.size() == 0 || ba.size() == 0 || !(ab[0] + 1 < ba.back() || ba[0] + 1 < ab.back())) cout << "NO\n"; else cout << "YES\n"; return 0; } ================================================ FILE: Explanations/Explanations 18/Vladik and Fractions Explanation.txt ================================================ This one calls for some inspired factorisation. But, that need not be the case if you know the history of Egyptian fractions. The Egyptians had found a trick to write any unit fraction 1/a as an infinite chain of unit fractions by using this - 1/a = 1/(a + 1) + 1/a(a + 1) It's the reverse of telescoping a series, where an infinite series was bought down to one or two fractions. If you know the historical trick, the factorisation will not appear too difficult. 2/n = 1/n + 1/n = 1/n + ( 1/(n + 1) + 1/n(n + 1) When n = 1, it is not possible because 1/n is = 1 ------------------------------------------------------------------------------------------------- int main() { int n; scanf("%d", &n); int x = n; int y = n + 1; int z = n*(n + 1); printf(n == 1 ? "-1\n" : "%d %d %d\n", x, y, z); return 0; } ================================================ FILE: Explanations/Explanations 18/Woodcutter.txt ================================================ Since we have three options for every tree, store the answer for each of them, f(i, straight), f(i, right), f(i, left) f(i, straight) = max{f(i - 1, ...)} f(i, right) = 1 + f(i, straight) {if right is possible) f(i, left) = 1 + max{f(i - 1, straight), f(i - 1, left)} if possible then, f(i, left) = max{f(i, left), 1 + f(i - 1, right)} -------------------------------------------------------------------------- #include #define max(a, b) (a > b ? a : b) #define max_3(a, b, c) max(a, max(b, c)) int main() { int no_of_trees; scanf("%d", &no_of_trees); long long height[no_of_trees + 1]; long long x[no_of_trees + 1]; for(int i = 1; i <= no_of_trees; i++) scanf("%I64d %I64d", &x[i], &height[i]); const int RIGHT = 1, STRAIGHT = 0, LEFT = 2; int max_cut[no_of_trees + 1][3]; max_cut[0][RIGHT] = max_cut[0][STRAIGHT] = max_cut[0][LEFT] = 0; for(int i = 1; i <= no_of_trees; i++) { max_cut[i][STRAIGHT] = max_3(max_cut[i - 1][LEFT], max_cut[i - 1][STRAIGHT], max_cut[i - 1][RIGHT]); max_cut[i][LEFT] = max_cut[i][RIGHT] = max_cut[i][STRAIGHT]; if(i == 1 || x[i] - height[i] > x[i - 1]) max_cut[i][LEFT] = 1 + max(max_cut[i - 1][LEFT], max_cut[i - 1][STRAIGHT]); if(height[i - 1] + height[i] + x[i - 1] < x[i]) max_cut[i][LEFT] = max(max_cut[i][LEFT], 1 + max_cut[i - 1][RIGHT]); if(i == no_of_trees || height[i] + x[i] < x[i + 1]) max_cut[i][RIGHT] = 1 + max_cut[i][STRAIGHT]; } int answer = max_3(max_cut[no_of_trees][RIGHT], max_cut[no_of_trees][STRAIGHT], max_cut[no_of_trees][LEFT]); printf("%d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 19/A Compatipble Pair Explanation.txt ================================================ It's not as simple as multiplying the second largest number from A with the largest from B. There are negative numbers as well, and the case of most negative x most negative must also be considered. What I did was iterate through all products. Find the largest product = A[i], B[j] Now exclude this A[i], what is the maximum product now ? Two O(nm) scans. ----------------------------------------------------------------------------------------------------- int main() { int a_elements, b_elements; scanf("%d %d", &a_elements, &b_elements); vector A(a_elements); for(int i =0; i < a_elements; i++) scanf("%I64d", &A[i]); vector B(b_elements); for(int i = 0; i < b_elements; i++) scanf("%I64d", &B[i]); long long max_product = -1e18; int best_choice_A; for(int i = 0; i < a_elements; i++) { for(int j = 0; j < b_elements; j++) { if(A[i]*1LL*B[j] > max_product) { best_choice_A = i; max_product = A[i]*1LL*B[j]; } } } long long max_product_without_best_A = -1e18; for(int i = 0; i < a_elements; i++) { if(i == best_choice_A) continue; for(int j = 0; j < b_elements; j++) { max_product_without_best_A = max(max_product_without_best_A, A[i]*1LL*B[j]); } } printf("%I64d\n", max_product_without_best_A); return 0; } ================================================ FILE: Explanations/Explanations 19/A Prosperous Lot Explanation.txt ================================================ Some numbers have 0 loops, some have 1, some have 2. You are allowed only 18 digits. So you can reach at most 36 loops. While no of loops >= 2, print a digit with 2 loops, and then print a digit with 1 loop. In the contest, I made the mistake of choosing the 1 loop digit as 0. They want a positive integer, so k = 1, gives WA. It didn't strike me. --------------------------------------------------------------------------- int main() { int no_of_loops; scanf("%d", &no_of_loops); const int MAX_LOOPS = 36; if(no_of_loops > MAX_LOOPS) { printf("-1\n"); return 0; } while(no_of_loops >= 2) { printf("8"); no_of_loops -= 2; } if(no_of_loops == 1) printf("9\n"); return 0; } ================================================ FILE: Explanations/Explanations 19/Almost Identity Permutations Explanation.txt ================================================ The key to note here is that k is very small. First we must choose k spots out of n. Now, we can fill these k spots in derangement(k) number of ways. How to find a recurrence for d(n) ? Consider we have n numbers .... Now, let us place n at position i. (There are (n - 1) choices for this.) There are two possibilities for i - Either it is at position n, or it is at some other position. Now if i is placed at position n, then the remaining (n - 2) numbers must be deranged ... given by d(n - 2). What if i is placed at some position other than n ? Then notice now that we have a situation where every element has exactly one spot it cannot fill. (1 cannot be in 1, 2 cannot be in 2, 3 cannot be in 3, . . i - 1 cannot be in i - 1 i cannot be in N i + 1 cannot be in i + 1 . . N - 1 cannot be in N - 1) We have i-1 elements and i - 1 positions to fill them, and each element cannot occupy one spot. Total answer = (n - 1)(d(n - 1) + d(n - 2)) (n - 1) choices to place n, and then accordingly d(n - 1) or d(n - 2) For convenience, when 0 elements are out of place, I want to add 1 to the answer for this question so define d(0) = 1 ------------------------------------------------------------------ long long choose(int n, int r) { if(r == 0 || r == n) return 1; if(r == 1 || r == n - 1) return n; return choose(n - 1, r) + choose(n - 1, r - 1); } long long derangements(int n) { if(n == 0) return 1; if(n == 1) return 0; if(n == 2) return 1; return (n - 1)*(derangements(n - 1) + derangements(n - 2)); } int main() { int n, k; scanf("%d %d", &n, &k); long long answer = 0; for(int i = 0; i <= k; i++) { answer += choose(n, i)*derangements(i); } printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 19/Amr and Large Array Explanation.txt ================================================ Firstly, keep track of the left most, right most and frequency of each element. If the frequency of each element = max frequency, then the subarray required to have only that element as the largest frequency element = right[i] - left[i] + 1 Then, we're done. ---------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); const int LIMIT = 1e6; vector A(no_of_elements + 1, 0); vector frequency(LIMIT + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); frequency[A[i]]++; } int max_frequency = 0; for(int i = 1; i <= LIMIT; i++) max_frequency = max(max_frequency, frequency[i]); vector rightmost_occurence(LIMIT + 1, 0); for(int i = 1; i <= no_of_elements; i++) rightmost_occurence[A[i]] = i; vector leftmost_occurence(LIMIT + 1, 0); for(int i = no_of_elements; i >= 1; i--) leftmost_occurence[A[i]] = i; int minimum_segment_length = no_of_elements + 1; int answer; for(int i = 1; i <= LIMIT; i++) { if(frequency[i] == max_frequency) { int subsegment_length = rightmost_occurence[i] - (leftmost_occurence[i] - 1); if(subsegment_length < minimum_segment_length) { answer = i; minimum_segment_length = subsegment_length; } } } printf("%d %d\n", leftmost_occurence[answer], rightmost_occurence[answer]); return 0; } ================================================ FILE: Explanations/Explanations 19/Beautiful Sets of Points Explanation.txt ================================================ The distance between two points is an integer, if and only if at least one of their coordinates are equal. (I was going to go for (0, 0) (1, 1) ... (m, m), but (0, 0) is restricted.) So, you can go for the other diagonal ... (0, m - 0), (1, m - 1) ... etc. The distance in between any (x, y) and (y, x) = root(2) x something, so it's never an integer --------------------------------------------------------------------------------------- int main() { int m, n; scanf("%d %d", &m, &n); int limit = min(m, n) + 1; printf("%d\n", limit); for(int i = 0; i < limit; i++) printf("%d %d\n", i, limit - i - 1); return 0; } ================================================ FILE: Explanations/Explanations 19/Buggy Robot Explanation.txt ================================================ For the robot to finish at the starting position, the left and right ... and the up and down .. directions must neutralise each other. So, the max = 2*min{L, R} + 2*min{U, D} This allows for neutralisation in both horizontal and vertical directions. -------------------------------------------------------------- int main() { int no_of_instructions; string instructions; cin >> no_of_instructions >> instructions; int lefts = 0, rights = 0, ups = 0, downs = 0; for(int i = 0; i < no_of_instructions; i++) { lefts += (instructions[i] == 'L'); rights += (instructions[i] == 'R'); downs += (instructions[i] == 'D'); ups += (instructions[i] == 'U'); } int max_correct_instructions = 2*min(lefts, rights) + 2*min(ups, downs); cout << max_correct_instructions; return 0; } ================================================ FILE: Explanations/Explanations 19/Cellular Network Explanation.txt ================================================ Both the cities and the towers are given in ascending order. Take each city and perform binary search to find the nearest tower. Perform lower bound(city) and it gives the leftmost occurence of city, if city occurs and otherwise returns the first tower to it's left. (If city is not present in towers, then upper bound and lower bound both perform exactly the same - point to the first position where the element can be inserted without breaking the order. (Suppose you search for 4, and the list has (3, 5) ... Both will point to 5) So, we need to compare with wherever lower bound points and one position less than that. (Don't forget to do bound checking to see it doesn't exceed the limit. If lower bound points to after the last element, then don't compare with it. If lower bound points to 0, then don't compare with -1.) Nearest tower = min(left, right) The nearest distance = max(nearest tower). ----------------------------------------------------- int main() { int number_of_cities, number_of_towers; scanf("%d %d", &number_of_cities, &number_of_towers); vector city(number_of_cities); for(int i = 0; i < number_of_cities; i++) scanf("%d", &city[i]); vector tower(number_of_towers); for(int i = 0; i < number_of_towers; i++) scanf("%d", &tower[i]); int min_range = 0; for(int i = 0; i < number_of_cities; i++) { int position = lower_bound(all(tower), city[i]) - tower.begin(); int closest_tower = 2e9; if(position != number_of_towers) closest_tower = min(closest_tower, abs(tower[position] - city[i])); if(position != 0) closest_tower = min(closest_tower, abs(tower[position - 1] - city[i])); min_range = max(min_range, closest_tower); } printf("%d\n", min_range); return 0; } ================================================ FILE: Explanations/Explanations 19/Coder Explanation.txt ================================================ Be greedy while distributing the pieces. Fill them up in alternating positions. Notice that in any two consecutive rows, we will have exactly N pieces. . C . C . C . C . C In this way - If it was an odd number, then C . C . C . C . C . C . C . C So, number of pieces = (n/2)*n + ceil(n/2) (if n is odd) ----------------------------------------------------------------------- int main() { int no_of_rows; scanf("%d", &no_of_rows); int maximum_pieces = (no_of_rows)*(no_of_rows/2) + (no_of_rows%2)*(no_of_rows/2 + no_of_rows%2); printf("%d\n", maximum_pieces); for(int i = 1; i <= no_of_rows; i++) { if(i%2 == 1) { for(int j = 1; j <= no_of_rows; j++) printf("%c", j%2 == 0 ? '.' : 'C'); } else { for(int j = 1; j <= no_of_rows; j++) printf("%c", j%2 == 0 ? 'C' : '.'); } printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 19/Diversity Explanation.txt ================================================ The idea is to keep one character of each letter and then be able to change the others. The minimum changes = 0, if we already have more than k characters = k - distinct characters, otherwise Check if minimum changes > changeable characters ------------------------------------------------------------ int main() { char string[MAX_LENGTH]; int min_distinct_characters; scanf("%s %d", string, &min_distinct_characters); int frequency[NO_OF_ALPHABETS] = {0}; for(int i = 0; string[i] != '\0'; i++) { frequency[string[i] - 'a']++; } int no_of_distinct_characters = 0, no_of_changeable_characters = 0; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(frequency[i] > 0) { no_of_distinct_characters++; no_of_changeable_characters += (frequency[i] - 1); //Keep one character } } int minimum_changes = max(min_distinct_characters - no_of_distinct_characters, 0); //printf("NO of changes = %d\n", no_of_changeable_characters); printf(minimum_changes > no_of_changeable_characters ? "impossible\n" : "%d\n",minimum_changes); return 0; } ================================================ FILE: Explanations/Explanations 19/Hamster Farm Explanation.txt ================================================ If you take box_i, number of remaining hamsters = Hamsters%box_i ... No of boxes = Hamsters/box_i Minimise the remainder. ----------------------------------------------------------- int main() { long long no_of_hamsters; int no_of_boxes; scanf("%I64d %d", &no_of_hamsters, &no_of_boxes); long long leftover_hamsters = 1e18, boxes_bought; int box_type; for(int i = 1; i <= no_of_boxes; i++) { long long box_i; scanf("%I64d", &box_i); if(no_of_hamsters%box_i < leftover_hamsters) { leftover_hamsters = no_of_hamsters%box_i; boxes_bought = no_of_hamsters/box_i; box_type = i; } } printf("%d %I64d\n", box_type, boxes_bought); return 0; } ================================================ FILE: Explanations/Explanations 19/K-Dominant Character Explanation.txt ================================================ At first, I thought that if a string is K-dominant, it is also (K + 1)-dominant. If it is not K-dominant, it is not (K - 1)-dominant either. This suggests binary search, How to check if a string is x dominant ? Do 26 O(n) scans. For each alphabet, check if it occurs at least once in every substring of length x. Now, if there's at least one alphabet that satisfies this, the string is x-dominant. -------------------------------------------------------------- int is_possible(int k, int length) { for(int alphabet = 0; alphabet < NO_OF_LETTERS; alphabet++) { int alphabet_occurs_in_every_segment = true; for(int left = 1, right = k; right <= length; left++, right++) { int alphabet_frequency_here = frequency[alphabet][right] - frequency[alphabet][left - 1]; if(alphabet_frequency_here == 0) alphabet_occurs_in_every_segment = false; } if(alphabet_occurs_in_every_segment) return true; } return false; } --------------------------------------------------------------- Do binary search for this - int answer, start = 1, end = length; while(start <= end) { int mid = (start + end) >> 1; if(is_possible(mid, length)) { if(!is_possible(mid - 1, length)) { answer = mid; break; } else { end = mid - 1; } } else { start = mid; } } ------------------------------------------------------------------------------------ Problem is this might take about 20 x 26 O(n) scans. This is too much ! Here's how we reduce it. The idea of solving it seperately for each alphabet is correct, For a given alphabet i, how do we find the minimum length k, such that the string is k-dominant for character i. The minimum length is the maximum distance S, between any two consecutive occurences of i. If k > S, then by definition we will have an i on the segment S. If K < S, then there is at least one segment which does not have i. Now, we find the k for all alphabets, and the minimum k is our answer ! ------------------------------------------------------------------------------- int main() { string S; cin >> S; const int NO_OF_LETTERS = 26; int length = S.size(), answer = S.size(); for(int alphabet = 0; alphabet < NO_OF_LETTERS; alphabet++) { int last_occurence = -1, largest_gap_for_this_alphabet = 0; for(int i = 0; S[i] != '\0'; i++) { if(S[i] == 'a' + alphabet) { largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, i - last_occurence); last_occurence = i; } } largest_gap_for_this_alphabet = max(largest_gap_for_this_alphabet, length - last_occurence); answer = min(answer, largest_gap_for_this_alphabet); } cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 19/Little Artem and Grasshopper Explanation.txt ================================================ They are asking you to emulate the grasshopper and perform DFS. If you ever visit a previously visited square, you are stuck in a loop. ------------------------------------------------------------------------------- int main() { int no_of_strips; char strip[NO_OF_STRIPS]; scanf("%d %s", &no_of_strips, strip); int jump[no_of_strips + 1]; int visited[no_of_strips + 1] = {false}; for(int i = 0; i < no_of_strips; i++) scanf("%d", &jump[i]); int square = 0, stuck_forever; while(true) { if(visited[square] == true) { stuck_forever = true; break; } visited[square] = true; if(strip[square] == '<') { if(square - jump[square] < 0) { stuck_forever = false; break; } square -= jump[square]; } else { if(square + jump[square] >= no_of_strips) { stuck_forever = false; break; } square += jump[square]; } } printf(stuck_forever ? "INFINITE\n" : "FINITE\n"); return 0; } ================================================ FILE: Explanations/Explanations 19/Longest K Good Segment Explanation.txt ================================================ Use a sliding window (Two pointers). Notice that the window end increases by one each time So, if S[l, l + 1, l + 2, ... , r] is a good segment and S[l, l + 1, .... , r, r + 1] is not a good segment, Then it means A[r + 1] is the (K + 1)th distinct character. Push L forward while the number of distince characters is more than k. When we do it like this, notice each character is visited at most two times (Once by L, once by R) So, complexity = O(n) Notice we don't need to check S[l + 1, l + 2] S[l + 1, l + 2, l + 3], etc ... Because we know we have S[l, l + 1, .... , r] No need of checking smaller segments. ------------------------------------------------------------------- int main() { int no_of_elements, k; scanf("%d %d", &no_of_elements, &k); vector element(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &element[i]); const int MAX = 1e6 + 1; vector frequency(MAX, 0); int left = 1, right = 1, best_left, best_right, distinct_elements = 0, maximum_length = 0; while(right <= no_of_elements) { frequency[element[right]]++; distinct_elements += (frequency[element[right]] == 1); while(distinct_elements > k) { frequency[element[left]]--; distinct_elements -= (frequency[element[left]] == 0); left++; } int current_segment_length = right - (left - 1); if(current_segment_length > maximum_length) { maximum_length = current_segment_length; best_left = left; best_right = right; } right++; } printf("%d %d\n", best_left, best_right); return 0; } ================================================ FILE: Explanations/Explanations 19/Love Triangle Explanation.txt ================================================ This problem is made a lot simpler because nobody likes himself. So, if A-> B and B-> A, ... A does not like A .... So, this is not a traingle. A-> A never occurs either. Now, for every i, find p(i) and p(p(i)) ... If p(p(p(i))) = i, then we have a triangle ! Else we do not. ------------------------------------------------------------------ int main() { int no_of_planes; scanf("%d", &no_of_planes); vector liked_by(no_of_planes + 1); for(int i = 1; i <= no_of_planes; i++) scanf("%d", &liked_by[i]); int love_triangle_exists = false; for(int i = 1; i <= no_of_planes; i++) { int a = i; int b = liked_by[a]; int c = liked_by[b]; if(a == liked_by[c]) { love_triangle_exists = true; } } printf(love_triangle_exists ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 19/Nuts Explanation.txt ================================================ One of those brute force questions where it's quite confusing to emulate the process. While you have dividers left, make as many divisions as allowed in the box. See how many nuts you have stored till here and if you need more boxes. ------------------------------------------------------------------------- int main() { int k, total_nuts, dividers, capacity; scanf("%d %d %d %d", &k, &total_nuts, ÷rs, &capacity); int boxes_used = 0, nuts_stored_till_here = 0; while(nuts_stored_till_here < total_nuts) { boxes_used++; int dividers_used_in_this_box = min(dividers, k - 1); int nuts_in_this_box = (dividers_used_in_this_box + 1)*capacity; dividers -= dividers_used_in_this_box; nuts_stored_till_here += nuts_in_this_box; } printf("%d\n", boxes_used); return 0; } ================================================ FILE: Explanations/Explanations 19/Palindrome Transformation Explanation.txt ================================================ We need to notice a few things. Firstly, it's always possible to make the string a palindrome. Secondly, it's enough to make one half of the string equal to the other half. Thirdly, we have to make every element equal to it's reflection. That is, make A[i] = A[n - i - 1] Fourthly, the number of vertical moves to make A[i] and A[n - i - 1] equal = min{A[i] - A[n - i - 1], 26 - A[i] + A[n - i - 1]} So, we go over every pair of elements that is not equal and calculate the vertical moves required to make them equal. Fifthly, calculate the leftmost and rightmost position of the cursor in the first half that is not equal to it's reflection. And then horizontal moves is whichever is minimum - (Cursor -> Leftmost->Rightmost or Cursor->Rightmost->Leftmost) -------------------------------------------------------------------------------------------------------------------------- int main() { int n; string A; int cursor; cin >> n >> cursor >> A; cursor--; n--; cursor = min(cursor, n - cursor); int middle = n/2; int leftmost = cursor, rightmost = cursor; for(int i = cursor; i <= middle; i++) if(A[i] != A[n - i]) rightmost = i; for(int i = cursor; i >= 0; i--) if(A[i] != A[n - i]) leftmost = i; int vertical_moves = 0; for(int i = leftmost; i <= rightmost; i++) vertical_moves += min(abs(A[i] - A[n - i]), 26 - abs(A[i] - A[n - i])); int horizontal_moves = min((cursor - leftmost) + (rightmost - leftmost), (rightmost - cursor) + (rightmost - leftmost)); int total_moves = horizontal_moves + vertical_moves; cout << total_moves; return 0; } ================================================ FILE: Explanations/Explanations 19/Palindromic Supersequence Explanation.txt ================================================ The simplest way to do this is to concatenate A with it's reverse. It is always guaranteed to be a palindrome. Also, length is at most 2 x 10^3 <= 10^4 --------------------------------------------------------------------------- string reverse(string A) { string rev; for(int i = A.size() - 1; i >= 0; i--) rev += A[i]; return rev; } int main() { string A; cin >> A; string A_rev = reverse(A); string B = A_rev + A; cout << B; return 0; } ================================================ FILE: Explanations/Explanations 19/Recursive Queries Explanation.txt ================================================ Firstly, for all n >= 10, f(n) < n. Why is this important ? So, g(n) = g(f(n)) ... We can calculate this bottom-up. -------------------------------------------------- I didn't prove it during the contest. The editorial had a nice proof. Let N = n1 n2 n3 ... nk So, product is at most = n1 x n2 x ... x nk Now, N = nk + 10n(k - 1) + ... + 10^(k - 1)n1 Now, each nk is at most 9. Product of digits <= 9^(k -1)n1 < 10^(k - 1)n1 < N ------------------------------------------------------- The key to note is that in the query [L, R, k], k is small < 10. So, we precompute g(i, k) for all i <= 10^6 and all k < 10. This allows us to answer the query in O(1) time. Here is the main idea ... Since f(n) < n ... Whenever we are at i, we have all values of g(x), where x < i. We simply find g(f(i)) Now, while storing the answer ..., Here's what we do - Let answer(i, k) be the number of numbers in the range [1, i] for which g(i) = k. If we know this, how can we calculate g(i + 1, k) ? There are two possibilities - Either g(i + 1) = k, or g(i + 1) =/= k If g(i + 1) =/= k, then Answer(i + 1, k) = Answer(i, k) If g(i + 1) = k, then Answer(i + 1, k) = Answer(i, k) + 1 Do this for all k from 1 to 9. This idea of precomputing the answers using a 2D array, I had come across in some SPOJ question a long time back. ---------------------------------------------------------------- const int LIMIT = 1e6 + 5; int answer[LIMIT][10]; int non_zero_digit_product(int n) { int product = 1; while(n) { product *= (n%10 != 0 ? n%10 : 1); n /= 10; } return product; } void precompute() { vector g(LIMIT, 0); for(int i = 1; i < LIMIT; i++) g[i] = (i < 10 ? i : g[non_zero_digit_product(i)]); for(int i = 1; i < LIMIT; i++) answer[i][0] = 0; for(int i = 1; i < LIMIT; i++) { for(int digit = 1; digit < 10; digit++) { answer[i][digit] = answer[i - 1][digit]; } if(g[i] < 10) answer[i][g[i]]++; } } int main() { precompute(); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) { int left, right, k; scanf("%d %d %d", &left, &right, &k); printf("%d\n", answer[right][k] - answer[left - 1][k]); } return 0; } ================================================ FILE: Explanations/Explanations 19/Run For Your Prize Explanation.txt ================================================ A takes the first i items, and B takes the remaining items from (I + 1) to N Precompute the time taken by A for first i, and for B from (I + 1) to N Find the minimum value of A[i] + B[i + 1]. ------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector items(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &items[i]); const int A_POSITION = 1; vector time_A(no_of_elements + 2, 0); for(int i = 1; i <= no_of_elements; i++) time_A[i] = (items[i] - A_POSITION); const int B_POSITION = 1e6; vector time_B(no_of_elements + 2, 0); for(int i = 1; i <= no_of_elements; i++) time_B[i] = (B_POSITION - items[i]); int minimum_time = B_POSITION + A_POSITION; for(int i = 0; i <= no_of_elements; i++) { int time_if_A_picks_first_i = max(time_A[i], time_B[i + 1]); minimum_time = min(minimum_time, time_if_A_picks_first_i); } printf("%d\n", minimum_time); return 0; } ================================================ FILE: Explanations/Explanations 19/Simple Strings Explanation.txt ================================================ Here's what we do. Be greedy. If A[i] =/= A[i - 1], put A[i] into the answer, If A[i] == A[i - 1], then put in some character other than A[i - 1] and A[i + 1]. Otherwise, put in A[i]. ----------------------------------- char some_char_other_than(char a, char b) { for(char ch = 'a'; ch <= 'z' ; ch++) if(ch != a && ch != b) return ch; } int main() { string A; cin >> A; string answer; answer += A[0]; for(int i = 1; i < A.size(); i++) { char predecessor = answer[answer.size() - 1]; char successor = (i + 1 == A.size() ? predecessor : A[i + 1]); if(A[i] == predecessor) { answer += some_char_other_than(predecessor, successor); } else { answer += A[i]; } } cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 19/The Useless Toy Explanation.txt ================================================ Make a map, that maps all possible positions the toy can take to an integer number. Notice that the number of spins is periodic about 4. We only need to consider the number of spins mod 4. The answer is undefined if we can reach a position either both clockwise and anticlockwise, or never at all. ----------------------------------------------------------------- int main() { map positions; positions['v'] = 0; positions['<'] = 1; positions['^'] = 2; positions['>'] = 3; char start_position, end_position; int no_of_spins; scanf("%c %c %d", &start_position, &end_position, &no_of_spins); int first_position = positions[start_position]; int final_position = positions[end_position]; if( (first_position + no_of_spins%4)%4 == final_position && (first_position + (4 - no_of_spins%4))%4 == final_position) printf("undefined\n"); else if( (first_position + no_of_spins%4)%4 == final_position) printf("cw\n"); else if( (first_position + (4 - no_of_spins%4))%4 == final_position) printf("ccw\n"); else printf("undefined\n"); return 0; } ================================================ FILE: Explanations/Explanations 19/Vasya and Socks Explanation.txt ================================================ Just simulate the process. ----------------------------------- int main() { int socks, new_sock_day; scanf("%d %d", &socks, &new_sock_day); int no_of_days = 0; while(socks > 0) { no_of_days++; if(no_of_days%new_sock_day == 0) socks++; socks--; } printf("%d\n", no_of_days); return 0; } ================================================ FILE: Explanations/Explanations 19/Watchmen Explanation.txt ================================================ We can see that if x1 = x2, or y1 = y2, then Euclidean distance = Manhattan distance. Now, by squaring both sides, it can be seen that Euclidean distance = Manhattan distance only if one or both of the coordinates are equal. We need to count the number of pairs which have the same x, the number of pairs with the same y and subtract the number of pairs with the same (x, y) because they're counted twice. O(n log n) --------------------------------------------------------------------------------------- int main() { int no_of_watchmen; scanf("%d", &no_of_watchmen); map x_frequency; map y_frequency; map , int> x_and_y_frequency; for(int i = 1; i <= no_of_watchmen; i++) { int x, y; scanf("%d %d", &x, &y); x_frequency[x]++; y_frequency[y]++; x_and_y_frequency[make_pair(x,y)]++; } long long same_x_pairs = 0; for(map :: iterator it = x_frequency.begin(); it != x_frequency.end(); it++) { long long current_frequency = it->second; same_x_pairs += (current_frequency*(current_frequency - 1))/2; } long long same_y_pairs = 0; for(map :: iterator it = y_frequency.begin(); it != y_frequency.end(); it++) { long long current_frequency = it->second; same_y_pairs += (current_frequency*(current_frequency - 1))/2; } long long same_x_and_y_pairs = 0; for(map , int> :: iterator it = x_and_y_frequency.begin(); it != x_and_y_frequency.end(); it++) { long long current_frequency = it->second; same_x_and_y_pairs += (current_frequency*(current_frequency - 1))/2; } long long answer = same_x_pairs + same_y_pairs - same_x_and_y_pairs; printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 19/Word Correction Explanation.txt ================================================ Insert a character from text to final text, only if final text last character is not a vowel. -------------------------------------------------------- int is_vowel(char ch) { switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': return true; } return false; } int main() { int length; string text; cin >> length >> text; string final_text; final_text += text[0]; for(int i = 1; i < length; i++) { if(is_vowel(text[i]) && is_vowel(final_text[final_text.size() - 1])) { continue; } final_text += text[i]; } cout << final_text; return 0; } ================================================ FILE: Explanations/Explanations 20/Alena and the Heater Explanation.txt ================================================ Now, it's given that this is always possible. Just choose L and R greedily. If B[i] == B[i - 1], don't do anything. Otherwise if B[i] = 1 and B[i - 1] = 0, since it's guaranteed that it's always possible, it's guranateed last 4 values of B are all 0s. Don't waste time checking. Now, among all such possibilities make the smallest L possible. L = 1 + max(A[i], A[i - 1], A[i - 2], A[i - 3], A[i - 4]) for this i, Do the same thing for all parts where B[i] = 0 and B[i - 1] = 1, and choose the maximum R possible, R = min(A[i], ... A[i - 4]) - 1 for this i. ----------------------------------------------------------------------------------- int main() { int length; cin >> length; vector A(length + 1); for(int i = 0; i < length; i++) cin >> A[i]; string B; cin >> B; int left = -1e9, right = 1e9; for(int i = 4; i < length; i++) { if(B[i] == B[i - 1]) continue; if(B[i] == '1') left = max(left, max_5(A[i], A[i - 1], A[i - 2], A[i - 3], A[i - 4]) + 1); if(B[i] == '0') right = min(right, min_5(A[i], A[i - 1], A[i - 2], A[i - 3], A[i - 4]) - 1); } cout << left << " " << right; return 0; } ================================================ FILE: Explanations/Explanations 20/Fafa and Ancient Alphabet Explanation.txt ================================================ Let f(i, G) be the number of ways to fill up positions from i to N such that A > B The idea is that if you fill position i for equality, then at some point in between (i + 1, N) ... A > B If you fill i such that A[i] > B[i], what comes after doesn't really matter. ----------------------------------------------------------------------------------------- When do you say that A > B ? (For example, why do we say that 112345 is greater that 112333 ? This is how we compare. First, we check if the lengths are equal. If they aren't the longer number is greater. If they are equal, then there must be some position i, for which A[i] =/= B[i], and all j < i A[j] = B[j] That is, there is some FIRST position where the strings aren't equal. The strings share a prefix before that. (In this case, it is 1123 - this is the common prefix. Note that if we were comparing 2562 and 7891, then the length of the common prefix is 0 Becasue the first unequal position is the first !) Now, we want to place a character at the i-th position of A, or B, or both, or neither (If they are both non-zero). How do we do this ? Suppose A[i] = 0, and we fill a character at A[i] so that A[i] = B[i] For instance, A = 0 1 2 B = 5 1 0 Suppose we fill A[1] = 5, then it means strings A and B are equal till position 1, and the number of ways of making A > B is equal to the number of ways of making A > B, by filling characters from (i + 1). There has to be SOME position after i + 1, after which A > B. So, we simply add f(i + 1, G) as that is exactly the information it contains. So, f(i, G) = f(i + 1, G) If we set A[i] = 6, then A is already greater than B .... And the 0s after position i can be filled by any of the m digits, and A will still be greater than B. f(i, G) = (M - B[i])*f(i + 1, ANY_WAY) Because there are (M - B[i]) ways of filling position i so that A[i] > B[i] And only one way of filling A[i] so that A[i] = B[i] Ultimately, f(i, G) = f(i + 1, G) + (M - B[i])*f(i + 1, ANY_WAY) I have just shown the case of A[i] = 0 and B[i] =/= 0. A similar analysis can be done to all possibilities. Just think how can we fill A[i] and B[i] ... How can we fill them for A = B, (In that case, count f(i + 1, G) and How can we fill them for A > B ------------------------------------------------------------------------------------------ f(i, A) be all the number of ways to fill up positions from i to N. if A[i] = 0 and B[i] = 0, then we can fill up the same character in both A and B. We get C(M, 2) f(i + 1, A) or equal here M f(i + 1, G) if A[i] = 0 f(i, G) = (M - B[i]) f(i + 1, A) + 1. f(i + 1, G) if B[i] = 0 f(i, G) = (A[i] - 1) f(i + 1, A) + 1. f(i + 1, G) if A[i] > B[i] f(i, G) = f(i + 1, A) if A[i] < B[i] f(i, G) = 0 if A[i] = B[i] f(i, G) = f(i + 1, G) ---------------------------------------------------------------------------- int main() { const int MOD = 1e9 + 7; int length, no_of_alphabets; scanf("%d %d", &length, &no_of_alphabets); vector A(length + 1); for(int i = 1; i <= length; i++) scanf("%d", &A[i]); vector B(length + 1); for(int i = 1; i <= length; i++) scanf("%d", &B[i]); int no_of_zeroes = 0; for(int i = 1; i <= length; i++) no_of_zeroes += (A[i] == 0) + (B[i] == 0); const int ANY_WAY = 0, GREATER = 1; typedef vector v_ll; vector no_of_ways(length + 5, v_ll(2, 1)); no_of_ways[length + 1][ANY_WAY] = 1; no_of_ways[length + 1][GREATER] = 0; for(int i = length; i >= 1; i--) { no_of_ways[i][ANY_WAY] = no_of_ways[i + 1][ANY_WAY]; if(A[i] == 0) no_of_ways[i][ANY_WAY] = (no_of_ways[i][ANY_WAY]*no_of_alphabets)%MOD; if(B[i] == 0) no_of_ways[i][ANY_WAY] = (no_of_ways[i][ANY_WAY]*no_of_alphabets)%MOD; if(A[i] == 0 && B[i] == 0) { long long choose_different_alphabets = choose_2(no_of_alphabets); long long choose_same_alphabet = no_of_alphabets; no_of_ways[i][GREATER] = choose_different_alphabets*no_of_ways[i + 1][ANY_WAY] + choose_same_alphabet*no_of_ways[i + 1][GREATER]; } else if(A[i] == 0) { no_of_ways[i][GREATER] = (no_of_alphabets - B[i])*no_of_ways[i + 1][ANY_WAY] + no_of_ways[i + 1][GREATER]; } else if(B[i] == 0) { no_of_ways[i][GREATER] = (A[i] - 1)*no_of_ways[i + 1][ANY_WAY] + no_of_ways[i + 1][GREATER]; } else if(A[i] > B[i]) { no_of_ways[i][GREATER] = no_of_ways[i + 1][ANY_WAY]; } else if(A[i] == B[i]) { no_of_ways[i][GREATER] = no_of_ways[i + 1][GREATER]; } else if(A[i] < B[i]) { no_of_ways[i][GREATER] = 0; } no_of_ways[i][ANY_WAY] %= MOD; no_of_ways[i][GREATER] %= MOD; } long long numerator = no_of_ways[1][GREATER]; long long denominator = power(no_of_alphabets, no_of_zeroes, MOD); long long answer = numerator*inverse(denominator, MOD); answer %= MOD; printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 20/Fafa and His Company Explanation.txt ================================================ Now, find the number of i, such that i | (n - i), excluding i = n. This can be done in O(n) However, whenever i | (n - i) => i | n So, count all of n's factors instead. It can be done in root(n). ------------------------------------------------------------------- int main() { int n; scanf("%d", &n); int answer = 1; for(int i = 2; i*i <= n; i++) if(n%i == 0) answer += (i*i == n ? 1 : 2); printf("%d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 20/Fafa and the Gates Explanation.txt ================================================ One way to do is keep track of the current half and then change x and y accordingly. But, a much simpler way is to notice that you are at the line y = x, only when the number of R and U is equal Futher, you cross over, when you make the same step as you did to reach there. If you reached y = x, using R, then you must be in the top half. Taking another R takes you to the lower half. If you reached y = x, using L, then you must be in the lower half. Taking another U takes you to the upper half. ------------------------------------------------------------------------ int main() { int no_of_steps; string steps; cin >> no_of_steps >> steps; int x = 0, y = 0, no_of_changes = 0; for(int i = 0; i < no_of_steps - 1; i++) { if(steps[i] == 'U') y++; if(steps[i] == 'R') x++; no_of_changes += (x == y && steps[i] == steps[i + 1]); } cout << no_of_changes; return 0; } ================================================ FILE: Explanations/Explanations 20/Fixing Typos Explanation.txt ================================================ Be greedy while constructing the string. Insert a character at the back of the string only if it doesn't violate the conditions. This is optimal because the string we have so far is a legal string. ---------------------------------------------------------------------------------------- int main() { string A; cin >> A; string answer; for(int i = 0; i < A.size(); i++) { char last_character, second_last_character, third_last_character; if(answer.size() >= 1) last_character = answer[answer.size() - 1]; if(answer.size() >= 2) second_last_character = answer[answer.size() - 2]; if(answer.size() >= 3) third_last_character = answer[answer.size() - 3]; if(answer.size() >= 2 && A[i] == last_character && last_character == second_last_character) continue; if(answer.size() >= 3 && A[i] == last_character && second_last_character == third_last_character) continue; answer += A[i]; } cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 20/Gargari and Bishops Explanation.txt ================================================ Firstly, notice that if we colour the board black and white like a chess board, then two bishops of the same colour will always attack one common square at least. So, we must place the bishops on different colours. We must find the best black and the best white bishop. Now, to do this, notice that if you put a bishop on square (x, y), you will get all the points in the principal and secondary diagonal that passes through that square. Precompute the diagonal sums. I was going to colour the squares like this - 1 2 3 4 5 1 2 3 6 5 1 2 7 6 5 1 But, the editorial made some brilliant observations. We don't need to explicitly colour the squares. The secondary diagonal has the invariant (x + y) The principal diagonal has the invariant (x - y). However, we want to avoid negative numbers and use array indices, so use (x - y + n). We also need not colour the board black and white physically. Notice that all white squares have even (x + y), and all black squares must have odd (x + y), since black squares are always at a distance of 1 from a white square. ---------------------------------------------------------------------------------------------------- int colour(int x, int y) { int sum = x + y; return (sum%2 == 0 ? WHITE : BLACK); } int get_principal_diagonal_no(int x, int y, int n) { return (x - y + n); } int get_secondary_diagonal_no(int x, int y) { return (x + y); } int main() { int n; scanf("%d", &n); memset(principal_diagonal_sum, 0, sizeof(principal_diagonal_sum)); memset(secondary_diagonal_sum, 0, sizeof(secondary_diagonal_sum)); for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { scanf("%d", &points[x][y]); int principal_diagonal_no = get_principal_diagonal_no(x, y, n); int secondary_diagonal_no = get_secondary_diagonal_no(x, y); principal_diagonal_sum[principal_diagonal_no] += points[x][y]; secondary_diagonal_sum[secondary_diagonal_no] += points[x][y]; } } int white_x, white_y; long long white_best = 0; int black_x, black_y; long long black_best = 0; for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { int principal_diagonal_no = get_principal_diagonal_no(x, y, n); int secondary_diagonal_no = get_secondary_diagonal_no(x, y); long long bishop_score = principal_diagonal_sum[principal_diagonal_no] + secondary_diagonal_sum[secondary_diagonal_no] - points[x][y]; if(colour(x, y) == WHITE) { if(bishop_score >= white_best) { white_best = bishop_score, white_x = x, white_y = y; } } else if(colour(x, y) == BLACK) { if(bishop_score >= black_best) { black_best = bishop_score, black_x = x, black_y = y; } } } } long long best = black_best + white_best; printf("%I64d\n", best); printf("%d %d %d %d", white_x, white_y, black_x, black_y); return 0; } ================================================ FILE: Explanations/Explanations 20/Gargari and Permutations Alternate Solution Explanation.txt ================================================ Let f(i) be the maximum subsequence that can be constructed from the first i elements of the first vector. Now, f(i) = 1, at least. Because a subsequence of 1 is always possible. For, all j < i Let Current = A[i], Previous = A[j], If Previous comes before Current in all permutations, then f(i) = f(j) + 1 Choose the best possible j Answer = max{f(i)} This is not as inspired as thinking in terms of a graph, but it gets the job done nonetheless. ---------------------------------------------------------------------------------------------------------------------- int main() { int no_of_permutations, length; scanf("%d %d", &length, &no_of_permutations); for(int k = 1; k <= no_of_permutations; k++) { for(int i = 1; i <= length; i++) { scanf("%d", &P[k][i]); int element = P[k][i]; position[k][element] = i; } } int answer = 1; for(int i = 1; i <= length; i++) { maximum_length_till[i] = 1; for(int j = 1; j < i; j++) { int current = P[1][i], previous = P[1][j]; int previous_always_before_current = true; for(int k = 1; k <= no_of_permutations; k++) { if(position[k][previous] > position[k][current]) { previous_always_before_current = false; } } if(previous_always_before_current) { maximum_length_till[i] = max(maximum_length_till[i], 1 + maximum_length_till[j]); } } answer = max(answer, maximum_length_till[i]); } printf("%d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 20/Gargari and Permutations Explanation.txt ================================================ Here's the main idea. If a-b-c is a common subsequence, then a occurs before b and b occurs before c in all the permutations. So, here's what we do. Draw an edge in between (i, j) if i comes before j in all the permutations. Now, in this graph, find the length of the longest path. -------------------------------------------------------------------------------------------------------------------- int get_longest_path(int v) { if(longest_path[v] != -1) return longest_path[v]; longest_path[v] = 1; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; longest_path[v] = max(longest_path[v], 1 + get_longest_path(child)); } return longest_path[v]; } int main() { int no_of_permutations, length; scanf("%d %d", &length, &no_of_permutations); for(int k = 1; k <= no_of_permutations; k++) { for(int i = 1; i <= length; i++) { int element; scanf("%d", &element); position[k][element] = i; } } for(int i = 1; i <= length; i++) { for(int j = i + 1; j <= length; j++) { int i_always_before_j = true, j_always_before_i = true; for(int k = 1; k <= no_of_permutations; k++) { if(position[k][i] > position[k][j]) { i_always_before_j = false; } if(position[k][j] > position[k][i]) { j_always_before_i = false; } } if(i_always_before_j) { graph[i].push_back(j); } if(j_always_before_i) { graph[j].push_back(i); } } } memset(longest_path, -1, sizeof(longest_path)); int graph_longest_path = 0; for(int i = 1; i <= length; i++) graph_longest_path = max(graph_longest_path, get_longest_path(i)); printf("%d\n", graph_longest_path); return 0; } ================================================ FILE: Explanations/Explanations 20/Hard Process Explanation.txt ================================================ Here's the trick. Maintain two pointers, [L, R]. We want the largest segment with at most k 0s. now, to do this fix L and let R go as far as possible till it has at most k 0s. Once there are more than K 0's, then Increment L till there are <= K 0's. Now, if R is at position X, when no of 0's = K + 1, There is no need to start checking all segments from [L + 1, L + 2], [L + 1, L + 3], .... [L + 1, X] and so on and so forth. We know that [L, X - 1] was a good segment. And all these segments are smaller than it. We only need to check larger segments. So for every possible left from [L, X- 1], we check only larger intervals, [L + 1, X + 1] and so on. If we know [L, X - 1] is a good segment, there is no need to check intervals smaller than that. --------------------------------------- int main() { int no_of_elements, max_zeroes; scanf("%d %d", &no_of_elements, &max_zeroes); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int no_of_0s = 0; int change_left = 0, change_right = 0, left = 1, right = 1, max_window_size = 0; while(right <= no_of_elements) { if(A[right] == 0) no_of_0s++; while(no_of_0s > max_zeroes) { if(A[left] == 0) no_of_0s--; left++; } int window_size = right - (left - 1); if(window_size > max_window_size) { max_window_size = window_size, change_left = left, change_right = right; } right++; } for(int i = change_left; i <= change_right; i++) A[i] = 1; printf("%d\n", max_window_size); for(int i = 1; i <= no_of_elements; i++) printf("%d ", A[i]); return 0; } ================================================ FILE: Explanations/Explanations 20/Lisa and Dima Explanation.txt ================================================ If n is a prime number, then k = 1 Else, we need to check if n can be written as the sum of two prime numbers. The sum of two odd numbers is never a prime number. So, one of the summands must be even, which means = 2. 2 + (n - 2) We need to check if (n - 2) is prime. Otherwise, we will always have answer with 3. Why ? Take any odd prime p < n. Notice that (n - p) is an even number. By Goldbach's conjecture, any even number in the specified range can be written as the sum of two prime numbers. Now, how do we find these three primes ? We need to use the fact that the prime gap is never too large till 10^9. It is at most 300. So, given N, ... We search for a prime number from [N, N - 300] .... We are guranteed to get a prime number. Now, we take the difference, N - p, which is an even number less than 300. We can check with brute force how to sum up to 300 with two prime numbers. ----------------------------------------------------------------------------------------------------------------------- void break_into_sum_of_primes(int N, int &prime_1, int &prime_2) { vector is_prime(N + 1, true); sieve(is_prime); for(int i = 2; i <= N; i++) { if(is_prime[i] && is_prime[N - i]) { prime_1 = i; prime_2 = N - i; return; } } } int main() { int n; scanf("%d", &n); if(is_prime(n)) { printf("1\n%d\n", n); return 0; } if(is_prime(n - 2)) { printf("2\n%d %d", 2, n - 2); return 0; } int prime_1, prime_2, prime_3; for(int i = n - 4; ; i--) { if(is_prime(i)) { prime_3 = i; break; } } break_into_sum_of_primes(n - prime_3, prime_1, prime_2); printf("3\n%d %d %d\n", prime_1, prime_2, prime_3); return 0; } ================================================ FILE: Explanations/Explanations 20/Love Rescue Explanation.txt ================================================ Draw an edge in between any two alphabets that occur in the same position of different strings. i.e. ... if A[i] =/= B[i], draw an edge in between them We will have a graph. What we must do is make sure all the components stay connected but minimise the number of edges required. If x can be reached from y in the original graph, it must be true for the new graph as well. Now, how do we do this ? Firstly, if a component has v vertices, it requires a minimum of (v - 1) edges to stay connected. In the contest, I thought I was only allowed to delete edges, but it turns out you can construct your own graph just ensuring the same components are connected ! (It's possible to do this by finding the MST of every component, but it's not required.) I made two solutions. In the first solution, every component had a sink, S that had an edge will all members of the component. In the other solution, every component member had either 1 or 2 edges, depending on whether it was the first/last, or intermediate vertex. Very interesting question. ----------------------------------------------------------------- const int MAX_N = 26; vector graph[MAX_N]; vector visited(MAX_N, false); vector component[MAX_N] ; void mark(int v, int component_no) { visited[v] = true; component[component_no].push_back(v); for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(!visited[child]) mark(child, component_no); } } int main() { int length; string A, B; cin >> length >> A >> B; for(int i = 0; i < length; i++) { if(A[i] != B[i]) { graph[A[i] - 'a'].push_back(B[i] - 'a'); graph[B[i] - 'a'].push_back(A[i] - 'a'); } } int component_no = 0, no_of_edges = 0; for(int i = 0; i < MAX_N; i++) { if(graph[i].size() != 0 && !visited[i]) { mark(i, component_no); no_of_edges += component[component_no].size() - 1; component_no++; } } cout << no_of_edges << "\n"; for(int i = 0; i < component_no; i++) { for(int j = 1; j < component[i].size(); j++) { cout << char('a' + component[i][j - 1]) << " " << char('a' + component[i][j]) << "\n"; } } return 0; } ---------------------------------------------------------------- The other solution with the sink would be printed like this - for(int i = 0; i < component_no; i++) { for(int j = 1; j < component[i].size(); j++) { cout << char('a' + component[i][0]) << " " << char('a' + component[i][j]) << "\n"; } } ================================================ FILE: Explanations/Explanations 20/Mashmok and Numbers Explanation.txt ================================================ Notice that the smallest score possible is n/2 ... By making all consecutive numbers coprime. The last (n - 2) numbers are such that gcd(A[i], A[i + 1]) = 1. So, the minimum contribution = (n - 2)/2 So, make the gcd of the first two numbers T = S - (n - 2)/2. I used T, 2T Now, Score = 0, is possible only for n = 1 n = 1 cannot reach any other score. ------------------------------------------------------------------- int main() { int n, score; scanf("%d %d", &n, &score); int minimum_score = n/2; if(n == 1 && score == 0) {printf("1\n"); return ;} if(n == 1 || score < minimum_score) { printf("-1\n"); return 0; } int score_except_last_two = (n - 2)/2; int second_term = score - score_except_last_two; printf("%d %d ", second_term, 2*second_term); for(int i = 3; i <= n; i++) printf("%d ", 2*second_term + i); return 0; } ================================================ FILE: Explanations/Explanations 20/Non-Secret Cypher Explanation.txt ================================================ For each element L, find the smallest R such that A[L, ... , R] is a good subarray. Notice that all subarrays starting at L and ending at least at R are good. There are N - R + 1 such arrays. So, add (N - R + 1) to the answer. Notice that subarrays ending at R and starting at most by L are also good subarrays. There are L such arrays. Now, we don't add L to the answer because we'd be overcounting. When we are at L, we have already considered all subarrays starting at any position smaller than L. So, don't count twice. We should fix one end, either L or R and then find the other end. ------------------------------------------------------------------------------------ int main() { int no_of_elements, no_of_equal_elements; scanf("%d %d", &no_of_elements, &no_of_equal_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int left = 1, right = 1; long long no_of_subarrays = 0; map frequency; while(right <= no_of_elements) { frequency[A[right]]++; while(frequency[A[right]] == no_of_equal_elements) { no_of_subarrays += (no_of_elements - right + 1); frequency[A[left]]--; left++; } right++; } printf("%I64d\n", no_of_subarrays); return 0; } ================================================ FILE: Explanations/Explanations 20/Olympiad Explanation.txt ================================================ The number of awards is equal to the number of positive numbers greater than 0. Now, it can be done in O(n), but I used a set and did it in O(n log n) --------------------------------------------------------------------------------------- int main() { int n; scanf("%d", &n); set awards; for(int i = 1; i <= n; i++) { int score; scanf("%d", &score); if(score > 0) awards.insert(score); } printf("%u\n", awards.size()); return 0; } ================================================ FILE: Explanations/Explanations 20/Partition Explanation.txt ================================================ Now, I would have done this by maintaining a sum of all positive numbers, P, sum of all negative numbers N And then P - N. But the editorial solution was even more elegant. Sum over abs(A[i]) It's a beautiful one-step observation that eschews some work. I loved it. I loved the element of surprise and how the two steps are combined. ----------------------------------------------------------------------------------- #define abs(x) (x > 0 ? x : -x) int main() { int no_of_elements; scanf("%d", &no_of_elements); int answer = 0; while(no_of_elements--) { int element; scanf("%d", &element); answer += abs(element); } printf("%d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 20/Petya and His Friends Alternate Solution Explanation.txt ================================================ Blog Link - http://qr.ae/TUTYGd Raziman told me about this brilliant solution. It was so creative, I had to code it myself ! I loved it so much. Here's the idea ... Write down all numbers from 1 to N in binary. For each bit, associate prime P[i] if the bit is set, and prime Q[i] if bit is unset. For example, we will associate 2 with all numbers which have the first bit set and 3 with all numbers which have the first bit unset. Every pair of numbers which have a common bit, have a common factor. Have we covered all pairs ? No. What pairs are remaining, ... The pairs in which no two numbers have a common bit set. So, for all (I, (n - 1)^I), we will associate another prime. After this, we have ensured that all pairs of numbers have a common prime factor (at least). No prime divides all numbers. So, we are done ! This approach is beautiful and creative ! -------------------------------------------------------------- int main() { const int LIMIT = 300; vector primes; precompute(primes, LIMIT); int n; scanf("%d", &n); if(n == 2) { printf("-1\n"); return 0; } int N = nearest_power_of_2_greater_than(n); vector A(N + 5, 1); int first_free_prime = 0; for(int bit = 0; (1 << bit) < N; bit++) { int set_bit_prime = primes[first_free_prime++]; int unset_bit_prime = primes[first_free_prime++]; for(int i = 1; i <= N; i++) { if(is_bit_set(i, bit)) A[i] *= set_bit_prime; else A[i] *= unset_bit_prime; } } for(int i = 1; 2*i <= N; i++, first_free_prime++) { A[i] *= primes[first_free_prime]; A[(N - 1)^i] *= primes[first_free_prime]; } for(int i = 1; i <= n; i++) printf("%I64d\n", A[i]); return 0; } ================================================ FILE: Explanations/Explanations 20/Petya and His Friends Explanation.txt ================================================ Here was my solution, First assign every element other than A[2], a factor of 2. Now, assign every element other than A[3] a factor of 3. Now, assign every element other than A[1], a factor of 5. Since, gcd(A[1], A[2], A[3]) = 1, the gcd of the entire array = 1 First three elements = (2 x 3, 3 x 5, 2 x 5, 2 x 3 x 5, 2 x 3 x 5 ... ) Now, the first three elements are (6, 15, 10) Now, after that append 0's to every number from A[4] onwards just to make sure the numbers are different. Solution = (6, 15, 10, 60, 600, 6000, 60000, etc) Important to know the corner case. No solution for N = 2 --------------------------------------------------------------- int main() { int n; scanf("%d", &n); if(n == 2) { printf("-1\n"); return 0; } printf("6\n10\n15\n"); for(int i = 4; i <= n; i++) { printf("6"); for(int zero = 1; zero <= i - 4 + 1; zero++) printf("0"); printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 20/Phone Numbers Explanation.txt ================================================ If the length of the answer string is greater than |S|, then simply print S and then append the smallest character of (S) at the end. Otherwise k <= n. Now, we want to match the longest prefix possible. IF A > S ... then it means for some i, A[i] > S[i] and before that A[j] = S[j] We want to maximise this i ... So we find the first i from the end for which a character greater than S[i] is available. A = S[1, ... , i] + first available greater character(S[i]) + smallest character of S (till length becomes k) -------------------------------------------------------------------------------------------------------------------- int main() { int length, answer_length; string A; cin >> length >> answer_length >> A; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < A.size(); i++) present[A[i] - 'a'] = true; char smallest_alphabet; for(int i = 0; i < NO_OF_ALPHABETS; i++) { if(present[i]) { smallest_alphabet = 'a' + i; break; } } if(answer_length > length) { cout << A; for(int i = A.size(); i < answer_length; i++) cout << smallest_alphabet; return 0; } int first_change_point; char char_at_first_change_point; for(int i = answer_length - 1; i >= 0; i--) { int greater_char_available = false; for(char alphabet = A[i] + 1; alphabet <= 'z'; alphabet++) { if(present[alphabet - 'a']) { greater_char_available = true; first_change_point = i; char_at_first_change_point = alphabet; break; } } if(greater_char_available) break; } for(int i = 0; i < first_change_point; i++) cout << A[i]; cout << char_at_first_change_point; for(int i = first_change_point + 1; i < answer_length; i++) cout << smallest_alphabet; return 0; } ================================================ FILE: Explanations/Explanations 20/Pocket Book Explanation.txt ================================================ Let's say you want string S[1],S[2], ... , S[m] Then first, swap string 1, with string X with prefix length = m, X is whichever string the character S[m] is from. Then do the same for S[m - 1], and so on. You can get any combination that is possible. The answer = product of distinct characters at each position. Now, I missed it. However, I have seen similar constructive type problems. The idea occurs in some Digit DPs too. Fix every character from right to left. I don't know why I didn't realise this. Maybe I wasn't interpreting this as a constructive problem and asking myself how to construct a string. --------------------------------------------------------------------------------------- int main() { int no_of_names, length; cin >> no_of_names >> length; set distinct_characters[length]; while(no_of_names--) { string name; cin >> name; for(int i = 0; i < length; i++) distinct_characters[i].insert(name[i]); } const int MOD = 1e9 + 7; long long total_strings = 1; for(int i = 0; i < length; i++) { total_strings = (total_strings*distinct_characters[i].size())%MOD; } cout << total_strings; return 0; } ================================================ FILE: Explanations/Explanations 20/Points on the Line Explanation.txt ================================================ First sort the sequence. For each i, calculate how many elements would need to be removed if A[i] was the first element. We remove (i - 1) elements from the back ... Let j be the first element position that A[j] - A[i] > d In that case, we need to remove all elements from j to n. This is given by n - (j - 1) = n - j + 1 Note that in case j = n + 1, this formula still works and we will remove 0 elements. ---------------------------------------------------------------------------------------------------------- int main() { int n, d; scanf("%d %d", &n, &d); vector A(n + 1, 0); for(int i = 1; i <= n; i++) scanf("%d", &A[i]); sort(all(A)); int removed_elements = n; for(int i = 1; i <= n; i++) { int removed_elements_to_start_at_i = i - 1, j = i; while(j <= n && A[j] - A[i] <= d) j++; removed_elements_to_start_at_i += (n - j + 1); removed_elements = min(removed_elements, removed_elements_to_start_at_i); } printf("%d\n", removed_elements); return 0; } ================================================ FILE: Explanations/Explanations 20/Protect Sheep Explanation.txt ================================================ If there are a wolf and a sheep in adjacent cells, the answer is no. Else it is always yes. --------------------------------------------------------------------------------------------------- int main() { int rows, columns; scanf("%d %d", &rows, &columns); char pasture[rows + 5][columns + 5]; for(int r = 1; r <= rows; r++) scanf("%s", pasture[r] + 1); int is_possible = true; for(int r = 1; r <= rows; r++) { for(int c = 1; c <= columns; c++) { if(pasture[r][c] == 'W') { if(pasture[r + 1][c] == 'S' || pasture[r][c + 1] == 'S' || pasture[r - 1][c] == 'S' || pasture[r][c - 1] == 'S') { is_possible = false; } } } } if(!is_possible) { printf("No\n"); return 0; } printf("Yes\n"); for(int r = 1; r <= rows; r++) { for(int c = 1; c <= columns; c++) { char current_cell = (pasture[r][c] == '.' ? 'D' : pasture[r][c]); printf("%c", current_cell); } printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 20/String Transformation Explanation.txt ================================================ Be greedy. Try to get each character, as early as possible. Let, last = 'a' - 1 at first. Now, scan through the string. If S[i] <= last + 1, Then S[i] = last + 1, last = S[i] At the end, check if last = 'z'. ---------------------------------------------------------------------- int main() { string S; cin >> S; int last_found = 'a' - 1; for(int i = 0; i < S.size() && last_found < 'z'; i++) { if(S[i] <= last_found + 1) { S[i] = last_found + 1; last_found = S[i]; } } cout << (last_found == 'z' ? S : "-1"); return 0; } ================================================ FILE: Explanations/Explanations 20/Sum and Replace Explanation.txt ================================================ Now, it happens that d(n) is a function that converges rapidly. Every number will ultimately be reduced to 2. In the given range every number goes to 2 in at most 6 times. After that d(2) = 2 and d(1) = 1 How do we use this fact ? We can't use lazy propagation for a function like number of divisors. Here's what we do ... Use a segment tree for sum and another one for max. While performing an update check if the max of any node is <= 2. If it is, then we can ignore it as it won't change with the update. We can afford to go to every leaf node and avoid nodes who's max <= 2. In the worst case, we will do 6 O(n) scans ! Which is perfectly fine ! It's very reasonable. This is an important trick to note in functions which converge rapidly. We can afford to change each element one-by-one and ignore nodes which have already hit the converged point. We won't be doing too many updates ... That's the main thing to learn here. Again the idea of a segment tree is to break the query interval into intervals that either lie completely with an interval or ones that lie completely outside the interval. --------------------------------------------------------- void precompute_divisors() { vector largest_prime_factor(MAX_N, 0); no_of_divisors[1] = 1; for(int i = 2; i < MAX_N; i++) { if(largest_prime_factor[i] == 0) { for(int multiple = i; multiple < MAX_N; multiple += i) { largest_prime_factor[multiple] = i; } } int exponent = 0, reduced_i = i; while(reduced_i%largest_prime_factor[i] == 0) { reduced_i /= largest_prime_factor[i]; exponent++; } no_of_divisors[i] = (exponent + 1)*no_of_divisors[reduced_i]; } } void build(int n, int left, int right) { if(left == right) { max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); } long long get_sum(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left) return 0; if(query_left <= left && right <= query_right) return sum_tree[n]; int mid = (left + right) >> 1; long long left_sum = get_sum(LEFT(n), left, mid, query_left, query_right); long long right_sum = get_sum(RIGHT(n), mid + 1, right, query_left, query_right); return (left_sum + right_sum); } void update(int n, int left, int right, int query_left, int query_right) { if(query_right < left || right < query_left || max_tree[n] <= 2) return; if(left == right) { A[left] = no_of_divisors[A[left]]; max_tree[n] = sum_tree[n] = A[left]; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, query_left, query_right); update(RIGHT(n), mid + 1, right, query_left, query_right); max_tree[n] = max(max_tree[LEFT(n)], max_tree[RIGHT(n)]); sum_tree[n] = sum_tree[LEFT(n)] + sum_tree[RIGHT(n)]; } int main() { precompute_divisors(); int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); build(1, 1, no_of_elements); while(no_of_queries--) { const int SUM = 2, REPLACE = 1; int query_type, left, right; scanf("%d %d %d", &query_type, &left, &right); if(query_type == SUM) { long long sum = get_sum(1, 1, no_of_elements, left, right); printf("%I64d\n", sum); } else if(query_type == REPLACE) { update(1, 1, no_of_elements, left, right); } } return 0; } ================================================ FILE: Explanations/Explanations 20/Vile Grasshoppers Explanation.txt ================================================ We need to find the greatest number upto y, such that it is not divisible by any number from [2, p]. Here's a very important fact - Upto 10^9, the distance between consecutive primes is never more than 300 or so. Notice that any prime number P, is automatically co prime to every number [2, p] This is a very important fact. This allows us to start from y, and keep decrementing 1 till we find a number who's smallest factor is > p. (We will never do more than 300 factorisation checks) As for the factorisation itself ... we go from [2, min{p, root(i)}]. Either way, it's quite reasonable. Never more than 10^5. ------------------------------------------------------------------------------------------------------------------------------------------------- int main() { int p, y; scanf("%d %d", &p, &y); int answer = y; while(answer > p) { int coprime_till_p = true; for(int i = 2; i <= p && i*i <= y; i++) { if(answer%i == 0) { coprime_till_p = false; break; } } if(coprime_till_p) break; answer--; } printf("%d\n", answer == p ? -1 : answer); return 0; } ================================================ FILE: Explanations/Explanations 20/Weird Subtraction Process Explanation.txt ================================================ Constraints are too big too simulate. The main observation is that if a >= 2b, Then, we will keep subtracting a with 2b, till a < 2b. In other words, a = a (mod 2b) This is similar to the Euclidean GCD algorithm. A very beautiful problem, and a very beautiful logic. ---------------------------------------------------------------------------------------------------------- int main() { long long a, b; cin >> a >> b; while(a != 0 && b != 0 && (a >= 2*b || b >= 2*a)) { if(a >= 2*b) { a %= (2*b); } else if(b >= 2*a) { b %= (2*a); } } cout << a << " " << b; return 0; } ================================================ FILE: Explanations/Explanations 21/Aramic Script Bitmask Solution.txt ================================================ Maintain a binary string of length 26. Construct a binary string with each given string as follows : The i-th bit is set if the i-th alphabet is present in the string and 0 otherwise. Strings which have the same 'root' have the same mask. Count the number of distinct masks. ------------------------------------------------ int main() { int no_of_words; cin >> no_of_words; set mask; while(no_of_words--) { string word; cin >> word; int current_mask = 0; for(int i = 0; i < word.size(); i++) current_mask |= (1 << (word[i] - 'a')); mask.insert(current_mask); } cout << mask.size(); return 0; } ================================================ FILE: Explanations/Explanations 21/Aramic Script Explanation.txt ================================================ For each string, keep track of which alphabets were used. And then make another string X, consisting of exactly one occurence of each of it's alphabets in alphabetical order. This ensures strings which have the same root are mapped to the same X. Count the number of distinct X. ---------------------------------------------------------- int main() { int no_of_words; cin >> no_of_words; set distinct_words; while(no_of_words--) { string word; cin >> word; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < word.size(); i++) present[word[i] - 'a'] = true; string root; for(int i = 0; i < NO_OF_ALPHABETS; i++) if(present[i]) root += (char)('a' + i); distinct_words.insert(root); } cout << distinct_words.size(); return 0; } ================================================ FILE: Explanations/Explanations 21/Arithmetic Progression Explanation.txt ================================================ There are a lot of different cases to handle in this one ! Firstly, if n = 1, then there are an infinite number of solutions. ----------------------------------------------- Then, let us say there are n integers already in AP with d > 0, Then we can add two cards, one at A[0] - d, and A[0] + d. The only exception is when n = 2, in that case, we can add a middle element too ! (This is an exception because doing this changes the d.) We can do this only if the middle elements is an integer. ------------------------------------------------ What to do if AP with d = 0 ? Then only one card can be inserted. ----------------------------------------------- Now, the tricky case, what to do if it's not an AP, but every pair of consecutive numbers EXCEPT 1 is at a difference of d. We have to check that if A[i] and A[i + 1] are not at a difference of d, Then A[i + 1] - A[i] = 2d So we can insert a card in between them ! --------------------------------------------- While checking the d of the sequence, check the minimum d, because adding new elements decreases the d but never increases it. --------------------------------------------------- int main() { int no_of_cards; scanf("%d", &no_of_cards); vector card(no_of_cards); for(int i = 0; i < no_of_cards; i++) scanf("%d", &card[i]); if(no_of_cards == 1) { printf("-1\n"); return 0; } vector new_cards; if(no_of_cards == 2 && (card[0] != card[1]) && (card[0] + card[1])%2 == 0) { new_cards.push_back( (card[0] + card[1])/2 ); } sort(all(card)); int min_difference = card[1] - card[0]; for(int i = 2; i < no_of_cards; i++) min_difference = min(min_difference, card[i] - card[i - 1]); int ap_possible = true, new_middle_cards = 0; for(int i = 1; i < no_of_cards; i++) { if(card[i] - card[i - 1] != min_difference) { if(card[i] - card[i - 1] == 2*min_difference) { new_middle_cards++; } else { ap_possible = false; } } } if(ap_possible) { if(min_difference == 0) { new_cards.push_back(card[0]); } else if(new_middle_cards == 0) { new_cards.push_back(card[0] - min_difference); new_cards.push_back(card[no_of_cards - 1] + min_difference); } else if(new_middle_cards == 1) { for(int i = 1; i < no_of_cards; i++) if(card[i] - card[i - 1] == 2*min_difference) new_cards.push_back(card[i - 1] + min_difference); } } sort(all(new_cards)); printf("%d\n", new_cards.size()); for(int i = 0; i < new_cards.size(); i++) printf("%d ", new_cards[i]); return 0; } ================================================ FILE: Explanations/Explanations 21/Bash and a Tough Math Puzzle Explanation.txt ================================================ If the gcd(L, R) is a multiple of x, then all we have to do is change any one element in the range to x. If there is at most one element in the range which is not a multiple of x, we set it to x to make the gcd = x If there are two elements which are not multiples of x, then it is impossible. -------------------------------- So, here's the idea - 1. Look for the first element which is not a multiple of x. Let it be A[p]. If it doesn't exist, then it is possible to make gcd = x. 2. Look for the first element which is not a multiple of x in [p + 1, R]. If it doesn't exist, then it is possible to make gcd = x. If it exists, then answer is NO. ---------------------------------------------- Now, how to find the first element that is not a multiple of x ? Maintain a GCD-segment tree. If the gcd of a node is a multiple of x, then don't look further. If the gcd is not a multiple of x, then 1. If it is a leaf node, then return the position of the leaf. 2. Look in the left subtree first. If it is found in the left subtree, return the position. 3. If it is not found in the left subtree, look in the right subtree. ----------------------------------------------------------------------------------------------------- int gcd(int a, int b) { if(a == 0 || b == 0) return (a + b); else return gcd(min(a, b), max(a, b)%min(a, b)); } void build(int n, int left, int right) { if(left == right) { gcd_tree[n] = A[left]; return; } int mid = (left + right) >> 1; build(LEFT(n), left, mid); build(RIGHT(n), mid + 1, right); gcd_tree[n] = gcd(gcd_tree[LEFT(n)], gcd_tree[RIGHT(n)]); } void update(int n, int left, int right, int index, int value) { if(right < index || index < left) return; if(left == right) { gcd_tree[n] = value; return; } int mid = (left + right) >> 1; update(LEFT(n), left, mid, index, value); update(RIGHT(n), mid + 1, right, index, value); gcd_tree[n] = gcd(gcd_tree[LEFT(n)], gcd_tree[RIGHT(n)]); } int get_first_indivisible_element(int n, int left, int right, int query_left, int query_right, int x) { if(gcd_tree[n]%x == 0 || right < query_left || query_right < left || right < left || query_right < query_left) return NOT_FOUND; if(left == right) //Leaf node and it's not divisible. So, it has to be this element. return left; int mid = (left + right) >> 1; int left_answer = get_first_indivisible_element(LEFT(n), left, mid, query_left, query_right, x); if(left_answer != NOT_FOUND) return left_answer; int right_answer = get_first_indivisible_element(RIGHT(n), mid + 1, right, query_left, query_right, x); return right_answer; } void solve() { const int GUESS_GCD = 1, UPDATE = 2; int query_type; scanf("%d ", &query_type); if(query_type == GUESS_GCD) { int left, right, x; scanf("%d %d %d", &left, &right, &x); int first_indivisible_element = get_first_indivisible_element(1, 1, no_of_elements, left, right, x); if(first_indivisible_element == NOT_FOUND) //Entire range divisible by x. { printf("YES\n"); } else if(first_indivisible_element != NOT_FOUND) //If 2 elements are not divisible by x, answer is NO. Else, if it is <= 1, answer is YES { int second_indivisible_element = get_first_indivisible_element(1, 1, no_of_elements, first_indivisible_element + 1, right, x); printf(second_indivisible_element == NOT_FOUND ? "YES\n" : "NO\n"); } } else if(query_type == UPDATE) { int index, value; scanf("%d %d", &index, &value); update(1, 1, no_of_elements, index, value); } } int main() { scanf("%d", &no_of_elements); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); build(1, 1, no_of_elements); int no_of_queries; scanf("%d", &no_of_queries); while(no_of_queries--) solve(); return 0; } ================================================ FILE: Explanations/Explanations 21/Consecutive Subsequences Explanation.txt ================================================ Let f(A[i]) denote the longest sequence ending at A[i]. Now, A[i] is appended to the sequence ending at A[i] - 1 So, f(A[i]) = 1 + f(A[i] - 1) As n is large use maps. Don't use unordered maps as unordered maps have worst case complexity O(n) so the algorithm degrades to O(n^2) and causes TLE. ------------------------------ I've solved two problems seperately. First, find the longest sequence length and the last element. Then collect the indices. If I know the longest sequence has length L, and last element X Then I need to store the index of (X - L + 1) (X - L + 2) ... (X -1) (X) At first the index list is empty. I store the index of element (X - L + 1). Then, after that store the index of i, where A[i] = A[index.back()] + 1 Because we know that i must be the index of the element that is one more than the last element in the list. ---------------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int last_element, longest_sequence = 0; map answer_with_last_element; for(int i = 1; i <= no_of_elements; i++) { answer_with_last_element[A[i]] = 1 + answer_with_last_element[A[i] - 1]; if(answer_with_last_element[A[i]] > longest_sequence) { longest_sequence = answer_with_last_element[A[i]]; last_element = A[i]; } } vector index; for(int i = 1; i <= no_of_elements; i++) { if(index.size() == 0) { if(A[i] == last_element - longest_sequence + 1) index.push_back(i); } else if(A[i] == A[index.back()] + 1) { index.push_back(i); } } printf("%d\n", longest_sequence); for(int i = 0; i < longest_sequence; i++) printf("%d ", index[i]); return 0; } ================================================ FILE: Explanations/Explanations 21/Cyclic Components Explanation.txt ================================================ Store each component in a seperate vector. In the contest, I used a more complicated solution. But there's an easier solution with an observation - A component is a cycle if each vertex has degree 2. This can be proven through induction. --------------------------------------------------------- void dfs_and_mark_component(int v, int no) { component[no].push_back(v); component_no[v] = no; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(component_no[child] == UNMARKED) dfs_and_mark_component(child, no); } } int main() { int no_of_vertices, no_of_edges; scanf("%d %d", &no_of_vertices, &no_of_edges); for(int i = 1; i <= no_of_edges; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } memset(component_no, UNMARKED, sizeof(component_no)); int no_of_components = 0; for(int i = 1; i <= no_of_vertices; i++) { if(component_no[i] == UNMARKED) dfs_and_mark_component(i, no_of_components++); } int no_of_cycles = 0; for(int i = 0; i < no_of_components; i++) { int is_cycle = true; for(int j = 0; j < component[i].size(); j++) { int v = component[i][j]; if(graph[v].size() != 2) { is_cycle = false; } } no_of_cycles += (is_cycle == true); } printf("%d\n", no_of_cycles); return 0; } ================================================ FILE: Explanations/Explanations 21/Divide by Three Multiply by Two Alternate Solution Explanation.txt ================================================ http://qr.ae/TUTyWZ For any x, we cannot have both (2x and x/3) in the array. This is because from x, we can go either to 2x or to x/3. If we go to 2x, we can never reach x/3 as we can never divide by 2. Similar reasoning for x/3. For any element A[i], the chain from A[i] is uniquely determined. All we need to do is find the first element. This is the element x, for which x/2 and 3x are both absent from the array. ----------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); map present; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64u", &A[i]); present[A[i]] = true; } ULL first_element; for(int i = 1; i <= no_of_elements; i++) { int comes_from_multiplication = (A[i]%2 == 0 && present[A[i]/2]); int comes_from_division = (A[i] <= 1e18 && present[3*A[i]]); if(!comes_from_multiplication && !comes_from_division) { first_element = A[i]; } } vector solution; solution.push_back(first_element); while(solution.size() < no_of_elements) { ULL last_element = solution.back(); if(last_element%3 == 0 && present[last_element/3]) { solution.push_back(last_element/3); } else { solution.push_back(2*last_element); } } for(int i = 0; i < no_of_elements; i++) printf("%I64u ", solution[i]); return 0; } ================================================ FILE: Explanations/Explanations 21/Divide by Three, Multiply by Two Explanation.txt ================================================ http://qr.ae/TUTyWZ Notice that Exp(3) only decreases from left to right. Exp(2) only increases. -Exp(3) only increases. This means Exp(2) - Exp(3) increases from left to right. In going from one element to another, only one of these values changes by 1. SO, the quantity Exp(2) - Exp(3) is a monotonic and increases by 1 for each element. The beautiful solution is to simply sort the array according to (Exp(2) - Exp(3)) ------------------------------------- struct info { int two, three; unsigned long long number; }; int compare(const info &A, const info &B) { if(A.two - A.three < B.two - B.three) return true; else return false; } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) { unsigned long long element; scanf("%I64u", &element); A[i].number = element; A[i].two = 0, A[i].three = 0; while(element%2 == 0) A[i].two++, element /= 2; while(element%3 == 0) A[i].three++, element /= 3; } sort(all(A), compare); for(int i = 0; i < no_of_elements; i++) printf("%I64u ", A[i].number); return 0; } ================================================ FILE: Explanations/Explanations 21/Dreamoon and Sets Explanation.txt ================================================ For the explanation, refer to this blog post - https://mathprogrammer.quora.com/4147697-1?share=fcd3169f&srid=F7Hz -------------------------------------------------- int main() { int no_of_sets, k; scanf("%d %d", &no_of_sets, &k); int maximum_number = (6*(no_of_sets - 1) + 5)*k; printf("%d\n", maximum_number); for(int i = 0; i < no_of_sets; i++) { const int NO_OF_TERMS = 4; int mod[NO_OF_TERMS] = {1, 2, 3, 5}; for(int m = 0; m < NO_OF_TERMS; m++) { int term = (6*i + mod[m])*k; printf("%d ", term); } printf("\n"); } return 0; } ================================================ FILE: Explanations/Explanations 21/File Name Explanation.txt ================================================ For every character i, check if the previous two characters were x, if it was, then remove it. ------------------------------------- int main() { int length; string S; cin >> length >> S; int removable_characters = 0; for(int i = 2; i < length; i++) removable_characters += (S[i] == 'x' && S[i - 1] == 'x' && S[i - 2] == 'x'); cout << removable_characters; return 0; } ================================================ FILE: Explanations/Explanations 21/Fox and Box Accumulation Explanation.txt ================================================ Let us make the observation - If p piles are possible, then it is possible to make p + 1 piles as well, if p + 1 <= N, We do this by simply taking the top of any one pile and making a new pile. If p piles are not possible, then even p - 1 piles are not possible. ------------------------------------- We are looking for a number P, such that P piles are possible but P - 1 piles are not ! We can do this by binary search ! ------------------------------------------ You have a number P, how do you check if P piles are possible ? Firstly, we shall choose the P boxes with the highest strength and then make a pile with each box as the first stone. We only keep track of the strength of the box on top of each pile. Now, we take each of the remaining boxes, starting from the one with the greatest strength and place it over the pile which has the highest strength box on top. The new top = min(top - 1, new box) We can place a new box on a pile as long as the strength of that pile's top > 0. If we have been able to place all the boxes, then the answer is Yes to P. Else the answer is No. --------------------------------------------- int main() { int no_of_cards; scanf("%d", &no_of_cards); vector card(no_of_cards); for(int i = 0; i < no_of_cards; i++) scanf("%d", &card[i]); if(no_of_cards == 1) { printf("-1\n"); return 0; } vector new_cards; if(no_of_cards == 2 && (card[0] != card[1]) && (card[0] + card[1])%2 == 0) { new_cards.push_back( (card[0] + card[1])/2 ); } sort(all(card)); int min_difference = card[1] - card[0]; for(int i = 2; i < no_of_cards; i++) min_difference = min(min_difference, card[i] - card[i - 1]); int ap_possible = true, new_middle_cards = 0; for(int i = 1; i < no_of_cards; i++) { if(card[i] - card[i - 1] != min_difference) { if(card[i] - card[i - 1] == 2*min_difference) { new_middle_cards++; } else { ap_possible = false; } } } if(ap_possible) { if(min_difference == 0) { new_cards.push_back(card[0]); } else if(new_middle_cards == 0) { new_cards.push_back(card[0] - min_difference); new_cards.push_back(card[no_of_cards - 1] + min_difference); } else if(new_middle_cards == 1) { for(int i = 1; i < no_of_cards; i++) if(card[i] - card[i - 1] == 2*min_difference) new_cards.push_back(card[i - 1] + min_difference); } } sort(all(new_cards)); printf("%d\n", new_cards.size()); for(int i = 0; i < new_cards.size(); i++) printf("%d ", new_cards[i]); return 0; } ================================================ FILE: Explanations/Explanations 21/Ghosts Explanation.txt ================================================ Unlike most problems, this problems specifically asks us to overcount rather than avoid it. Each collision must be counted two times - once for each ghost. Now, the equation for the motion of a ghost = P + VT, where V is velocity, T is time and P is position. We have two dimensions and the equations need to be applied seperately on both. Now the trick is in noticing that two ghosts will intersect if the time for their x coordinates to be equal is the same as the Y. X1 + Vx1T = X2 + Vx2T X1 - X2 = T(Vx2 - Vx1) T = (X1 - X2)/(Vx2 - Vx1) And Y1 + Vy1T = Y2 + Vy2T Y1 - Y2 = T(Vy2 - Vy1) T = (Y1 - Y2)/(Vy2 - Vy1) (X1 - X2)/(Vx2 - Vx1) = (Y1 - Y2)/(Vy2 - Vy1) (X1 - X2)/(Vx2 - Vx1) = (aX1 + b - aX2 - b)/(Vy2 - Vy1) (X1 - X2)/(Vx2 - Vx1) = a(X1 - X2)/(Vy2 - Vy1) 1/(Vx2 - Vx1) = a/(Vy2 - Vy1) Vy2 - Vy1 = aVx2 - aVx1 ------------------------------- aVx1 - Vy1 = aVx2 - Vy2 This shows that ghosts which have the same aVx - Vy intersect at some point. However, we need to notice that if two ghosts are parallel (V1 = V2) then they never meet. --------------------------------- Take each ghost. That ghost intersects with all ghosts who have aVx - Vy value, but not with those that have the same V. (Parallel) A very elegant way to keep track of slopes is to maintain a map of pairs. {Vx, Vy}. Maintain another map for {aVx - Vy} ------------------------------------------ Multiply the number of collisions by 2 at the end. ------------------------------------------------------ int main() { int no_of_points, a, b; scanf("%d %d %d", &no_of_points, &a, &b); long long total_collisions = 0; map < pair, int > slope_count; map intersections; for(int i = 1; i <= no_of_points; i++) { int x, vx, vy; scanf("%d %d %d", &x, &vx, &vy); total_collisions += intersections[a*1LL*vx - vy] - slope_count[make_pair(vx, vy)]; //Parallel points don't meet. slope_count[make_pair(vx, vy)]++; intersections[a*1LL*vx - vy]++; } total_collisions *= 2; printf("%I64d\n", total_collisions); return 0; } ================================================ FILE: Explanations/Explanations 21/Less or Equal Explanation.txt ================================================ Let us sort the array. The question is asking for any number in the range [A[k], A[k + 1] - 1] This is not possible when A[k] = A[k + 1] Otherwise, just output A[k] The special case is k = 0, when we must output a number smaller than all the elements of the array. If A[1] = 1, then we cannot output any number as we must output a number that is at least 1. Else, we simply output 1. ------------------------------------------------- int main() { int no_of_elements, position; scanf("%d %d", &no_of_elements, &position); vector A(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); sort(all(A)); int answer; if(position == 0) { answer = (A[1] > 1 ? 1 : -1); } else { answer = (position < no_of_elements && A[position] == A[position + 1] ? -1 : A[position]); } printf("%d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 21/Little Girl and Maximum XOR Explanation.txt ================================================ Let L = 000110011 R = 0001101111 Notice that there must be some position p, where R[p] = 1, and L[p] = 0 and for all i < p, R[p] = L[p] The key observation here is that all numbers in between [L, R] will all have the same value for all those bits before p. The XOR of any two numbers will give 0. It doesnt contribute anything. Now, the largest possible XOR we can get is a number with p 1s since all the bits before that will always be 0 in any pair we choose. Now, Ill prove its always possible to get a number with p 1s. Let A match the common prefix of L and R. A[p] = 0, and let all positions after this = 1 A is smaller than R for sure since R[p] = 1. It is >= L. It cant be smaller than L because it matches L till position P and from then has all 1s. Let B match the common prefix of L and R till p. B[p] = 1, and then all positions after that have 0. B is greater than L because B[p] = 1 > L[p] B is <= R because it matches R till position P and from there has all 0s. (A xor B) = a string of 1s. We dont even need to find out what the numbers are ! ---------------------------------------------------------------------------------- int main() { long long left, right; scanf("%I64d %I64d", &left, &right); if(left == right) { printf("0\n"); return 0; } int largest_unequal_bit_position; for(int i = 0; left > 0 || right > 0; i++) { if(left%2 != right%2) largest_unequal_bit_position = i; left >>= 1; right >>= 1; } long long answer = all_ones(largest_unequal_bit_position); //This gives a number consisting of n 1's in binary printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 21/Lucky Sum of Digits Explanation.txt ================================================ Now, whenever x is possible, x + 4 is also possible All numbers greater than 18 are possible since (18, 19, 20, 21) are all possible. Now, we want to minimise the number of summands, so we maximise the number of 7s. Let N = 4x + 7y We start with y = floor(n/7) and check if there exists an x. Print x 4s followed by y 7s for the answer. -------------------------------------------------------------------------------------------- int main() { int sum; scanf("%d", &sum); int possible = false; int no_of_4s = 0, no_of_7s = sum/7; while(no_of_7s >= 0) { if( (sum - 7*no_of_7s)%4 == 0) { no_of_4s = (sum - 7*no_of_7s)/4; possible = true; break; } no_of_7s--; } if(!possible) { printf("-1\n"); return 0; } for(int i = 1; i <= no_of_4s; i++) printf("4"); for(int i = 1; i <= no_of_7s; i++) printf("7"); return 0; } ================================================ FILE: Explanations/Explanations 21/Mahmoud and Ehab and Another Array Construction Test Explanation.txt ================================================ Blog Link - http://qr.ae/TUTAnY If all the elements are pairwise coprime, then it means that no prime number occurs in the prime factorisation of two numbers. Let us keep an array Used[] Used[x] = true, if prime factor x occurs in the factorisation of some A[i]. Used[x] = false, otherwise. Now, we go through each A[i], If all of A[i]'s prime factors are unused, then mark all of them and add A[i] to the solution. If we get an A[i], which has at least one used prime factor, Then, x = A[i], while(all_prime_factors_unused(x)) x++ And then insert x to the solution. Now, we have lexicographically larger B. From here, onwards, we must print the smallest numbers that are not used. These numbers must be prime. Let us suppose we have a composite numbe C. We can get a smaller number by replacing C with any of it's prime factors. So, here's the overall algorithm. 1. Push as many A[i] as possible. 2. If an A[i] is not possible, x = A[i] + 1, keep incrementing till x is possible. 3. After x, print the smallest unused primes. ----------------------------------------------------------------------------------------------- void sieve(vector &is_prime, int LIMIT) { is_prime[0] = is_prime[1] = false; for(long long i = 2; i*i <= LIMIT; i++) { if(is_prime[i]) { for(long long multiple = i*i; multiple <= LIMIT; multiple += i) { is_prime[multiple] = false; } } } } int all_prime_factors_available(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { if(used[p] == true) return false; n /= p; } } if(n > 1 && used[n]) return false; return true; } void mark_prime_factors(int n, vector &used) { for(int p = 2; p*p <= n; p++) { while(n%p == 0) { used[p] = true; n /= p; } } if(n > 1) used[n] = true; } int main() { const int LIMIT = 2e6; vector is_prime(LIMIT, true); sieve(is_prime, LIMIT); int no_of_elements; scanf("%d", &no_of_elements); vector original(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &original[i]); vector solution; vector used(LIMIT, false); for(int i = 0; i < no_of_elements; i++) { if(all_prime_factors_available(original[i], used)) { solution.push_back(original[i]); mark_prime_factors(original[i], used); } else { int x = original[i] + 1; while(!all_prime_factors_available(x, used)) x++; mark_prime_factors(x, used); solution.push_back(x); break; } } for(int i = 2; i < LIMIT && solution.size() < no_of_elements; i++) { if(!used[i] && is_prime[i]) solution.push_back(i); } for(int i = 0; i < no_of_elements; i++) printf("%d ", solution[i]); return 0; } ================================================ FILE: Explanations/Explanations 21/Mahmoud and Ehab and Even Odd Game Explanation.txt ================================================ If n is even, then Mahmoud takes n and wins. If n is odd, no matter what even number takes, he leaves an odd number for Ehab. Ehab then takes it and wins. ----------------------------------------------------- int main() { int n; scanf("%d", &n); printf(n%2 == 0 ? "Mahmoud\n" : "Ehab\n"); return 0; } ================================================ FILE: Explanations/Explanations 21/Mahmoud and a Triangle Explanation.txt ================================================ Let us sort the sides. S[1] < S[2] < ... < S[n] Let us try to make S[i] the largest side of the triangle and match S[i] with S[i - 1], S[i - 2] If we get a triangle, we are done. Else, S[i] >= S[i - 1] + S[i - 2] Replacing S[i - 1] or S[i - 2] by any other side will only give a smaller sum. So, this means there is no triangle with S[i] as the largest side. We need to do one O(n) scan after O(n log n) sorting to check if we can construct a triangle with each S[i] as the largest side. --------------------------------------------- Note - There is an important optimisation here. Let us try to construct the smallest sequence of numbers which don't allow a triangle formation. First two numbers = 1, 1 The third number must satisfy S[i] >= S[i - 1] + S[i - 2] We want the smallest possible S[i], So S[i] = S[i - 1] + S[i - 2] This gives us the Fibonacci numbers. They grow quite rapidly and there are only 45 of them till 10^9. This means that if there are more than 45 numbers, there must be some i in the series such that S[i] < Fibo[i] and for all j < i, S[j] >= Fibo[j] Fibo[i] = Fibo[i - 1] + Fibo[i - 2] <= S[i - 1] + S[i - 2] S[i] < Fibo[i] <= S[i - 1] + S[i - 2] S[i] < S[i - 1] + S[i - 2] ------------------------------------------------------------------------ If there are more than 45 numbers, the answer will always be yes ! Else, O(n log n + n). Actually O(n^3) naive solution is also possible among 45 numbers. int main() { int no_of_sides; cin >> no_of_sides; const int FIBO_LIMIT_MAX_SIDES = 45; if(no_of_sides > FIBO_LIMIT_MAX_SIDES) { cout << "YES\n"; return 0; } vector side(no_of_sides); for(int i = 0; i < no_of_sides; i++) cin >> side[i]; sort(all(side)); int triangle_possible = false; for(int i = no_of_sides - 1; i >= 2; i--) { if(side[i] < side[i - 1] + side[i - 2]) { triangle_possible = true; break; } } cout << (triangle_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 21/Make a Square Alternate Solution Explanation.txt ================================================ This is more brute force. Generate all squares less than N. Check if each square is a subsequence of N. Choose the square which preserves the maximum digits. It generalises less quickly than the bitmasks solution. --------------------------------------------------------------- int is_subsequence(int sequence, int n) { while(sequence > 0 && n > 0) { if(n%10 == sequence%10) { sequence /= 10; if(sequence == 0) return true; } n /= 10; } return false; } int main() { int n; scanf("%d", &n); int digit_count = no_of_digits(n), maximum_digits = 0; for(int i = 0; square(i) <= n; i++) { if(is_subsequence(square(i), n) && no_of_digits(square(i)) > maximum_digits) { maximum_digits = no_of_digits(square(i)); } } int deleted_digits = digit_count - maximum_digits; printf(deleted_digits == digit_count ? "-1\n" : "%d\n", deleted_digits); return 0; } ================================================ FILE: Explanations/Explanations 21/Make a Square Explanation.txt ================================================ Use bitmasks. The number will not have more than 10 digits. Have a bitmask of the same length as N. For every mask, choose only those digits of N in which position the bit is set in mask. Check if each mask is a square. And then check how many digits are deleted. Choose the square with the minimum deleted digits (or maximum preserved digits). I made a mistake here where leading 0s were included. Had to put in another condition to stop leading zeroes from being considered. There's another approach. You can simply generate all squares upto 10^9 (About 3x10^4). And check if each square is a subsequence of n. This approach generalises more easier. If n <= 10^18, we can't check all squares till 10^9, but we can still check all bitmasks till 2^18. ---------------------------------------------------------------- int main() { int n; scanf("%d", &n); int digit_count = no_of_digits(n), maximum_digits = 0; int digit[11]; for(int i = 0; i < digit_count; i++, n /= 10) digit[i] = n%10; for(int mask = (1 << digit_count) - 1; mask > 0; mask--) { int number = 0; for(int i = digit_count - 1; i >= 0; i--) { if(is_bit_set(mask, i)) number = number*10 + digit[i]; } if(is_square(number) && no_of_digits(number) > maximum_digits) maximum_digits = no_of_digits(number); } int deleted_digits = digit_count - maximum_digits; printf(deleted_digits == digit_count ? "-1\n" : "%d\n", deleted_digits); return 0; } ================================================ FILE: Explanations/Explanations 21/Mancala Explanation.txt ================================================ There are only 14 hold. The problem is small enough to simulate. Take each hole. Calculate the answer if this hole was redistributed. And keep track of the best hole. How to calculate the answer if a particular hole is distributed ? Well, let's say hole[i] has S stones. And let S = 14q + r, q is the quotient, r is the remainder, 0 <= r < 14 Now, first of all set hole[i] = 0. Then all 14 holes will get an additional q stones. Then simulate the process of distributing the left out r stones. (Start from (i + 1) and give one stone to all holes till you run out of stones.) After this do an O(n) scan to find out the hole with the maximum number of stones. This requires 3 O(n) scans. We do this for all 14 holes. So 42 O(n) scans. ------------------------------------------------------------ long long score_by_distributing(int chosen, vector stone, int no_of_holes) { int quotient = stone[chosen]/no_of_holes, remainder = stone[chosen]%no_of_holes; stone[chosen] = 0; int current = chosen; do { stone[current] += quotient; current = (current + 1)%no_of_holes; } while(current != chosen); current = (chosen + 1)%no_of_holes; while(remainder > 0) { stone[current]++; remainder--; current = (current + 1)%no_of_holes; } long long score = 0; for(int i = 0; i < stone.size(); i++) if(stone[i]%2 == 0) score += stone[i]; return score; } int main() { const int NO_OF_HOLES = 14; vector stone(NO_OF_HOLES); for(int i = 0; i < NO_OF_HOLES; i++) cin >> stone[i]; long long maximum_score = 0; for(int i = 0; i < NO_OF_HOLES; i++) maximum_score = max(maximum_score, score_by_distributing(i, stone, NO_OF_HOLES)); cout << maximum_score; return 0; } ================================================ FILE: Explanations/Explanations 21/Pairs of Lines Explanation.txt ================================================ Notice that if there are upto 4 points, an answer is always possible. Let us take the first 3 points. By the Pigeonhole principle, at least 2 of these points have to lie on the same line. (3 points, 2 lines) Let us say P1, P2 are on the same line. (We need to check all 3 cases.) Then go through all the remaining points, If point i, is not on the same line as P1, P2, then put Pi in a Vector L2. At the end check if all points on L2 lie on the same line. For checking if a list of points lie on the same line, all we have to do is check_on_line(P[0], P[1], P[i]), for all i in the list. ---------------------------------------------------------------------------------------------- struct Point{ long long x, y; }; int is_on_line(Point a, Point b, Point c) { //Checking slope product to avoid division return ( (c.y - b.y)*(b.x - a.x) == (b.y - a.y)*(c.x - b.x) ); } int check_line(vector &line) { for(int i = 2; i < line.size(); i++) if(!is_on_line(line[0], line[1], line[i])) return false; return true; } int check_one_line_passing_through(int a, int b, vector &P) { vector line_2; for(int i = 1; i < P.size(); i++) { if(!is_on_line(P[a], P[b], P[i])) line_2.push_back(P[i]); } int two_lines_possible = check_line(line_2); return two_lines_possible; } int main() { int no_of_points; scanf("%d", &no_of_points); vector P(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) scanf("%I64d %I64d", &P[i].x, &P[i].y); int two_lines_possible = (no_of_points <= 4 || check_one_line_passing_through(1, 2, P) || check_one_line_passing_through(2, 3, P) || check_one_line_passing_through(3, 1, P)); printf(two_lines_possible ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 21/Two Gram Explanation.txt ================================================ There are only (n - 1) two-grams. Keep track of the frequency of each two-gram. The most frequent two-gram is the answer. -------------------------------------------------- int main() { int length; string S; cin >> length >> S; map frequency; int max_frequency = 0; string answer; for(int i = 0; i + 1 < length; i++) { string two_gram = S.substr(i, 2); frequency[two_gram]++; if(frequency[two_gram] > max_frequency) max_frequency = frequency[two_gram], answer = two_gram; } cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 21/Valhalla Siege Explanation.txt ================================================ To kill i soldiers, we need to shoot S[1] + S[2] + ... + S[i] arrows. Maintain a prefix sum array. Keep track of the total number of arrows shot so far. If total_arrows >= S[n], then total_arrows = 0 After that use binary search and find the smallest position i, such that total_arrows < S[i]. (i - 1) soldiers would have been dead at that time and the remaining N - i are alive. ----------------------------------------------------------- int main() { int no_of_soldiers, no_of_queries; scanf("%d %d", &no_of_soldiers, &no_of_queries); vector strength(no_of_soldiers + 1); for(int i = 1; i <= no_of_soldiers; i++) scanf("%I64d", &strength[i]); vector sum(no_of_soldiers + 1, 0); for(int i = 1; i <= no_of_soldiers; i++) sum[i] = sum[i - 1] + strength[i]; long long total_arrows = 0; while(no_of_queries--) { long long arrows; scanf("%I64d", &arrows); total_arrows += arrows; if(total_arrows >= sum[no_of_soldiers]) total_arrows = 0; int no_of_dead_soldiers = upper_bound(all(sum), total_arrows) - sum.begin() - 1; int no_of_alive_soldiers = no_of_soldiers - no_of_dead_soldiers; printf("%d\n", no_of_alive_soldiers); } return 0; } ================================================ FILE: Explanations/Explanations 21/Wrong Subtraction Explanation.txt ================================================ The process is simple enough to simulate. ---------------------------------- #include int main() { int n, no_of_operations; scanf("%d %d", &n, &no_of_operations); while(no_of_operations--) { n = (n%10 == 0 ? n/10 : n - 1); } printf("%d\n", n); return 0; } ================================================ FILE: Explanations/Explanations 22/AND Graph Explanation.txt ================================================ Blog Link - http://qr.ae/TUT6oy Basically,X&Y = 0, if Y is any submask of X's complement. So perform DFS. Start from X From X visit all of the submasks of the complement of Y. Mark N visited if you have visited all of it's submasks. If any of the submasks are also present in the array, then visit all the submasks of it's complement as well ! Do this recursively till all integers which can be reached starting from X (in the same component). ------------------------------------------ void dfs(int mask, int no_of_bits) { if(visited[mask]) return; visited[mask] = true; for(int bit = 0; bit < no_of_bits; bit++) { if(mask&(1LL << bit)) { int submask = mask - (1LL << bit); dfs(submask, no_of_bits); } } if(is_present[mask]) dfs(complement(mask, no_of_bits), no_of_bits); } int main() { int no_of_bits, no_of_vertices; scanf("%d %d", &no_of_bits, &no_of_vertices); for(int i = 1; i <= no_of_vertices; i++) { int x; scanf("%d", &x); is_present[x] = true; } int no_of_components = 0; for(int i = 0; i < (1LL << no_of_bits); i++) { if(is_present[i] && !visited[i]) { dfs(complement(i, no_of_bits), no_of_bits); no_of_components++; } } printf("%d\n", no_of_components); return 0; } ================================================ FILE: Explanations/Explanations 22/Almost Arithmetic Progression Explanation.txt ================================================ Any AP is uniquely determined by it's first two elements. Let us check all possible first two elements A[0] +/- 1 A[1] +/- 1 For each of the 9 possible first two terms, check if an AP with that difference is possible with only adding or subtracting one to each element. If it's possible, then |term1 + k*d - A[k]| <= 1 If it is greater then it is not possible. If |term1 + k*d - A[k]| = 1, no of operations++ Keep track of the total no of operations and minimum total in all 9 configurations. In my program, if it's not possible, I set the number of operations to oo. -------------------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements); for(int i = 0; i < no_of_elements; i++) scanf("%d", &A[i]); const int oo = 1e7; int add[3] = {-1, 0, 1}, min_operations = oo; for(int i = 0; i < 3; i++) { int term_1 = A[0] + add[i]; for(int j = 0; j < 3; j++) { int term_2 = A[1] + add[j]; int difference = term_2 - term_1; int no_of_operations = (term_1 != A[0]) + (term_2 != A[1]); for(int k = 2; k < no_of_elements; k++) { if(abs(term_1 + k*difference - A[k]) == 1) { no_of_operations++; } else if(abs(term_1 + k*difference - A[k]) > 1) { no_of_operations = oo; } } min_operations = min(min_operations, no_of_operations); } } printf("%d\n", min_operations >= oo ? -1 : min_operations); return 0; } ================================================ FILE: Explanations/Explanations 22/Antipalindrome Alternate Solution Explanation.txt ================================================ The constraints are small enough to allow for an O(n^3) solution where all substrings are checked but there's an elegant O(n) solution ! Case 1: S is not a palindrome, then answer = n. Case 2: S is a palindrome. then we check S[1, ... , n - 1] and S[2, ... n] If either of these strings are not a palindrome, then the answer = n - 1 Case 3: S, S[1, ... , n - 1] and S[2, ... , n] are all palindromes. In that case, Notice S[1] = S[n], from 1 S[2] = S[n], from 3 Also, S[2] = S[n - 1], from 1 And S[1] = S[n - 1], from 2 So, this implies S[1] = S[2] = S[n - 1] = S[n - 2] Similarly, we see from 1, that S[i] = S[n - i] And S[i] = S[n - 1 - i] So, S[n - i] = S[n - 1 - i] We continually apply the above inequality to show that all characters are the same. If that's the case, then ANY substring will be a palindrome. -------------------------------- Therefore, the answer is either n, n - 1 or 0. ----------------------------------------------- int main() { string S; cin >> S; int length = S.size(); if(!is_palindrome(S, 0, length - 1)) cout << length; else if(!is_palindrome(S, 0, length - 2) || !is_palindrome(S, 1, length - 1)) cout << length - 1; else cout << "0"; return 0; } ================================================ FILE: Explanations/Explanations 22/Antipalindrome Explanation.txt ================================================ N is very small. Check all choose(N, 2) substrings if they're palindromes, starting from the longest substrings. This is O(N^3). --------------------------------------- int is_palindrome(string S) { for(int i = 0; i < S.size(); i++) if(S[i] != S[S.size() - 1 - i]) return false; return true; } int main() { string S; cin >> S; for(int length = S.size(); length >= 1; length--) { for(int i = 0; i + length - 1 < S.size(); i++) { if(!is_palindrome(S.substr(i, length))) { cout << length; return 0; } } } cout << "0"; return 0; } ================================================ FILE: Explanations/Explanations 22/Ball Explanation.txt ================================================ Blog Link - http://qr.ae/TUpFlU You have N triplets (A, B, C). Sort the triplets by A. Maintain an array S, where the index is B and the value is C. Initially C is empty. Process triplets in descending order of A. Check if max{S[B[i] + 1, B[i] + 2, ... , N]} > C_i, If yes, then we have found a triplet j such that A_j > A_i, because it was processed first. B_j > B_i, because we have queried in the range > B_i C_j > C_i, as we have just found out ! We compress the coordinates of B and maintain a segment tree over S. Otherwise, it once again degrades to O(n^2). But, with our beautiful segment tree, it's now O(n log n). ------------------------------------------------ int main() { int no_of_ladies; scanf("%d", &no_of_ladies); vector lady(no_of_ladies + 1); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].beauty); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].richness); for(int i = 1; i <= no_of_ladies; i++) scanf("%d", &lady[i].intellect); sort(all(lady), sort_by_beauty); vector intelligence(no_of_ladies + 1, 0); for(int i = 1; i <= no_of_ladies; i++) intelligence[i] = lady[i].intellect; sort(all(intelligence)); map iq_rank; for(int i = 1; i <= no_of_ladies; i++) { iq_rank[intelligence[i]] = (intelligence[i] == intelligence[i - 1] ? iq_rank[intelligence[i - 1]] : i); } memset(max_tree, 0, sizeof(max_tree)); int suicides = 0; for(int i = no_of_ladies; i >= 1; ) { int j; for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { int max_richness_with_other_2_greater = get_max_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect] + 1, no_of_ladies); if(max_richness_with_other_2_greater > lady[j].richness) suicides++; } for(j = i; j >= 1 && lady[j].beauty == lady[i].beauty; j--) { insert_richness(1, 1, no_of_ladies, iq_rank[lady[j].intellect], lady[j].richness); } i = j; } printf("%d", suicides); return 0; } ================================================ FILE: Explanations/Explanations 22/Bits Explanation.txt ================================================ Blog Link - The basic idea is that if L and R have different number of digits, than the answer consists of no_of_bits(R) - 1 ones. If R is a string of all ones, then the answer is R. If L and R have the same number of digits, then search for the first bit i, where L[i] = 0 and R[i] = 1, A will have the same prefix upto (i + 1). Then if R is a string of all ones from I till 0, then A[i] = A[i - 1] = ... = A[0] = 1, in other words A = R Else, A[i] = 0, and then A[i - 1] = A[i - 2] = ... = A[0] = 1 --------------------------- void solve() { long long left, right; scanf("%I64d %I64d", &left, &right); long long answer = 0; if(all_ones(no_of_bits(right)) == right) { answer = right; } else if(no_of_bits(left) != no_of_bits(right)) { answer = all_ones(no_of_bits(right) - 1); } else if(no_of_bits(left) == no_of_bits(right)) { for(int bit = 63; bit >= 0; bit--) { if(is_set(left, bit) && is_set(right, bit)) { answer |= (1LL << bit); } else if(!is_set(left, bit) && is_set(right, bit)) //If L[i] = 0, and R[i] = 1 { answer |= all_ones(bit); //Setting the current bit to 0, and then padding with 1s till the end. if((answer|(1LL << bit)) <= right) //Checking if the current bit can also be 1 answer |= (1LL << bit); } } } printf("%I64d\n", answer); } ================================================ FILE: Explanations/Explanations 22/Bookshelves Explanation.txt ================================================ Blog Link - http://qr.ae/TUTmQ6 Let us answer, a related question. If given a number x, how do we determine if it is possible to divide the numbers into K segments such that the bitwise AND of the sum of the K segments = x ? Each segment[L, R] has to obey the following property - (Sum[R] - Sum[L - 1])&x = x, i.e. all the bits that are set in x, must be set in the sum from [L, ... , R] for each of the K segments ! We can check this with dynamic programming. Let f(n, k) = true, if it is possible for the bitwise-AND of the sums of the first K segments = x, with the last segment ending on n. And f(n, k) = false, otherwise. f(R, K) = true, if there exists some L < R, such that Sum[L ... R]&x = x and f(L - 1, K - 1) = true. It takes us O(N^2 K) time to answer one such question. Now, let us be greedy and start from i = 60, and check if answer + 2^i is possible, if it is then the answer = answer + 2^i. This is always optimal. Overall Complexity = O(log(max{A}) N^2 K) ----------------------------------------------- int is_possible(LL goal) { memset(possible, false, sizeof(possible)); possible[0][0] = true; for(int part = 1; part <= no_of_parts; part++) { for(int right = 1; right <= no_of_elements; right++) { for(int left = 0; left < right; left++) { if( possible[left][part - 1] && ( ( (sum[right] - sum[left])&goal ) == goal ) ) { possible[right][part] = true; break; } } } } return possible[no_of_elements][no_of_parts]; } int main() { scanf("%d %d", &no_of_elements, &no_of_parts); for(int i = 1; i <= no_of_elements; i++) scanf("%I64d", &A[i]); sum[0] = 0; for(int i = 1; i <= no_of_elements; i++) sum[i] = sum[i - 1] + A[i]; LL answer = 0; for(int bit = MAX_BIT; bit >= 0; bit--) { if(is_possible(answer|(1LL << bit))) { answer |= (1LL << bit); } } printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 22/Businessman Problems Explanation.txt ================================================ For every item x, we add max{A_cost[x], B_cost[x]} If x does not exist in either A or B, then it is 0. We can use maps to do this ! While reading A_cost, just read in cost[x]. While reading B_cost, then cost[x] = max{cost[x], cost} ------------------------------------------------- int main() { int a_elements; scanf("%d", &a_elements); map cost; for(int i = 1; i <= a_elements; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = cost_i; } int b_elements; scanf("%d", &b_elements); for(int i = 1; i <= b_elements; i++) { int element_i, cost_i; scanf("%d %d", &element_i, &cost_i); cost[element_i] = max(cost[element_i], cost_i); } long long total_cost = 0; for(map :: iterator it = cost.begin(); it != cost.end(); it++) { total_cost += it->second; } printf("%I64d\n", total_cost); return 0; } ================================================ FILE: Explanations/Explanations 22/Chess Placing Explanation.txt ================================================ There are only two possibilities. At the end, either all the squares are on black squares or they're all on white squares. Calculate the number of moves if all pieces are on black squares, and if all the pieces are on white squares and the answer is the minimum of these two. To calculate the minimum number of moves to put all pieces on squares of the same colour, it is always best to put on square i, the piece closest to it. So Ans = |P[i] - 2i|, to put all pieces on even squares. Of course, the pieces must be sorted before this. The proof is that if P[i] is the closest to 2i, if we replace P[i] by any piece > P[i], then we increase the number of moves. ----------------------------------- int main() { int n; cin >> n; vector A(n/2 + 1); for(int i = 1; 2*i <= n; i++) cin >> A[i]; sort(all(A)); int black_moves = 0; for(int i = 1; 2*i <= n; i++) black_moves += abs(A[i] - (2*i - 1)); int white_moves = 0; for(int i = 1; 2*i <= n; i++) white_moves += abs(A[i] - 2*i); int minimum_moves = min(black_moves, white_moves); cout << minimum_moves; return 0; } ================================================ FILE: Explanations/Explanations 22/Correct Solution Explanation.txt ================================================ If you are given N, the answer is all the digits of N in ascending order. If N[0] = 0, then swap it with the first non zero number. (There's always a non zero digit, if the number of digits > 1 as there is no number consisting of multiple zeroes. However, a single 0 is a special case. Be careful. If it's only 0, then there's no non zero digit to replace it with.) Compare the answer with B. -------------------------------------------------------------- string solve(string S) { vector digits; for(int i = 0; i < S.size(); i++) digits.push_back(S[i]); sort(all(digits)); if(digits[0] == '0') { int first_nonzero = 1; while(first_nonzero < digits.size() && digits[first_nonzero] == '0') first_nonzero++; swap(digits[0], digits[first_nonzero]); } string answer; for(int i = 0; i < digits.size(); i++) answer += digits[i]; return answer; } int main() { string A, B; cin >> A >> B; string answer = solve(A); cout << ((answer == B) ? "OK\n" : "WRONG_ANSWER\n"); return 0; } ================================================ FILE: Explanations/Explanations 22/Couting Kangaroos is Fun Explanation.txt ================================================ At most N/2 kangaroos can hold a kangaroo. So, it is always optimal for the lighter kangaroos to be held by the heavier kangaroos. This is exactly what we do. Divide into two sets of size N/2. And then greedily try to match them. ----------------------------------------------- int main() { int no_of_kangaroos; scanf("%d", &no_of_kangaroos); vector kangaroo_size(no_of_kangaroos); for(int i = 0; i < no_of_kangaroos; i++) scanf("%d", &kangaroo_size[i]); sort(all(kangaroo_size)); int no_of_pairs = 0; int front_i = 0, back_i = no_of_kangaroos/2; for( ; front_i < no_of_kangaroos/2 && back_i < no_of_kangaroos; front_i++) { while(back_i < no_of_kangaroos) { if(kangaroo_size[front_i]*2 <= kangaroo_size[back_i]) { back_i++; no_of_pairs++; break; } else { back_i++; } } } int no_of_visible_kangaroos = no_of_pairs + (no_of_kangaroos - 2*no_of_pairs); printf("%d\n", no_of_visible_kangaroos); return 0; } ================================================ FILE: Explanations/Explanations 22/Fruits Explanation.txt ================================================ Keep track of the frequency of each fruit. To minimise prices, the most frequent fruits, get the lowest prices. To maximise prices, the most frequent fruits get the highest prices. ------------------------------ sort(all(fruit_frequency)); reverse(all(fruit_frequency)); long long min_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) min_price += price[i]*1LL*fruit_frequency[i]; reverse(all(price)); long long max_price = 0; for(int i = 0; i < fruit_frequency.size(); i++) max_price += price[i]*1LL*fruit_frequency[i]; ================================================ FILE: Explanations/Explanations 22/High Schooll Become Human Explanation.txt ================================================ Blog Link - http://qr.ae/TUTQHH You can either compare the logarithms. Or, if x^y > y^x, then y log x > x log y (log x)/x > (log y)/y Now, (log x)/x has a derivative of (1 - log x)/x^2 The derivative = 0, at x = e Derivative < 0, x > e, which means it is a monotonically decreasing function when x > e If x, y > e And x < y Then, (log x)/x > (log y)/y x^y > y^x ---------------------- Also, x^y = y^x, whenever x = y, and x = 2, y = 4 The remaining cases can be handled by hand. ------------------------------------------------------ int main() { long long x, y; scanf("%I64d %I64d", &x, &y); if(x == y || (min(x, y) == 2 && max(x, y) == 4)) { printf("="); } else if(min(x, y) == 1) { printf(x == 1 ? "<" : ">"); } else if(min(x, y) == 2) { if(x == 2) { printf(y < 4 ? "<" : ">"); } else if(y == 2) { printf(x < 4? ">" : "<"); } } else if(min(x, y) >= 3) //Both greater than e { printf(x < y ? ">" : "<"); } return 0; } ================================================ FILE: Explanations/Explanations 22/Infinity Gauntlet Explanation.txt ================================================ Have a map of all the colours and their powers. And then have a map of which colours have been used. If a colour has not been used, then display it. ------------------------------------- int main() { map power; power["red"] = "Reality"; power["purple"] = "Power"; power["green"] = "Time"; power["yellow"] = "Mind"; power["orange"] = "Soul"; power["blue"] = "Space"; map present; int no_of_names; cin >> no_of_names; while(no_of_names--) { string colour; cin >> colour; present[colour] = true; } vector answer; for(map :: iterator it = power.begin(); it != power.end(); it++) { if(!present[it->first]) answer.push_back(it->second); } cout << answer.size() << "\n"; for(int i = 0; i < answer.size(); i++) cout << answer[i] << "\n"; return 0; } ================================================ FILE: Explanations/Explanations 22/Knights of a Polygonal Table Explanation.txt ================================================ Sort the knights, first by their power. And then maintain a priority queue of the k highest coins so far. k is at most 10. So, this works. As each knight can only kill knights that are less powerful than him, we insert coins into the priority queue only AFTER processing all knights of the same power. So when we're at knight i, we have processed all knights that have less than power of this knight i. All of the coins of the first (i - 1) are in a priority queue. This allows us to get the maximum in O(1) time. ----------------------------------------- int main() { int no_of_knights, max_coins; scanf("%d %d", &no_of_knights, &max_coins); vector knights(no_of_knights + 1); for(int i = 1; i <= no_of_knights; i++) knights[i].position = i; for(int i = 1; i <= no_of_knights; i++) scanf("%d", &knights[i].power); for(int i = 1; i <= no_of_knights; i++) scanf("%d", &knights[i].coin); sort(all(knights), sort_by_power); vector answer(no_of_knights + 1, 0); multiset best_coin; for(int i = 1; i <= no_of_knights; i++) { if(knights[i].power == knights[i - 1].power) { answer[knights[i].position] = answer[knights[i - 1].position] - knights[i - 1].coin + knights[i].coin; } else { int c = 1; answer[knights[i].position] = knights[i].coin; for(multiset :: reverse_iterator it = best_coin.rbegin(); it != best_coin.rend() && c <= max_coins; it++, c++) { answer[knights[i].position] += *it; } } best_coin.insert(knights[i].coin); } for(int i = 1; i <= no_of_knights; i++) printf("%I64d ", answer[i]); return 0; } ================================================ FILE: Explanations/Explanations 22/Letters Explanation.txt ================================================ Maintain a prefix sum array of the array. Then do binary search to find the first i, such that S[i] >= x and S[i - 1] < x i is the dorm no And x - S[i - 1] is the room no I used upper bound here quite clearly. upper bound(x) returns the first element which is GREATER than x. So upper bound(x - 1) does the trick quite nicely ! ----------------------------------------------- int main() { int no_of_elements, no_of_queries; scanf("%d %d", &no_of_elements, &no_of_queries); vector A(no_of_elements + 1); vector sum_till(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) { scanf("%I64d", &A[i]); sum_till[i] = sum_till[i - 1] + A[i]; } while(no_of_queries--) { long long x; scanf("%I64d", &x); int dorm_no = upper_bound(all(sum_till), x - 1) - sum_till.begin(); long long room_no = x - sum_till[dorm_no - 1]; printf("%d %I64d\n", dorm_no, room_no); } return 0; } ================================================ FILE: Explanations/Explanations 22/Local Extrema Explanation.txt ================================================ Go from 2 to N - 1 and check in O(n). int is_extrema(int mid, int start, int end) { return ((start < mid && end < mid) || (mid < start && mid < end)); } int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); int local_extrema = 0; for(int i = 2; i < no_of_elements; i++) local_extrema += is_extrema(A[i], A[i - 1], A[i + 1]); printf("%d\n", local_extrema); return 0; } ================================================ FILE: Explanations/Explanations 22/Remove Duplicates Explanation.txt ================================================ Read the integers right to left and keep track of what has been used so far. Put that into the solution and then print the solution in reverse. ---------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); const int MAX = 1015; vector used(MAX, false); vector ans; for(int i = no_of_elements; i >= 1; i--) { if(!used[A[i]]) { used[A[i]] = true; ans.push_back(A[i]); } } reverse(all(ans)); printf("%d\n", ans.size()); for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]); return 0; } ================================================ FILE: Explanations/Explanations 22/Super Agent Explanation.txt ================================================ There are only 9 points and 4 pairs. Check all of them. int main() { const int N = 3; char grid[N + 2][N + 2]; for(int i = 1; i <= N; i++) scanf("%s", grid[i] + 1); int symmetric = (grid[1][1] == grid[3][3]) && (grid[1][2] == grid[3][2]) && (grid[1][3] == grid[3][1]) && (grid[2][3] == grid[2][1]); printf(symmetric ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 22/Switches and Lamps Explanation.txt ================================================ Count the number of switches that each lamp is connected to. (In other words, find the sum of each column.) The go through all switches and check if there is any switch that can be ignored. A switch can be ignored, if each of it's connected lamp has another switch connected to it. i.e. If Switch[i][j] = 1, and lamp[j] > 1, then the i-th switch can be ignored. ---------------------------------------------------- int main() { int no_of_switches, no_of_lamps; cin >> no_of_switches >> no_of_lamps; vector switches(no_of_switches); for(int i = 0; i < no_of_switches; i++) cin >> switches[i]; vector no_of_switches_for(no_of_lamps, 0); for(int i = 0; i < no_of_switches; i++) for(int lamp = 0; lamp < no_of_lamps; lamp++) no_of_switches_for[lamp] += (switches[i][lamp] == '1'); int one_ignorable = false; for(int i = 0; i < no_of_switches; i++) { int can_ignore_this_one = true; for(int lamp = 0; lamp < no_of_lamps; lamp++) { if(switches[i][lamp] == '1' && no_of_switches_for[lamp] == 1) can_ignore_this_one = false; } if(can_ignore_this_one) one_ignorable = true; } cout << (one_ignorable ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 22/Three Displays Explanation.txt ================================================ This is the O(n^2) solution. Iterate over all possible middle elements. If A[i] is the middle element, then go from (i + 1) to N. Check if S[r] > A[i], if yes then best right[i] = min{best right[i], C[r]} Do the same thing towards the left as well. Best cost = min{Best cost, best left[i] + A[i] + best right[i]} We perform an O(n) scan for every possible mid element. Hence, O(n^2) ---------------------------------------------------- int main() { int no_of_displays; scanf("%d", &no_of_displays); vector text_size(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &text_size[i]); vector cost(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &cost[i]); const long long oo = 1e10; vector best_left(no_of_displays + 1, oo); vector best_right(no_of_displays + 1, oo); long long best_cost = oo; for(int mid = 1; mid <= no_of_displays; mid++) { for(int right = mid + 1; right <= no_of_displays; right++) { if(text_size[mid] < text_size[right]) best_right[mid] = min(best_right[mid], cost[right]); } for(int left = 1; left < mid; left++) { if(text_size[left] < text_size[mid]) best_left[mid] = min(best_left[mid], cost[left]); } best_cost = min(best_cost, best_right[mid] + cost[mid] + best_left[mid]); } printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: Explanations/Explanations 22/Three Displays Segment Tree Solution Explanation.txt ================================================ This is actually a beautiful technique. There are plenty of problems where segment trees can make O(n^2) to O(n log n). Here's what we do. While processing element i, ensure that we have already processed all elements which have a smaller font size. Now find the minimum cost in the range [1, Position(i) - 1]. (To avoid a clash, ensure that you have not processed elements which have equal font size but who's positions lie to the left of Position(i) because we should not be considering their cost.) So, we sort by font size, If font size is equal, then the rightmost element comes first. One by one, we insert the costs into segment tree at Position(i). And then query the minimum in [1, Position(i) - 1]. As we have ensured rightmost element comes first for equal font sizes, elements with equal font size to the left of an element will not effect it's query as it's not been inserted yet. While finding the best right, we do the opposite. We insert elements in the reverse order that we did for the left and then find the minimum in the range [Position(i) + 1, N]. --------------------------------------------- int main() { int no_of_displays; scanf("%d", &no_of_displays); vector A(no_of_displays + 1); for(int i = 1; i <= no_of_displays; i++) A[i].position = i; for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].font_size); for(int i = 1; i <= no_of_displays; i++) scanf("%d", &A[i].cost); sort(A.begin() + 1, A.end(), compare_by_size); build_min_tree(1, 1, no_of_displays); vector best_left(no_of_displays + 1, oo); for(int i = 1; i <= no_of_displays; i++) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_left[i] = get_min(1, 1, no_of_displays, 1, A[i].position - 1); } build_min_tree(1, 1, no_of_displays); vector best_right(no_of_displays + 1, oo); for(int i = no_of_displays; i >= 1; i--) { update_min(1, 1, no_of_displays, A[i].position, A[i].cost); best_right[i] = get_min(1, 1, no_of_displays, A[i].position + 1, no_of_displays); } long long best_cost = oo; for(int i = 1; i <= no_of_displays; i++) best_cost = min(best_cost, best_left[i] + A[i].cost + best_right[i]); printf(best_cost >= oo ? "-1\n" : "%I64d\n", best_cost); return 0; } ================================================ FILE: Explanations/Explanations 22/Tufurama Explanation.txt ================================================ Blog Link - http://qr.ae/TUpORd Maintain an array S of 1s and 0s. We want the number of pairs such that i < j, A[i] >= j and A[j] >= i For each i, sum over S in [i + 1, A[i]] After step i, delete all occurences of i in the array and set S[p] = 0, if A[p] = i This ensures that at step i, all elements < i are deleted so only >= i are present. ----------------------------------------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); vector index[no_of_elements + 1]; memset(sum_tree, 0, sizeof(sum_tree)); for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); A[i] = min(A[i], no_of_elements); update(1, 1, no_of_elements, i, 1); index[A[i]].push_back(i); } long long answer = 0; for(int i = 1; i <= no_of_elements; i++) { answer += get_sum(1, 1, no_of_elements, i + 1, A[i]); for(int j = 0; j < index[i].size(); j++) { update(1, 1, no_of_elements, index[i][j], 0); } } printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 22/Useful Decomposition Explanation.txt ================================================ We root the tree at a vertex V, and we make a path from V to each of it's leaves. We can always decompose a tree, unless V has some descendant that has more than one child. So, here's what we do 1. If the graph has more than one vertex which has 3 or more edges, then it is not possible. 2. If the graph has exactly one vertex which has 3 or more edges, then we root the tree at that vertex. If the graph has no such vertex, then it means every vertex has at most two edges (one parent and one child). We can arbitrarily root the graph at any of these vertices, then. Once we have a root, then make a path from the root the leaf vertex by going through each of the root's children. Note - You don't need to minimise the number of paths. Otherwise, the root is the vertex which has degree > 2, or the vertex with degree = 1, if all vertices have degree <= 2 Let us suppose we were asked to minimise or maximise the number of paths. Call a vertex a root if it's degree > 2. Case 1 : There is atleast one vertex with degree > 2 If there is more than one root, then the solution stays the same as a decomposition is not possible. If there was exactly one root, then we have to make it the root and the solution stays the same. Making any other vertex the root will not satisfy the given conditions. Case 2 : All vertices have degree <= 2 To minimise the number of paths, we must choose a leaf vertex since it has only one child and it will result in 1 simple path from one leaf to another. For maximising the number of paths, we will have to pick any non-leaf vertex which has a degree of 2. There will be two paths, one to each leaf. ---------------------------------------- int dfs_leaf_from(int v, int parent) { if(graph[v].size() == 1) return v; for(int i = 0; i < graph[v].size(); i++) { int child = graph[v][i]; if(child == parent) continue; return dfs_leaf_from(child, v); } } int main() { int no_of_vertices; scanf("%d", &no_of_vertices); for(int i = 1; i < no_of_vertices; i++) { int u, v; scanf("%d %d", &u, &v); graph[u].push_back(v); graph[v].push_back(u); } int no_of_roots = 0, root = 1; for(int i = 1; i <= no_of_vertices; i++) { if(graph[i].size() > 2) { no_of_roots++; root = i; } } if(no_of_roots > 1) { printf("No\n"); return 0; } printf("Yes\n"); int no_of_paths = graph[root].size(); printf("%d\n", no_of_paths); for(int i = 0; i < graph[root].size(); i++) { int child = graph[root][i]; int leaf = dfs_leaf_from(child, root); printf("%d %d\n", root, leaf); } return 0; } ================================================ FILE: Explanations/Explanations 23/An Impassioned Circulation of Affection Explanation.txt ================================================ We compute the answer for every range. For every range [L, R], we find the answer for every alphabet. We can do this because there are only 26 alphabets. Another thing to take care for is that f(c, r) = max{f(c, r), f(c, r - 1)} where f(c, r) is the length of the maximum substring of 'c' with at most r replacements. --------------- int main() { int length; string S; cin >> length >> S; for(int ch = 0; ch < MAX_ALPHABETS; ch++) { for(int left = 0; left < length; left++) { int replacements = 0; for(int right = left; right < length; right++) { replacements += (S[right] != 'a' + ch); maximum_segment[ch][replacements] = max(maximum_segment[ch][replacements], right - left + 1); } } } for(int ch = 0; ch < MAX_ALPHABETS; ch++) { for(int replacements = 1; replacements <= length; replacements++) { maximum_segment[ch][replacements] = max(maximum_segment[ch][replacements], maximum_segment[ch][replacements - 1]); } } int no_of_queries; cin >> no_of_queries; while(no_of_queries--) { int max_replacements; char character; cin >> max_replacements >> character; cout << maximum_segment[character - 'a'][max_replacements] << '\n'; } return 0; } ================================================ FILE: Explanations/Explanations 23/Another Problem on Strings Explanation.txt ================================================ Let us consider the range S[L, ... , R]. The sum is Sum[R] - Sum[L - 1] Now for a given R, how many L's exist such that Sum[R] - Sum[L - 1] = k ? It is equal to the number of Ls such that Sum[L - 1] = Sum[R] - k Let us maintain the frequency of all sums. Then at each i, add Sum_frequency[Sum[i] - k] to the answer. ----------------- int main() { int target_no_of_1s; scanf("%d", &target_no_of_1s); const int MAX = 1e6 + 3; char S[MAX]; scanf("%s", S); vector sum(MAX, 0); sum[0] = (S[0] == '1'); for(int i = 1; S[i] != '\0'; i++) sum[i] = sum[i - 1] + (S[i] == '1'); vector sum_frequency(MAX, 0); sum_frequency[0] = 1; //Empty string long long no_of_good_substrings = 0; for(int i = 0; S[i] != '\0'; i++) { if(sum[i] >= target_no_of_1s) no_of_good_substrings += (sum_frequency[sum[i] - target_no_of_1s]); sum_frequency[sum[i]]++; } printf("%I64d\n", no_of_good_substrings); return 0; } ================================================ FILE: Explanations/Explanations 23/Babaei and Birthday Cake Explanation.txt ================================================ Blog Link - http://qr.ae/TUGuqG Let us do this ... Firstly, calculate the volumes of all the cylinders. Let the volumes be v_1, v_2, ... , v_n for(int i = 1; i <= no_of_cylinders; i++) { int radius, height; scanf("%d %d", &radius, &height); const double PI = 3.14159; volume[i] = (PI*radius*radius*1LL*height); sorted_volume[i] = volume[i]; } ----------------------------- Let us sort the volumes and give each volume a rank indicating it's position in the sorted list. sort(all(sorted_volume)); map rank; for(int i = 1; i <= no_of_cylinders; i++) rank[sorted_volume[i]] = i; --------------------------- Now, let f(i) represent the maximum volume possible if the last cylinder used was the one with RANK i. Then what is the recurrence for i ? f(i) = V(i) + max{f(j)} where 1. j < i 2. V(j) < V(i) In other words, 1. j < i 2. Rank(V(j)) < Rank(V(i)) How do we find out this j ? We can obviously do so in O(n^2) time. But, that will not fit in the time limit and there is a more insightful way of doing it ! Let us maintain a maximum segment tree over an array Z. 1. Process the volumes in the order that it is given. 2. After processing, insert f(i) into Z at the position Rank(V(i)). Z[Rank(V(i))] = f(i) We will add f(i) = V(i) + max{Z[1, ... , Rank[V(i)] - 1]} We know that this is the j we want because 1. j < i because we have processed V(j) already and inserted it into Z. 2. Rank(V(j)) < Rank(V(i)) because we are only searching in that range. 3. Among all such j which satsifies both conditions, we have chosen the one that maximises f(i). map answer_with_last; for(int i = 1; i <= no_of_cylinders; i++) { answer_with_last[volume[i]] = volume[i] + get_max(1, 1, no_of_cylinders, 1, rank[volume[i]] - 1); insert(1, 1, no_of_cylinders, answer_with_last[volume[i]], rank[volume[i]]); } -------------------------- Now, the answer is the maximum value of f(i) in the array. double answer = 0; for(int i = 1; i <= no_of_cylinders; i++) answer = max(answer, answer_with_last[volume[i]]); ================================================ FILE: Explanations/Explanations 23/Bear and Prime Numbers Explanation.txt ================================================ The numbers are only until 10^7. For each prime till 10^7, keep track of it's number of multiples. Don't do this by factorising each integer. Rather go over all it's multiples frequencies. Similar to sieving. vector no_of_multiples(MAX_N + 1, 0); for(int i = 1; i <= MAX_N; i++) { if(!is_prime[i]) continue; for(int multiple = i; multiple <= MAX_N; multiple += i) { no_of_multiples[i] += frequency[multiple]; } } ----------------------------- Now build a prefix sum for this. Answer queries in O(1) time. vector answer(MAX_N + 1, 0); for(int i = 1; i <= MAX_N; i++) answer[i] = answer[i - 1] + no_of_multiples[i]; ------------------------- There's a catch. Both left and right should be at most 10^7, not 10^9. Because all the numbers are guaranteed to be less than 10^7. while(no_of_queries--) { int left, right; scanf("%d %d", &left, &right); right = min(right, MAX_N); left = min(left, MAX_N); printf("%d\n", answer[right] - answer[left - 1]); } ================================================ FILE: Explanations/Explanations 23/Cirriculum Vitae Explanation.txt ================================================ We need the longest sequence of the form - 000... 111 -------- int main() { int no_of_games; scanf("%d", &no_of_games); vector won(no_of_games + 1); for(int i = 1; i <= no_of_games; i++) scanf("%d", &won[i]); vector wins_from(no_of_games + 2, 0); for(int i = no_of_games; i >= 1; i--) wins_from[i] = wins_from[i + 1] + (won[i]); int final_no_of_games = 0; int losses_so_far = 0; for(int i = 1; i <= no_of_games; i++) { losses_so_far += (!won[i]); final_no_of_games = max(final_no_of_games, losses_so_far + wins_from[i]); } printf("%d\n", final_no_of_games); return 0; } ================================================ FILE: Explanations/Explanations 23/Classy Numbers Explanation.txt ================================================ The number of such numbers is quite small. We can precompute all of them and then perform binary search for each query :) ----------- void precompute(int position, int non_zero_count, long long current_num) { if(non_zero_count > 3) return; if(position == MAX_DIGITS) { classy_numbers.push_back(current_num); return; } for(int digit = 0; digit <= 9; digit++) { precompute(position + 1, non_zero_count + (digit != 0), current_num*10 + digit); } } --------------- int main() { precompute(0, 0, 0); classy_numbers.push_back(1e18); //This has 19 digits int no_of_tests; scanf("%d", &no_of_tests); while(no_of_tests--) { long long left, right; scanf("%I64d %I64d", &left, &right); int classy_number_count = upper_bound(all(classy_numbers), right) - lower_bound(all(classy_numbers), left); printf("%d\n", classy_number_count); } return 0; } ================================================ FILE: Explanations/Explanations 23/Counting Arrays Explanation.txt ================================================ Firstly, let us try to count the number of ways to factorise into positive integers. This is equal to the number of ways of distributing each prime factor into y factors. We use stars and bars for each prime. int x, no_of_summands; cin >> x >> no_of_summands; map prime_exponents; factorise(x, prime_exponents); long long answer = 1; for(map :: iterator it = prime_exponents.begin(); it != prime_exponents.end(); it++) { int exponent = it->second; answer *= choose(no_of_summands + exponent - 1, no_of_summands - 1); answer %= MOD; } ----------------------------- Now, after this we need to make an even number of integers even. C(n, 0) + C(n, 2) + ... C(n, 2m), where 2m <= n and 2m + 1 >= n This is equal to 2^{n - 1} long long ways_to_distribute_signs = power_mod(2, no_of_summands - 1); answer = (answer*ways_to_distribute_signs)%MOD;%= MOD; ================================================ FILE: Explanations/Explanations 23/Crazy Town Explanation.txt ================================================ I thought of a complicated solution where I create a graph and draw an edge if two regions share a border, and perform BFS but the solution was stunningly simple. Draw a line from source to destination. The line crosses how many lines ? It crosses every line such that the source and destination are on different sides ! That's it ! That's all that needs to be checked ! Beautiful geometry problem, indeed ! ------------------------------------------ int main() { int start_x, start_y, end_x, end_y; scanf("%d %d %d %d", &start_x, &start_y, &end_x, &end_y); int no_of_lines; scanf("%d", &no_of_lines); int crossed_lines = 0; while(no_of_lines--) { long long a, b, c; scanf("%I64d %I64d %I64d", &a, &b, &c); long long start_side = a*start_x + b*start_y + c; long long end_side = a*end_x + b*end_y + c; if( (start_side > 0 && end_side < 0) || (start_side < 0 && end_side > 0) ) crossed_lines++; } printf("%d\n", crossed_lines); return 0; } ================================================ FILE: Explanations/Explanations 23/Find Maximum Explanation.txt ================================================ Every integer smaller than m has some matching prefix, and then has a 0 where m has a 1. For example if m = 100010010 Then Some numbers will have same first four bits and fifth bits = 0 10000 ..... and can have anything after that. Since all the numbers are positive integers. We will set a 1 to a 0 and then activate all integers after that. So in this case, we will check 011111111 100001111 100010001 And of course, we will have to check m itself ! ------------------------- int main() { int n; scanf("%d", &n); vector A(n + 1); for(int i = 1; i <= n; i++) scanf("%d", &A[i]); vector prefix_sum(n + 1, 0); for(int i = 1; i <= n; i++) prefix_sum[i] = prefix_sum[i - 1] + A[i]; const int MAX_N = 1e5 + 5; char S[MAX_N]; scanf("%s", S + 1); long long answer = 0, set_bit_sum = 0; for(int i = n; i > 0; i--) { if(S[i] == '1') { answer = max(answer, set_bit_sum + prefix_sum[i - 1]); set_bit_sum += A[i]; } } answer = max(answer, set_bit_sum); printf("%I64d\n", answer); return 0; } ================================================ FILE: Explanations/Explanations 23/Fish Explanation.txt ================================================ Blog Link - http://qr.ae/TUpa1S Maintain a mask for all fish that are alive at a given moment. --------------------------------- for(int mask = max_mask; mask >= 1; mask--) { for(int eating_fish = 0; eating_fish < no_of_fish; eating_fish++) { if(is_alive(mask, eating_fish)) //Eating fish is alive { for(int victim_fish = 0; victim_fish < no_of_fish; victim_fish++) { if(is_alive(mask, victim_fish) && eating_fish != victim_fish) { int mask_without_victim = kill(mask, victim_fish); int no_of_alive_fish = no_of_set_bits(mask); int no_of_combinations = choose_2(no_of_alive_fish); probability[mask_without_victim] += (probability[mask]*eat_probability[eating_fish][victim_fish])/no_of_combinations; } } } } } ================================================ FILE: Explanations/Explanations 23/Garbage Disposal Explanation.txt ================================================ Let us be greedy and only use a bag when we need to. ------------------ int main() { int no_of_days, k; cin >> no_of_days >> k; vector A(no_of_days + 1); for(int i = 1; i <= no_of_days; i++) cin >> A[i]; long long minimum_bags = 0; for(int i = 1; i <= no_of_days; i++) { minimum_bags += A[i]/k; A[i] %= k; if(A[i] > 0) { minimum_bags++; if(i + 1 <= no_of_days) A[i + 1] = max(0LL, A[i + 1] - (k - A[i])); } } cout << minimum_bags; return 0; } ================================================ FILE: Explanations/Explanations 23/Guest from the Past Explanation.txt ================================================ int main() { long long money, plastic_bottle_price, glass_bottle_price, return_amount; scanf("%I64d %I64d %I64d %I64d", &money, &plastic_bottle_price, &glass_bottle_price, &return_amount); long long effective_glass_bottle_price = glass_bottle_price - return_amount; long long no_of_bottles = 0; if(plastic_bottle_price <= effective_glass_bottle_price || glass_bottle_price > money) { no_of_bottles = money/plastic_bottle_price; } else if(effective_glass_bottle_price < plastic_bottle_price && glass_bottle_price <= money) { no_of_bottles = (money - return_amount)/effective_glass_bottle_price; long long remaining_money = money - no_of_bottles*effective_glass_bottle_price; long long remaining_bottles = remaining_money/plastic_bottle_price; no_of_bottles += remaining_bottles; } printf("%I64d\n", no_of_bottles); return 0; } ================================================ FILE: Explanations/Explanations 23/Ice Skater Explanation.txt ================================================ We can go from one point to another if either the x-coordinate or y-coordinate is the same. Let us make a graph with the points as vertices and draw an edge between two points if one can be reached from the other. This graph will have a set of connected components. We need to connect all these components together. To connect any two components we need exactly one new point. (For example with the x-coordinate of some point of one component and the y-coordinate of some point of the other component.) Answer = C - 1 --------------------------------------- int main() { int no_of_points; scanf("%d", &no_of_points); vector X(no_of_points + 1); vector Y(no_of_points + 1); for(int i = 1; i <= no_of_points; i++) scanf("%d %d", &X[i], &Y[i]); int no_of_components = 0; for(int i = 1; i <= no_of_points; i++) { for(int j = 1; j < i; j++) { if(X[i] == X[j] || Y[i] == Y[j]) { graph[i].push_back(j); graph[j].push_back(i); } } } for(int i = 1; i <= no_of_points; i++) { if(!visited[i]) { no_of_components++; dfs(i); } } printf("%d\n", no_of_components - 1); return 0; } ================================================ FILE: Explanations/Explanations 23/Lazyland Explanation.txt ================================================ If a number occurs only one time, then there is no point in persuading the person to change as that would not increase the number of distinct values. Suppose some number occurs more than once. We can persuade anyone except the person with the greatest time to change. We can maintain an array A, which has all the times which can be persuaded. Look at all the people who can be persuaded and choose the people with the smallest time. This corresponds with the smallest integers of A. --------------- int main() { int no_of_people, distinct_targets; scanf("%d %d", &no_of_people, &distinct_targets); vector A(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &A[i]); vector time(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &time[i]); map max_time_for_task; vector free_time; for(int i = 1; i <= no_of_people; i++) { if(max_time_for_task[A[i]] != 0) free_time.push_back(min(time[i], max_time_for_task[A[i]])); max_time_for_task[A[i]] = max(max_time_for_task[A[i]], time[i]); } sort(all(free_time)); int distinct_numbers = max_time_for_task.size(); int required_new_distinct_numbers = distinct_targets - distinct_numbers; long long total_time = 0; for(int i = 0; i < required_new_distinct_numbers; i++) total_time += free_time[i]; printf("%I64d\n", total_time); return 0; } ================================================ FILE: Explanations/Explanations 23/Lesha and Array Splitting Explanation.txt ================================================ If the array only has 0s, then there is no answer. Else, find any valid i, where A[1, ... , i] and A[i + 1, ... n] are both non-zero sums. If the sum of the entire array is not 0, then give the full array. Else if the sum is 0, but there are non-zero elements, there must be two parts of non-zero sum which negate each other :) -------- int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) scanf("%d", &A[i]); vector prefix_sum(no_of_elements + 1, 0); for(int i = 1; i <= no_of_elements; i++) prefix_sum[i] = prefix_sum[i - 1] + A[i]; vector suffix_sum(no_of_elements + 2, 0); for(int i = no_of_elements; i>= 1; i--) suffix_sum[i] = suffix_sum[i + 1] + A[i]; int all_zeroes = true; for(int i = 1; i <= no_of_elements; i++) { if(A[i] != 0) all_zeroes = false; } if(all_zeroes) { printf("NO\n"); } else { printf("YES\n"); if(no_of_elements == 1 || prefix_sum[no_of_elements] != 0) { printf("1\n1 %d\n", no_of_elements); } else { int division_point; for(int i = 1; i < no_of_elements; i++) { if(prefix_sum[i] != 0 && suffix_sum[i + 1] != 0) { division_point = i; break; } } printf("2\n"); printf("1 %d\n", division_point); printf("%d %d\n", division_point + 1, no_of_elements); } } return 0; } ================================================ FILE: Explanations/Explanations 23/Lost Array Explanation.txt ================================================ If Array X is the answer, then it must satisfy this property - X[i (mod k)] = A[i + 1] - A[i] For every i, we will need to check that X[i (mod k)] satisfies this property. One way of doing this is constructing an array where X[i] = A[i + 1] - A[i] If X[i (mod k)] = A[i + 1] - A[i], Then A[i + 1] - A[i] = A[j + 1] - A[j] if i = j (mod k) ----------------- Then, we will check here if X[0] = X[k] = X[2k] = X[3k] X[1] = X[k + 1] = X[2k + 1] = X[3k + 1] X[2] = X[k + 2] = X[2k + 2] = X[3k + 2] X[3] = X[k + 3] = X[2k + 3] = X[3k + 3] and so on ------------------- We go through all numbers from 1 to N and check which lengths are possible. vector answer; for(int i = 1; i <= no_of_elements; i++) { if(is_possible(X, i)) { answer.push_back(i); } } ------------------ This is how we check if it is possible. int is_possible(vector &A, int k) { for(int i = 1; i < A.size(); i++) { if(A[i] != A[(i%k)]) return false; } return true; } ================================================ FILE: Explanations/Explanations 23/Maze Explanation.txt ================================================ There are S free cells We will use DFS to visit S - K cells. The remaining K will be marked as walls ------------------------------------- void dfs(int r, int c, int target) { if(no_of_visits >= target) return; visited[r][c] = true; no_of_visits++; const int NO_OF_NEIGHBOURS = 4; int next_x[NO_OF_NEIGHBOURS] = {-1, 0, 0, 1}; int next_y[NO_OF_NEIGHBOURS] = {0, 1, -1, 0}; for(int i = 0; i < NO_OF_NEIGHBOURS; i++) { int next_r = r + next_x[i], next_c = c + next_y[i]; if(0 < next_r && next_r <= rows && 0 < next_c && next_c <= columns && !visited[next_r][next_c] && grid[next_r][next_c] == '.') { dfs(next_r, next_c, target); } } } ----------------- for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == '.') { dfs(i, j, total_free - k); break; } } } for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { printf("%c", (grid[i][j] == '.' && !visited[i][j]) ? 'X' : grid[i][j]); } printf("\n"); } ================================================ FILE: Explanations/Explanations 23/Minesweeper Explanation.txt ================================================ int neighbour_bomb_count(int x, int y) { const int NO_OF_NEIGHBOURS = 8; int step_x[NO_OF_NEIGHBOURS] = {-1, 0, 1, -1, 1, - 1, 0, 1}; int step_y[NO_OF_NEIGHBOURS] = {-1, -1, -1, 0, 0, 1, 1, 1}; int no_of_bombs = 0; for(int i = 0; i < NO_OF_NEIGHBOURS; i++) { no_of_bombs += (grid[x + step_x[i]][y + step_y[i]] == BOMB); } return no_of_bombs; } int main() { int rows, columns; scanf("%d %d", &rows, &columns); for(int i = 1; i <= rows; i++) scanf("%s", grid[i] + 1); int valid = true; for(int i = 1; i <= rows; i++) { for(int j = 1; j <= columns; j++) { if(grid[i][j] == EMPTY) { if(neighbour_bomb_count(i, j) != 0) valid = false; } else if('0' <= grid[i][j] && grid[i][j] <= '9') { if(neighbour_bomb_count(i, j) != grid[i][j] - '0') valid = false; } } } printf(valid ? "YES\n" : "NO\n"); return 0; } ================================================ FILE: Explanations/Explanations 23/Minimum Diameter Tree Explanation.txt ================================================ Notice that the diameter is always between two leaf vertices. (Suppose by contradiction that the diamater is in between two non-leafs u-v. Then we can extend both u and v to their nearest leaves - l1 and l2. The path between l1 and l2 cannot weigh less than u-v because it contains u-v.) ------------ The diameter will always be between two leafs. So, let us set all non-leaf edges to 0 and make all leaf edges equal. If we don't make them equal, then some diameters will always be more than others. ------------ We set every leaf = S/no_of_leaves. --------- int main() { int no_of_vertices, total_weight; scanf("%d %d", &no_of_vertices, &total_weight); vector degree(no_of_vertices + 1, 0); for(int i = 1; i <= no_of_vertices - 1; i++) { int u, v; scanf("%d %d", &u, &v); degree[u]++; degree[v]++; } int no_of_leafs = 0; for(int i = 1; i <= no_of_vertices; i++) no_of_leafs += (degree[i] == 1); double leaf_weight = ( (double) total_weight)/ no_of_leafs; double diameter = leaf_weight*2; printf("%.12f\n", diameter); return 0; } ================================================ FILE: Explanations/Explanations 23/No To Palindromes Explanation.txt ================================================ Fact - To avoid palindromic substrings, it is sufficient to avoid palindromic substrings of length 2 and 3. ------------- We will start from the rightmost position and then look for the first position where we can update S[i] and ensure 2 and 3 length palindromes are avoided. S[i] should not be equal to S[i - 1] and S[i - 2]. for(int i = length - 1; first_greater_position == NOT_FOUND && i >= 0; i--) { for(char new_ch = S[i] + 1; new_ch <= 'a' + max_alphabet - 1; new_ch++) { int possible = true; for(int j = i - 1; j >= max(i - 2, 0); j--) { if(new_ch == S[j]) possible = false; } if(possible) { first_greater_position = i; replacement = new_ch; break; } } } if(first_greater_position == NOT_FOUND) { cout << "NO\n"; return 0; } ------------ Now we must make the suffix as small as possible. We only need to use a, b and c. As long as k >= 3, we can always do this. If k < 3, then we cannot have a string of length longer than 2. And it would have been caught by the previous part of the program. :) string next_good_string; for(int i = 0 ; i < first_greater_position; i++) next_good_string += S[i]; next_good_string += replacement; for(int i = first_greater_position + 1; i < length; i++) { char current_char; for(current_char = 'a'; current_char <= 'c'; current_char++) { if( (i - 1 >= 0 && next_good_string[i - 1] == current_char) || (i - 2 >= 0 && next_good_string[i - 2] == current_char) ) { continue; } else { next_good_string += current_char; break; } } } ================================================ FILE: Explanations/Explanations 23/On Number of Decompositions into Multipliers Explanation.txt ================================================ Let us notice that if N is a prime number we can't break it down further and can only assign it to one of k places. ------------------------ If N = p^m, Then it is equal to the number of ways of writing m as the result of m summands. This is like stars and bars. The answer is C(m + k - 1, k - 1) ---------------------------------- Each prime is independent. We will break down N into it's prime factors and solve seperately for each prime exponent. -------------------------------- int main() { sieve(); precompute(); int no_of_elements; cin >> no_of_elements; map prime_exponents; for(int i = 1; i <= no_of_elements; i++) { int element; cin >> element; factorise(element, prime_exponents); } const int MOD = 1e9 + 7; long long answer = 1; for(map :: iterator it = prime_exponents.begin(); it != prime_exponents.end(); it++) { int exponent = it->second; answer *= choose(no_of_elements + exponent - 1, no_of_elements - 1); answer %= MOD; } cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 23/Summarise to Powers of Two Explanation.txt ================================================ For every element of the array, check if there exists (2^p - A[i]), for 30 powers of 2. The special case is when (2^p - A[i]) = A[i], In that case, the frequency of the complement must be 2, not 1. ------------------------------------------------ int main() { int no_of_elements; scanf("%d", &no_of_elements); vector A(no_of_elements + 1); map frequency; for(int i = 1; i <= no_of_elements; i++) { scanf("%d", &A[i]); frequency[A[i]]++; } int no_of_deletions = 0; for(int i = 1; i <= no_of_elements; i++) { int complement_exists = false; for(int power = 0; power <= 32; power++) { int complement = (1LL << power) - A[i]; if(complement == A[i]) { if(frequency[A[i]] >= 2) complement_exists = true; } else if(frequency.find(complement) != frequency.end()) { complement_exists = true; } } if(!complement_exists) no_of_deletions++; } printf("%d\n", no_of_deletions); return 0; ================================================ FILE: Explanations/Explanations 23/The Fair Nut and String Explanation.txt ================================================ Every alphabet other than 'a' and 'b' does not matter. We might as well delete it. Whenever we have a block of 'a' ... We may choose a single 'a' from it or not choose any 'a'. Each block is independent. The answer is Prod(Block_size + 1) - 1 We subtract 1 because we have also counted the empty sequence. -------------- int main() { string S; cin >> S; const int MOD = 1e9 + 7; long long total_sequences = 1, current_block_of_a = 0; for(int i = 0; i <= S.size(); i++) { if(S[i] == 'a') { current_block_of_a++; } else if(i == S.size() || S[i] == 'b') { total_sequences = (total_sequences*(current_block_of_a + 1))%MOD; current_block_of_a = 0; } } total_sequences = (total_sequences + MOD - 1)%MOD; cout << total_sequences; return 0; } ================================================ FILE: Explanations/Explanations 23/The Meaningless Game Explanation.txt ================================================ The sum of the prime exponents of numbers in both A and B should be a multiple of 3. Let A win X points in total and let B win Y points in total. Then A = X^2 Y and B = X^2 Y Now we notice that AB = (XY)^3 We can compute the first million cubes to find the cube roots till 10^{18}. After finding XY = (AB)^(1/3) A = X (XY) and B = Y (XY) Now we can simply find X and Y and then we check if the A and B are consistent. ---------------- int main() { int no_of_people, distinct_targets; scanf("%d %d", &no_of_people, &distinct_targets); vector A(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &A[i]); vector time(no_of_people + 1); for(int i = 1; i <= no_of_people; i++) scanf("%d", &time[i]); map max_time_for_task; vector free_time; for(int i = 1; i <= no_of_people; i++) { if(max_time_for_task[A[i]] != 0) free_time.push_back(min(time[i], max_time_for_task[A[i]])); max_time_for_task[A[i]] = max(max_time_for_task[A[i]], time[i]); } sort(all(free_time)); int distinct_numbers = max_time_for_task.size(); int required_new_distinct_numbers = distinct_targets - distinct_numbers; long long total_time = 0; for(int i = 0; i < required_new_distinct_numbers; i++) total_time += free_time[i]; printf("%I64d\n", total_time); return 0; } ================================================ FILE: Explanations/Explanations 24/Brutality Explanation.txt ================================================ Suppose there was only one alphabet. Then what is the answer ? The answer is the k highest numbers. Now we have to treat every block of consecutive characters independently. For each block, maintain the costs. Sort it and take the k greatest numbers as the answer. A block ends either when you have reached the end of the string or when S[i] != S[i - 1]. ---- int main() { int length, max_elements; cin >> length >> max_elements; vector A(length); for(int i = 0; i < length; i++) cin >> A[i]; string S; cin >> S; long long total = 0; vector last_pressed_costs; for(int i = 0; i <= length; i++) { if(i == length ||S[i] != S[i - 1]) { sort(all(last_pressed_costs)); reverse(all(last_pressed_costs)); for(int j = 0; j < min(max_elements, last_pressed_costs.size()); j++) { total += last_pressed_costs[j]; } last_pressed_costs.clear(); } if(i == length) continue; last_pressed_costs.push_back(A[i]); } cout << total; return 0; } ================================================ FILE: Explanations/Explanations 24/Connect Explanation.txt ================================================ Let us do DFS and put two cells in the same component if they lie on land and are reachable without crossing water. If the Start and Finish points are in the same component, the answer is 0. Else, make a vector of all the points in the starting component and all the points in the finish component and find the minimum distance between these points. Actually, we do not need to handle the 0 case seperately. Simply make a component of all points in the start and finish point and find the distance between every pair of points between them. If it's the same component, the distance will be 0. ------------- int calculate_distance(Point P, Point Q) { return (P.x - Q.x)*(P.x - Q.x) + (P.y - Q.y)*(P.y - Q.y); } int is_outside(int x, int y, int n) { return (x < 1 || n < x || y < 1 || n < y); } void dfs(int x, int y, int n, int number) { if(is_water[x][y] || is_outside(x, y, n) || component_no[x][y] != 0) return; component_no[x][y] = number; for(int i = 0; i < NO_OF_NEIGHBOURS; i++) { dfs(x + next_x[i], y + next_y[i], n, number); } } int main() { int n; cin >> n; Point start, finish; cin >> start.x >> start.y >> finish.x >> finish.y; memset(is_water, false, sizeof(is_water)); for(int i = 0; i < n; i++) { string row; cin >> row; for(int j = 0; j < n; j++) { if(row[j] == '1') { is_water[i + 1][j + 1] = true; } } } memset(component_no, 0, sizeof(component_no)); int last_component_no = 0; for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { if(component_no[x][y] == 0) { dfs(x, y, n, ++last_component_no); } } } vector start_component, finish_component; for(int x = 1; x <= n; x++) { for(int y = 1; y <= n; y++) { if(component_no[x][y] == component_no[start.x][start.y]) start_component.push_back(Point(x, y)); if(component_no[x][y] == component_no[finish.x][finish.y]) finish_component.push_back(Point(x, y)); } } int distance = oo; for(int i = 0; i < start_component.size(); i++) { for(int j = 0; j < finish_component.size(); j++) { distance = min(distance, calculate_distance(start_component[i], finish_component[j])); } } cout << distance; return 0; } ================================================ FILE: Explanations/Explanations 24/Div Times Mod Explanation.txt ================================================ Let us iterate over the divisors of n. For each pair of factors (f1, f2) such that f1 x f2 = n, One will be the quotient and one will the remainder. We need to check if the remainder is smaller than k, of course. And then among all such values we set x to the minimum. ------------- int main() { int n, k; cin >> n >> k; const int oo = 1e9; int answer = oo; for(int i = 1; i*i <= n; i++) { if(n%i == 0) { int quotient = i, remainder = n/i; if(remainder < k) answer = min(answer, quotient*k + remainder); quotient = n/i, remainder = i; if(remainder < k) answer = min(answer, quotient*k + remainder); } } cout << answer; return 0; } ================================================ FILE: Explanations/Explanations 24/Diverse Garland Explanation.txt ================================================ Greedy Solution works. We will from from i = 1 to N Whenever S[i] = S[i - 1], we will change S[i]'s colour. Note that if we change whenever S[i] = S[i + 1], then it might not be optimal as swapping S[i] when it is different from S[i + 1] might solve at most one position's problem. But swapping when S[i] = S[i - 1] can solve two positions' problems. --- I kept a string called colour "RGB" for convenience in knowing what to swap. Similar to the C of this contest, where I kept 6 string - RGB, RBG, BGR, BRG, GRB, GBR And counted number of replacements for each string S[i] = R[i%3]. --- int main() { int length; string S; cin >> length >> S; string colour = "RGB"; int replacements = 0; for(int i = 1; i < length; i++) { if(S[i] == S[i - 1]) { for(int j = 0; j < colour.size(); j++) { if( (i + 1 == length && colour[j] != S[i - 1]) || (colour[j] != S[i + 1] && colour[j] != S[i - 1]) ) { replacements++; S[i] = colour[j]; break; } } } } cout << replacements << "\n" << S; return 0; } ================================================ FILE: Explanations/Explanations 24/Division and Union Explanation.txt ================================================ Let us sort the segments by their endings. Then for some segment Si, we know that all segments from [i + 1, ... , n] have their endings after Si. If we know that the smallest beginning is also after Si, then we can place [1, 2, ... , i] in one group and the remaining segments in the other group. Alternatively, we could also sort by beginnings and then check for some i, if the largest ending in [1, 2, ... , i - 1] is before the beginning of Si. If no such segment i exists, then it means the segments are all connected and two such groups are not possible. ----- void solve() { int no_of_segments; cin >> no_of_segments; vector L; for(int i = 0; i < no_of_segments; i++) { int left, right; cin >> left >> right; L.push_back(line(left, right, i)); } sort(all(L)); vector minimum_left_from(no_of_segments); for(int i = no_of_segments - 1; i >= 0; i--) { if(i == no_of_segments - 1) minimum_left_from[i] = L[i].left; else minimum_left_from[i] = min(minimum_left_from[i + 1], L[i].left); } const int NOT_FOUND = -1; int first_group_ending = NOT_FOUND; for(int i = 0; i < no_of_segments - 1; i++) { if(L[i].right < minimum_left_from[i + 1]) first_group_ending = i; } if(first_group_ending == NOT_FOUND) { cout << NOT_FOUND << "\n"; return ; } vector group(no_of_segments); for(int i = 0; i < no_of_segments; i++) group[L[i].position] = (i <= first_group_ending ? 1 : 2); for(int i = 0; i < no_of_segments; i++) cout << group[i] << " "; cout << "\n"; } ================================================ FILE: Explanations/Explanations 24/Finite or Not Explanation.txt ================================================ The fraction is finite, if gcd(p, q) = 1 and q | b^k. Let us keep dividing denominator by base to determine if there are prime factors in q that are not in b. ----------------- void solve() { LL numerator, denominator, base; scanf("%I64d %I64d %I64d", &numerator, &denominator, &base); LL gcd_fraction = gcd(numerator, denominator); numerator /= gcd_fraction; denominator /= gcd_fraction; base = gcd(base, denominator); while(base > 1) { while(denominator%base == 0) denominator /= base; base = gcd(base, denominator); } printf(denominator == 1 ? "Finite\n" : "Infinite\n"); } ================================================ FILE: Explanations/Explanations 24/Ilya and Escalator Explanation.txt ================================================ Let f(i, j) represent the probability that there are i people at time j. f(i, j) = p f(i - 1, j - 1) + (1 - p) f(i, j - 1) The first term represents the case where a person comes on at time j. So there have to be (i - 1) people at time (j - 1). The second term represents the case where no new person steps on at time j. So there have to be (i) people at time (j - 1). ---- Now, f(N, j) = f(N, j - 1) + (p) f(N - 1, j - 1) The reason is that if there are N people already on the esclator, no new person can step on so there's no need to multiply it with (1 - p). ---- f(0, j) = (i - p) f(0, j - 1) ----- Now to find the expectation, we will sum over i f(i, T). ----------- int main() { int no_of_people, total_time; double new_person_probability; cin >> no_of_people >> new_person_probability >> total_time; double no_new_person_probability = 1 - new_person_probability; memset(probability, 0, sizeof(probability)); probability[0][0] = 1; for(int t = 1; t <= total_time; t++) { probability[0][t] = no_new_person_probability*probability[0][t - 1]; for(int i = 1; i < no_of_people; i++) { probability[i][t] = new_person_probability*probability[i - 1][t - 1] + no_new_person_probability*probability[i][t - 1]; } probability[no_of_people][t] = probability[no_of_people][t - 1] + new_person_probability*probability[no_of_people - 1][t - 1]; } double expectation = 0; for(int i = 1; i <= no_of_people; i++) expectation += i*probability[i][total_time]; cout << setprecision(7) << expectation; return 0; } ================================================ FILE: Explanations/Explanations 24/Increasing by Modulo Explanation.txt ================================================ We can binary search the number of operations required to make the array non-decreasing. We can make A[i] = (A[i], A[i] + x) (mod M). These are the reachable values for A[i]. We will choose the smallest value possible at each step for each A[i], while maintaining the condition that A[i] is not smaller than the prefix minimum. If possible we will make A[i] = the prefix minimum. Otherwise, we will make the minimum = A[i]. If A[i] can't be made >= minimum and is < minimum, then it is not possible in x moves. --- At each step, we are making the minimum as small as possible. It is never optimal to increase some previous element by more than what we have as that would increase the minimum. --- int possible(int operations, int m, vector &A) { int minimum = 0; for(int i = 1; i < A.size(); i++) { if( (A[i] <= minimum && A[i] + operations >= minimum) || (A[i] > minimum && A[i] + operations - m >= minimum) ) continue; if(A[i] < minimum) return false; minimum = A[i]; } return true; } int main() { int no_of_elements, m; cin >> no_of_elements >> m; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; int left = -1, right = m; while(right - left > 1) { int mid = (left + right)/2; if(possible(mid, m, A)) right = mid; else left = mid; } cout << right; return 0; } ================================================ FILE: Explanations/Explanations 24/Nice Garland Explanation.txt ================================================ Every position = 0 (mod 3) must have the same colour. Every position = 1 (mod 3) must have the same colour. Every position = 2 (mod 3) must have the same colour. We must distribute RGB into 3 holes. There are 3! = 6 ways of doing this. We will count the number of replacements required in the 6 ways and give the one that minimises it. ---- int replacements(string &R, string &S) { int difference_count = 0; for(int i = 0; i < S.size(); i++) difference_count += (S[i] != R[i%3]); return difference_count; } int main() { int length; cin >> length; string S; cin >> S; const int NO_OF_OPTIONS = 6, oo = 1e9; string option[NO_OF_OPTIONS] = {"RGB", "RBG", "BRG", "BGR", "GRB", "GBR"}; int minimum_replacement = oo, best_option = 0; for(int i = 0; i < NO_OF_OPTIONS; i++) { int replacements_here = replacements(option[i], S); if(replacements_here < minimum_replacement) { minimum_replacement = replacements_here; best_option = i; } } cout << minimum_replacement << "\n"; for(int i = 0; i < length; i++) cout << option[best_option][i%3]; return 0; } ================================================ FILE: Explanations/Explanations 24/Planning the Expedition Explanation.txt ================================================ Let us use binary search over the number of days. It can be proved that it is a monotonic function. --------------- int possible(vector A, int days, int min_participants) { int participants = 0; for(int i = 0; i < A.size(); i++) { participants += A[i]/days; A[i] %= days; } return (participants >= min_participants); } int main() { int no_of_participants, no_of_packages; scanf("%d %d", &no_of_participants, &no_of_packages); const int MAX = 100; vector frequency(MAX + 1, 0); for(int i = 1; i <= no_of_packages; i++) { int type; scanf("%d", &type); frequency[type]++; } if(no_of_packages < no_of_participants) { printf("0"); return 0; } int left_days = 1, right_days = MAX; while(left_days <= right_days) { int mid_days = (left_days + right_days) >> 1; if(possible(frequency, mid_days, no_of_participants)) { if(mid_days == right_days || !possible(frequency, mid_days + 1, no_of_participants)) { printf("%d\n", mid_days); return 0; } else { left_days = mid_days + 1; } } else { right_days = mid_days - 1; } } return 0; } ================================================ FILE: Explanations/Explanations 24/Playing Piano Explanation.txt ================================================ Let f(i, j) be true if it is possible to play the first i notes using the finger j for the last note. We will first calculate f(i, j). If f(N, j) is true for any j, it is possible other wise it is not. For example, if A[i - 1] < A[i], Then f(i, j) is true, if for some j', where j' < j and f(i - 1, j) is true. Since j' is a smaller finger, if we can play (i - 1) with j' last, then we can play i notes with j last. for(int i = 1; i <= no_of_notes; i++) { for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(i == 1) { is_possible[i][finger] = true; continue; } if(notes[i - 1] <= notes[i]) { for(int previous_finger = 1; previous_finger < finger; previous_finger++) { if(is_possible[i - 1][previous_finger]) { is_possible[i][finger] = true; } } } if(notes[i - 1] >= notes[i]) { for(int previous_finger = NO_OF_FINGERS; previous_finger > finger; previous_finger--) { if(is_possible[i - 1][previous_finger]) { is_possible[i][finger] = true; } } } } } ----- Now to actually construct the sequence, we must go backwards. For every i, look at A[i] and A[i + 1]. Case 1 - A[i] < A[i + 1]. Then look at the finger assigned to note (i + 1). Find any smaller finger j, such that f(i, j) is true. Then assign finger j to note i. Case 2 - A[i] > A[i + 1] Then look at the finger assigned to note (i + 1). Find any greater finger j, such that f(i, j) is true. Case 3 - A[i] = A[i + 1] Assign any finger j, such that f(i, j) is true and j is not the finger used for the i-th note. vector playing_finger(no_of_notes + 1); for(int i = no_of_notes; i >= 1; i--) { if(i == no_of_notes) { for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[i][finger]) { playing_finger[i] = finger; break; } } continue; } if(notes[i] < notes[i + 1]) { for(int finger = playing_finger[i + 1] - 1; finger >= 1; finger--) { if(is_possible[i][finger]) { playing_finger[i] = finger; break; } } } if(notes[i] > notes[i + 1]) { for(int finger = playing_finger[i + 1] + 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[i][finger]) { playing_finger[i] = finger; break; } } } if(notes[i] == notes[i + 1]) { for(int finger = 1; finger <= NO_OF_FINGERS; finger++) { if(is_possible[i][finger] && finger != playing_finger[i + 1]) { playing_finger[i] = finger; break; } } } } ================================================ FILE: Explanations/Explanations 24/Posterized Explanation.txt ================================================ int main() { int no_of_colours, group_size; scanf("%d %d", &no_of_colours, &group_size); const int MAX_COLOUR = 255; vector colour(no_of_colours + 1); for(int i = 1; i <= no_of_colours; i++) scanf("%d", &colour[i]); vector key(MAX_COLOUR + 1); vector used(MAX_COLOUR + 1, false); for(int i = 1; i <= no_of_colours; i++) { int current_colour = colour[i]; if(!used[current_colour]) { int first_colour = max(0, current_colour - group_size + 1); while(used[first_colour] && key[first_colour] + group_size - 1 < current_colour) first_colour++; if(!used[first_colour]) key[first_colour] = first_colour, used[first_colour] = true; for(int j = first_colour + 1; j <= current_colour; j++) { key[j] = key[first_colour]; used[j] = true; } } } for(int i = 1; i <= no_of_colours; i++) printf("%d ", key[colour[i]]); return 0; } ================================================ FILE: Explanations/Explanations 24/Powers of Two Explanation.txt ================================================ if k < no of bits in n, then it is not possible because the binary representation of a number writes it using the fewest possible powers of 2. If k > n, then it is not possible as we can at most have n ones. These two cases aside, we always have an answer. We will be greedy. As long as we haven't gotten the required number of summands, we simply pick some summand > 1, 2^i remove it and put in 2^{i -1} and 2^{i - 1}. ------- int main() { int n, no_of_summands; cin >> n >> no_of_summands; int no_of_summands_made = 0; const int MAX_POWER = 32; vector frequency(MAX_POWER, 0); for(int i = 0; i < MAX_POWER; i++) { if(is_bit_set(i, n)) { frequency[i]++; no_of_summands_made++; } } if(no_of_summands < no_of_summands_made || no_of_summands > n) { cout << "NO\n"; return 0; } cout << "YES\n"; while(no_of_summands_made < no_of_summands) { for(int i = 1; i < MAX_POWER; i++) { if(frequency[i] > 0) //Break 2^i into 2^{i - 1} and 2^{i - 1} { frequency[i]--; frequency[i - 1] += 2; no_of_summands_made++; break; } } } for(int i = 0; i < MAX_POWER; i++) { for(int j = 0; j < frequency[i]; j++) { cout << (1 << i) << " "; } } return 0; } ================================================ FILE: Explanations/Explanations 24/Splitting into Digits Explanation.txt ================================================ Print N 1s. This ensures that they sum to N and they are all the same. --- int main() { int n; cin >> n; cout << n << "\n"; for(int i = 1; i <= n; i++) cout << "1 "; return 0; } ================================================ FILE: Explanations/Explanations 24/Stages Explanation.txt ================================================ int main() { int no_of_letters, required_letters; string S; cin >> no_of_letters >> required_letters >> S; const int NO_OF_ALPHABETS = 26; vector present(NO_OF_ALPHABETS, false); for(int i = 0; i < no_of_letters; i++) present[S[i] - 'a'] = true; int sum = 0, chosen = 0; for(int i = 0; i < NO_OF_ALPHABETS && chosen < required_letters; i++) { if(present[i]) { chosen++; sum += i + 1; i++; } } cout << (chosen < required_letters ? -1 : sum); return 0; } ================================================ FILE: Explanations/Explanations 24/Tanya and Candies Explanation.txt ================================================ Whenever we remove an element, then even_sum_till[i - 1] + odd_sum_from[i + 1] = odd_sum_till[i - 1] + even_sum_from[i + 1]. The reason is that removing an element changes the parity of all indices after it. We need to precompute the prefix and suffix sums. I did this elegantly with a two dimensional array. --------------- const int MAX_N = 2e5 + 5, EVEN = 0, ODD = 1; long long sum_till[MAX_N][2], sum_from[MAX_N][2]; int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; sum_till[0][ODD] = sum_till[0][EVEN] = 0; for(int i = 1; i <= no_of_elements; i++) { sum_till[i][ODD] = sum_till[i - 1][ODD]; sum_till[i][EVEN] = sum_till[i - 1][EVEN]; sum_till[i][i%2] += A[i]; } sum_from[no_of_elements + 1][ODD] = sum_from[no_of_elements + 1][EVEN] = 0; for(int i = no_of_elements; i >= 1; i--) { sum_from[i][ODD] = sum_from[i + 1][ODD]; sum_from[i][EVEN] = sum_from[i + 1][EVEN]; sum_from[i][i%2] += A[i]; } int no_of_points = 0; for(int i = 1; i <= no_of_elements; i++) { no_of_points += (sum_till[i - 1][EVEN] + sum_from[i + 1][ODD] == sum_till[i - 1][ODD] + sum_from[i + 1][EVEN]); } cout << no_of_points; return 0; } ================================================ FILE: Explanations/Explanations 24/The Way to Home Explanation.txt ================================================ Let f(i) denote the minimum number of jumps to reach position i. Then f(i) = 1 + min{f(i - 1), f(i - 2), f(i - 3), f(i - 4), ... , f(i - d)} --------- int main() { int length, max_jump; cin >> length >> max_jump; string path; cin >> path; const int oo = 1e9; vector minimum_jumps_to_reach(length, 0); minimum_jumps_to_reach[0] = 0; for(int i = 1; i < length; i++) { minimum_jumps_to_reach[i] = oo; if(path[i] == '0') continue; for(int j = 1; j <= max_jump && i - j >= 0; j++) { minimum_jumps_to_reach[i] = min(minimum_jumps_to_reach[i], 1 + minimum_jumps_to_reach[i - j]); } } cout << (minimum_jumps_to_reach[length - 1] == oo ? -1 : minimum_jumps_to_reach[length - 1]); return 0; } ================================================ FILE: Explanations/Explanations 24/Vanya and Label Explanation.txt ================================================ If a certain bit is 1, then we only have one option 1. If a certain bit is 0, then we have 3 options. Go through every bit of every letter, and the answer is 3^z, where z is the number of 0s. -------------------- int main() { string S; cin >> S; long long no_of_ways = 1; const int MOD = 1e9 + 7; for(int i = 0; i < S.size(); i++) { for(int bit = 0; bit < 6; bit++) { if(!is_bit_set(value(S[i]), bit)) { no_of_ways = (no_of_ways*3)%MOD; } } } cout << no_of_ways; return 0; } ================================================ FILE: Explanations/Explanations 24/Where Do I Turn Explanation.txt ================================================ int main() { int a_x, a_y, b_x, b_y, c_x, c_y; scanf("%d %d %d %d %d %d", &a_x, &a_y, &b_x, &b_y, &c_x, &c_y); //Checking if (y2 - y1)/(x2-x1) = slope of AB = Slope of BC. Multiplication is done to avoid division by zero error and precision losses. if( (c_y - b_y)*1LL*(b_x - a_x) - (b_y - a_y)*1LL*(c_x - b_x) == 0 ) printf("TOWARDS\n"); else if( (c_y - b_y)*1LL*(b_x - a_x) - (b_y - a_y)*1LL*(c_x - b_x) > 0 ) printf("LEFT\n"); else printf("RIGHT\n"); return 0; } ================================================ FILE: Explanations/Explanations 24/Zero Quantity Maximisation Explanation.txt ================================================ How do we make C[1] = 0 ? We have to set D = -B[1]/A[1]. Now, when we set D = -B[1]/A[1] ? Any pair of integers where B[i]/A[i] = B[1]/A[1]. So, we simply have to keep track of the frequency of each fraction and find out which comes the highest. Also, a few things to keep in mind - 1. If (A[i] == 0), then we cannot have a fraction, so we just ignore it. 2. If(A[i] = B[i] = 0) already, then we will always get a 0 at this position so we need to keep track of the number of such positions. -------- A few things to keep in mind. While implementing fractions, 1. Keep track of the fraction in it's reduced form where the numerator and denominator are coprime. 2. a/b = (-a)/(-b) 3. (-a)/b = a/(-b). So, try to standardise and maintain only the numerator or only the denominator as negative. 4. While calculate gcd(a, b) do gcd(|a|, |b|) 5. Since we are using maps, we need to over load the < operator so that the map knows how to store the fractions. 6. In maps, two objects are considered equal if !(a < b) && !(b < a). So while overloading the < operator, don't add <= by mistake. Here is the fraction structure. -------- struct fraction { long long numerator, denominator; fraction(){} fraction(long long N, long long D) { long long G = __gcd(abs(N), abs(D)); numerator = N/G; denominator = D/G; if(denominator < 0) { numerator *= -1; denominator *= -1; } } const int operator <(const fraction &F) const { return (denominator*F.numerator - numerator*F.denominator < 0); } }; --------- The solution int main() { int no_of_elements; cin >> no_of_elements; vector A(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> A[i]; vector B(no_of_elements + 1); for(int i = 1; i <= no_of_elements; i++) cin >> B[i]; int both_zeroes = 0; for(int i = 1; i <= no_of_elements; i++) both_zeroes += (A[i] == 0 && B[i] == 0); map frequency; for(int i = 1; i <= no_of_elements; i++) { if(A[i] == 0) continue; frequency[fraction(-B[i], A[i])]++; } int max_frequency = 0; for(map :: iterator it = frequency.begin(); it != frequency.end(); it++) { max_frequency = max(max_frequency, it->second); } int answer = max_frequency + both_zeroes; cout << answer; return 0; } ================================================ FILE: README.md ================================================ CodeForces This repository is a notebook consisting of all my solutions to questions from CodeForces. It is divided into two sections. The folder 'Explanation' consists of text files which document the algorithm and my explanation of the problems. Grouping is also done because there are significant changes in my programming style over time. My handle is `ghoshsai5000`