Skip to main content

Topcoder SRM 684 DivFreed2 Div 2 level 2

Hello all, today I want to share a problem which comes in many forms of counting the number of sequences subject to some constraints on the elements of the sequence. The problem goes like following. link to problem statement
-------------------------------------------------------------------

Problem Statement

Hero likes some arrays. The arrays he likes are the arrays that have all of the following properties:

  • The length of the array is n.
  • Each element is an integer between 1 and k, inclusive.
  • Whenever A and B are two consecutive elements of the array (in this order), we have (A <= B) or (A mod B != 0).

For example, suppose n=4 and k=7. Hero will like the array {1,7,7,2} because it has the right length, all elements are in the correct range, 1 <= 7, 7 <= 7, and 7 mod 2 != 0. Hero will not like the array {4,4,4,2}.

You are given the ints n and k. Let X be the number of different arrays Hero likes. Compute and return the value (X mod 1,000,000,007).
---------------------------------------------------------------------

Solution

What approach do you have in mind ? I approached it as dynamic programming problem.
Let us consider a function fi,jf_{i,j} denoting the number of sequences such that it has size equal to i and it ends at jj. A1,A2,A3,A4,.......Ai=jAxAx+1A_{1}, A_{2}, A_{3}, A_{4}, .......A_{i}=j | A_{x} \le A_{x+1} or AxmodAx+1!=0A_{x} mod A_{x+1} != 0 x<i\forall x \lt i

Now let us try to form a recurrence relation for fi,jf_{i,j}. We know that fi,jf_{i,j} can be reached from fi1,1,fi1,2,fi1,3.......fi1,jf_{i-1,1},f_{i-1,2},f_{i-1,3}.......f_{i-1,j} as all these will form valid states. Other than these we also have some states which can land us upto fi,jf_{i,j} like any state which is greater than jj let’s say p and jj does not divide it as in this case fi1,pf_{i-1,p} can lead us to fi,jf_{i,j}.

So, if we try to write it mathematically we get a clear idea.
fi,j=t=1t=jfi1,t+t=j+1t=kfi1,tt mod j!=0f_{i,j} = \sum_{t=1}^{t=j}f_{i-1,t} + \sum_{t=j+1}^{t=k}f_{i-1,t} \mid t\ mod\ j !=0
This seems perfect with only one problem that the time complexity to calculate this recurrence is clearly O(k)O(k) and It seems overall complexity of this solution is O(n.k2)O(n.k^2) which is an obvious case of Time Limit Exceeded.

Now the question remains is how to reduce it? One observation we can make while seeing the recurrence is what if we do a t=1t=kfi1,t\sum_{t=1}^{t=k}f_{i-1,t} . This includes all the cases in above recurrence as well as some extra terms like those states of t where t mod j==0t\ mod \ j == 0. So in all we need to subtract these cases. Since these cases will be very few like for t=2t=2 there will be approximate k/2k/2 cases for t=3t=3 approximate k/3k/3 cases and so on, so overall complexity for each substructure will be O(logk)O(logk). Check this link for detailed analysis here.

By storing sum of all previous t=1t=kfi1,t\sum_{t=1}^{t=k}f_{i-1,t} we can get rid of loop. we will need just one loop for iterating over those multiplicants of jj greater than j and less than eqaul to kk and subtract them from our stored sum . Therefore overall complexity is O(n.k.logk)O(n.k.logk), which is good enough to pass. Let us see the implementation.

include <bits/stdc++.h>
#define mod 1000000007
using namespace std;
typedef vector<int> vi;
typedef vector< vi > vvi;
 
class DivFreed2 {
 public:
 int count(int n, int k) {
  int f[100005][15];
  int sum =0 ; 
  vvi div(100005);
  for(int i=1;i<=k;i++){
   for(int j=2*i ; j<=k ; j+=i){
    if(j%i == 0 ){
     div[i].push_back(j);
    }
   }
  }
  for(int i=1; i<=k ; i++){
   f[i][1] = 1;
  }
  sum = k;
  int newsum=k;
  for(int col=2 ; col<=n ; col++){
   int tmp=sum;
   newsum = 0;
   for(int row = 1; row<=k ; row++){
    for(int t = 0 ; t < div[row].size() ; t++){
     tmp = (tmp - f[div[row][t]][col-1]+mod)%mod;
    }
    f[row][col] = (tmp+mod)%mod;
    tmp = sum;
    newsum =  (newsum+f[row][col])%mod;
   }
   sum = newsum;
  }
  return newsum;
 }
};

I enjoyed solving this problem, I hope you enjoyed it too. See you all in the next post. Thank you.

Comments

Popular posts from this blog

Solving CodeChef June Long Challenge Problem "PRMQ" using Segment Tree

Hello folks. Hope you are having a good time. I wanted to share my solution to CodeChef June '17 problem   PRMQ . Though there might be many solutions possible to this problem, I will walk you through a Segment-Tree solution for this. Approach There are nearly 78,000 prime numbers between 1 and 10^6, so in worst case a number in this query range L to R can have maximum of 8 prime numbers as the number of factors. Why 8 see 2*3*5*7*11*13*17*19 > 10^6 . And the root node can have maximum of 78,000 nodes with each prime number in the leaf node merging to form the root node. Now let us think what we should store in a node of segment tree. We may need the following information:- 1. The element of the array so as to compute their prime factors. 2. Some way to combine the factors of each element as key and their count as value, suppose we are having 2 elements say 8 and 9 so when we merge these node in the tree, we have got 2 as a factor with count 3 and 3 as a factor with

Modular Exponentiation

Just wanted to introduce you to very basic concept of Modular Exponentiation through a problem,  Big Mod . We need to calculate A^B % M for large inputs. For a second let's forget about A^B  % M and think about A^B only and say A^B lies within the range of long long int and B is less than 10^7. A basic brute force approach to calculate A^B will be to loop through 1 to B and multiply A every time. The time complexity of this approach is O(n). This is perfect on current constraints but what happens if I change the constraint on B and raise it to 10^12 or so. Now  this approach will give a TLE. An efficient approach is needed. O(n) is not sufficient. We will use a recursive approach for this. Suppose I want to calculate A^B but if B is even, I can calculate A^(B/2) and multiply it to itself, and the way to calculate A^(B/2) is to calculate A^(B/4) and so on you get the idea. But what if B is not even, no problem,  B-1 will be even do the same except replace B with B-1 and separ