# Miscelleneous Problems 13 ## Game Of Ways ### Problem Statement Batman is about to take off from Gotham’s airport which has m runways(numbered from 1 to m) of length n units. As always, the Joker has come up with an insane game to have fun with Batman. The rules of the game are as follows:: - Batman’s plane can take off only after running for n-units distance in the runways. - Batman can start on any runway and end on any runway. - Batman can switch his plane from runway i to j only if i and j are coprime. - If the batman fails to switch his plane to a coprime runway, after running for 1 unit distance on a single runway, the Joker will bomb the plane. The Joker does not want to kill the batman, because what will he do without him. So he asks for your help to find out number of ways in which Batman can take off his plane without getting bombed. As the answer can be very large, output answer modulo (1000000007) ---------- **Input Format** ``` First argument given is an Integer A, Length of the runway. Second argument given is an Integer B, Number of different runways available ``` **Output Format** ``` Return a single integer X, the number of ways Batman can take off his plane without getting bombed. As X can be very large, return X MOD 10^9+7 ``` **Constraints** ``` 1 <= A <= 1000000000 0 <= B <= 10 ``` **For Example** ```C++ Input 1: A = 1 B = 3 Output 1: 3 Input 2: A = 2 B = 3 Output 1: 7 Explanation: For test 1: 3 Ways Starting at 1, 2, 3 For test 2: 1st way: starting and covering whole distance at runway 1. i.e 1 -> 1 (1 and 1 are co-prime so Batman can continue on runway 1 without getting bombed) 2nd way: starting and covering distance of 1 at runway 1 and covering remaining distance at runway 2. i.e 1 -> 2 3rd way: starting and covering distance of 1 at runway 1 and covering remaining distance at runway 3. i.e 1 -> 3 similarly there are 4 more ways i.e 2 -> 1, 2 -> 3, 3 -> 1, 3 -> 2 we can't go from 2 -> 2 and 3 -> 3 as per given rules. ``` ### Brute force - Generate all permutations of 1,...,B of size A. - Check if all the consicutive elements are co-prime. Count all such permutations. - Time Complexity: B^A. ### First Approach - It should be clear from the question that we need a graph of size B. - Let's apply dynamic programing on this graph. - Let dp[i][k] be the number of ways to start at i and run a length of k. - dp[i][1] = 1 for all i. - $dp[i][k] = \sum_{j \in adj[i]}dp[j][k-1]$ **Code** ```C++ int gcd(int i, int j){ if(i>j) return gcd(j,i); else if (i == 0) return j; else{ int k = j%i; return gcd(k, i); } } bool coPrime(int i, int j){ return gcd(i,j) == 1; } void printArray(vector> adj){ for(int i = 0 ; i> adj(B); for(int i = 0; i< B; ++i){ for(int j = i ; j dp_old(B); vector dp_new(B); for(int i = 0; i < B; ++i){ dp_new[i] = 1; } int mod = 1000000007; for(int k = 2; k<=A; ++k){ dp_old = dp_new; for(int i = 0; i< B; ++i){ dp_new[i] = 0; for(auto j : adj[i]){ dp_new[i] += dp_old[j]%mod; dp_new[i] %= mod; } } } int res= 0; for(int i= 0; ij) return gcd(j,i); else if (i == 0) return j; else{ int k = j%i; return gcd(k, i); } } bool coPrime(int i, int j){ return gcd(i,j) == 1; } void printArray(vector> adj){ for(int i = 0 ; i> &A, vector> &B){ int n = A.size(); for(int i= 0; i> &A){ int n = A.size(); vector> temp(n, vector(n)); copy(A,temp); for(int i = 0; i> &A, vector> &B){ int n = A.size(); vector> temp(n, vector(n)); copy(A,temp); for(int i = 0; i> A){ cout << "-------------" << endl; for(auto row: A){ for(auto cell: row){ cout << cell << " " ; } cout << endl; } } void pow_matrix(vector> &adj,int A, vector> &orignal){ //print(adj); //cout << A << endl; if(A == 1) return; int n = adj.size(); pow_matrix(adj, A/2, orignal); square(adj); if(A%2 == 1){ multiply(adj, orignal); } } int Solution::solve(int A, int B) { if(A == 0) return 0; if(A == 1) return B; vector > adj(B, vector (B,0)); for(int i = 0; i< B; ++i){ for(int j = 0 ; j> identity(n, vector(n,0)); copy(adj,identity); pow_matrix(adj, A-1, identity); long long int sum = 0; for(int i= 0; i A[i+1]$ - $A[j] > A[j+1]$ - We fill all the nodes after j to level of j. And fill nodes after $i$ like the first case. ### Code ```C++ bool isValid(vector psum, int i, int X, int Y, int h){ long long sum = psum[X] - psum[i]; return h*(X-i) - sum <= Y; } void update(vector &array, int X, int Y){ int n = array.size(); vector psum(n,0); psum[0] = array[0]; for(int i=1; i 0){ array[i]++; Y--; remaining--; } } return; } vector Solution::solve(int A, vector > &B) { vector array(A,0); for(auto b : B){ update(array, b[0]-1, b[1]); } return array; } ``` ### Time Complexity - Since we are running a loop of size $O(X)$ twice for every update, $O(X* T)$. ## Sum of Inversions ### Problem Statement Consider a random permutation P of numbers [1, 2, .., N]. This permutation is called special if there is no element P[i] in P such that **P[i] = i+1** (Consider 0 based indexing). In other words, a permutation is special if it is a derangement (no number is at its "natural" (ordered) place). Given a number N, find the sum of inversions in all the special permutations of numbers [1, 2, ..., N] modulo **1000000007**. An inversion in an array P is a pair P[i], P[j] such that P[i] > P[j] and i rank in iteration i=3 in for loop is 1 which means // there is 1 number in the mask less than 4 (and that number is 2 in this case) rank += 1; } } ``` ### Hints on Website This type of problems requires a special DP formulation known as Bitmask DP. Those who are not familiar with the concept are advised to Google it before proceeding further. Consider the following DP formulation: mask = bitmask where i-th set bit from the left means number i is yet to be used in generating a special permutation. e.g.: mask = 5 => mask = 101 (binary) => Current permutation 2 _ _. Use numbers [1,3] to fill the blanks in the current permutation. cnt = no. of unset bits in mask (mask = 5 => mask = 101 (binary) => no. of unset bits = 1) dp[mask] = sum of inversions of all the special permutations that can be generated using the numbers corresponding to set bits in mask such that the numbers should be arranged at positions [cnt+1, cnt+2, .., N] e.g.: mask = 101 One number is already fixed at position 1 and that number is 2. Permutation generated till this point is 2 _ _. Now we have to arrange the remaining numbers [1,3] at blank positions and form a special permutation. Recursion tree for N = 3 looks like following: ``` 111 / | \ 011(1__) 101(2__) 110(3__) / \ / \ 001 100 100 010 (21_) (23_) (32_) (31_) ``` Here, 011 at level 2 in the tree is not extended further as it is not a valid permutation (011 corresponds to permutation 1 _ _ and 1 cannot be at its correct position according to our rule of special permutations). Similarly "100" (child of "110" in level 3) is also not a valid permutation as that corresponds to permutation 32_. This type of formulation will require us to ignore the branches of tree that form a non-valid permutation and consider those which forms a valid permutation. Now, the only challenge is to count the sum of inversions at every node of the tree. This is left as an exercise to the reader. Coding part is very easy once you have thought of a way to augment the recursion tree to store necessary information. Time complexity of this approach would be O(C*N*(2^N)) which is much less than O(N!). For any given N, our answer is simply dp[(1< rank in iteration i=3 in for loop is 1 which means // there is 1 number in the mask less than 4 (and that number is 2 in this case) rank += 1; } } dp[mask].vis = 1; return dp[mask]; } int Solution::solve(int n){ int mask = (1< 111...1 "n ones" for(int i=0; i< (1<