Count the number of ways to give ranks for N students such that same ranks are possible
Last Updated :
12 Apr, 2023
Given the number N which represents the number of students, the task is to calculate all possible ways to rank them according to their CGPA/marks, considering that two or more students can have the same rank. Since the answer can be large, perform the modulo with 109 + 7.
Examples:
Input: N = 1
Output: 1
Explanation:
There is only one way to rank a student, irrespective of his marks.
Input: N = 2
Output: 3
Explanation:
First way : if A and B student Got same marks, then Let say A has got higher rank than B .
Second Way : if A and B student Got same marks, then Let say B has got higher rank than A .
Third way: If both got different, Then the person got higher mark , will get higher rank.
Approach: The idea for this problem is to use the Bell Numbers.
- A bell number is a number that counts the possible partitions of a set. Therefore, an N-th bell number is a number of non-empty subsets a set of size N can be partitioned into.
- For example, let’s consider the set {1, 2, 3} for N = 3. The bell number corresponding to N = 3 is 5. This signifies that the given set can be partitioned into the following 5 non-empty subsets:
{{1}, {2}, {3}}
{{1, 2}, {3}}
{{1, 3}, {2}}
{{2, 3}, {1}}
{{1, 2, 3}}
- Clearly, the above bell numbers signify all the possible ranks. However, they do not calculate the permutations of the subset.
- Therefore, by multiplying every subset with K!, where K denotes the size of the respective subset, we get all the possible arrangements.
- As the same subproblems can be repeated, we can store the values of each subproblem in a data structure to optimize the complexity.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
vector<vector< int > > dp;
int f( int n, int k)
{
if (n < k)
return 0;
if (n == k)
return 1;
if (k == 1)
return 1;
if (dp[n][k] != -1)
return dp[n][k];
return dp[n][k] = ((k * f(n - 1, k)) % mod
+ (f(n - 1, k - 1)) % mod)
% mod;
}
long operation( int n)
{
dp.resize(n + 1, vector< int >(n + 1, -1));
long ans = 0, fac = 1;
for ( int k = 1; k <= n; k++) {
fac *= k;
ans = (ans + (fac * f(n, k)) % mod)
% mod;
}
return ans;
}
int main()
{
int n = 5;
cout << operation(n) << endl;
return 0;
}
|
Java
import java.util.*;
class GFG{
static int mod = ( int )(1e9 + 7 );
static int [][]dp;
static int f( int n, int k)
{
if (n < k)
return 0 ;
if (n == k)
return 1 ;
if (k == 1 )
return 1 ;
if (dp[n][k] != - 1 )
return dp[n][k];
return dp[n][k] = ((k * f(n - 1 , k)) % mod +
(f(n - 1 , k - 1 )) % mod) % mod;
}
static long operation( int n)
{
dp = new int [n + 1 ][n + 1 ];
for ( int i = 0 ; i < n + 1 ; i++)
{
for ( int j = 0 ; j < n + 1 ; j++)
{
dp[i][j] = - 1 ;
}
}
long ans = 0 , fac = 1 ;
for ( int k = 1 ; k <= n; k++)
{
fac *= k;
ans = (ans + (fac * f(n, k)) % mod) % mod;
}
return ans;
}
public static void main(String[] args)
{
int n = 5 ;
System.out.print(operation(n) + "\n" );
}
}
|
Python3
mod = 1e9 + 7
dp = [[ - 1 for x in range ( 6 )]
for y in range ( 6 )]
def f(n, k):
if (n < k):
return 0
if (n = = k):
return 1
if (k = = 1 ):
return 1
if (dp[n][k] ! = - 1 ):
return dp[n][k]
dp[n][k] = ((((k * f(n - 1 , k)) % mod +
(f(n - 1 , k - 1 )) % mod) % mod))
return dp[n][k]
def operation(n):
global dp
ans = 0
fac = 1
for k in range ( 1 , n + 1 ):
fac * = k
ans = (ans + (fac * f(n, k)) % mod) % mod
return ans
if __name__ = = "__main__" :
n = 5
print ( int (operation(n)))
|
C#
using System;
class GFG{
static int mod = ( int )(1e9 + 7);
static int [,]dp;
static int f( int n, int k)
{
if (n < k)
return 0;
if (n == k)
return 1;
if (k == 1)
return 1;
if (dp[n, k] != -1)
return dp[n, k];
return dp[n, k] = ((k * f(n - 1, k)) % mod +
(f(n - 1, k - 1)) % mod) % mod;
}
static long operation( int n)
{
dp = new int [n + 1, n + 1];
for ( int i = 0; i < n + 1; i++)
{
for ( int j = 0; j < n + 1; j++)
{
dp[i, j] = -1;
}
}
long ans = 0, fac = 1;
for ( int k = 1; k <= n; k++)
{
fac *= k;
ans = (ans + (fac * f(n, k)) % mod) % mod;
}
return ans;
}
public static void Main(String[] args)
{
int n = 5;
Console.Write(operation(n) + "\n" );
}
}
|
Javascript
<script>
var mod = parseInt( 1e9 + 7);
var dp;
function f(n , k) {
if (n < k)
return 0;
if (n == k)
return 1;
if (k == 1)
return 1;
if (dp[n][k] != -1)
return dp[n][k];
return dp[n][k] = ((k * f(n - 1, k)) % mod +
(f(n - 1, k - 1)) % mod) % mod;
}
function operation(n) {
dp = Array(n + 1).fill().map(()
=>Array(n + 1).fill(0));
for (i = 0; i < n + 1; i++) {
for (j = 0; j < n + 1; j++) {
dp[i][j] = -1;
}
}
var ans = 0, fac = 1;
for (k = 1; k <= n; k++) {
fac *= k;
ans = (ans + (fac * f(n, k)) % mod) % mod;
}
return ans;
}
var n = 5;
document.write(operation(n) + "\n" );
</script>
|
Time Complexity: O(N*N)
Auxiliary Space: O(N*N)
Efficient approach: Using DP Tabulation method ( Iterative approach )
The approach to solving this problem is the same but DP tabulation(bottom-up) method is better the Dp + memorization(top-down) because memorization method needs extra stack space of recursion calls.
Steps to solve this problem:
- Create a vector to store the solution of the subproblems.
- Initialize the table with base cases
- Fill up the table iteratively.
- Return the final solution
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int operation( int n)
{
vector<vector< int > > dp(n + 1, vector< int >(n + 1));
for ( int i = 0; i <= n; i++) {
dp[i][0] = 0;
dp[i][i] = 1;
}
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j < i; j++) {
dp[i][j] = (j * dp[i - 1][j] + dp[i - 1][j - 1])
% mod;
}
dp[i][i] = 1;
}
long ans = 0, fac = 1;
for ( int k = 1; k <= n; k++) {
fac *= k;
ans = (ans + (fac * dp[n][k]) % mod) % mod;
}
return ans;
}
int main()
{
int n = 5;
cout << operation(n) << endl;
return 0;
}
|
Java
import java.util.*;
public class Main {
static final int mod = 1000000007 ;
static int operation( int n) {
int [][] dp = new int [n+ 1 ][n+ 1 ];
for ( int i = 0 ; i <= n; i++) {
dp[i][ 0 ] = 0 ;
dp[i][i] = 1 ;
}
for ( int i = 1 ; i <= n; i++) {
for ( int j = 1 ; j < i; j++) {
dp[i][j] = (j * dp[i- 1 ][j] + dp[i- 1 ][j- 1 ]) % mod;
}
dp[i][i] = 1 ;
}
long ans = 0 , fac = 1 ;
for ( int k = 1 ; k <= n; k++) {
fac *= k;
ans = (ans + (fac * dp[n][k]) % mod) % mod;
}
return ( int )ans;
}
public static void main(String[] args) {
int n = 5 ;
System.out.println(operation(n));
}
}
|
Python
mod = 10 * * 9 + 7
def operation(n):
dp = [[ 0 for j in range (n + 1 )] for i in range (n + 1 )]
for i in range (n + 1 ):
dp[i][ 0 ] = 0
dp[i][i] = 1
for i in range ( 1 , n + 1 ):
for j in range ( 1 , i):
dp[i][j] = (j * dp[i - 1 ][j] + dp[i - 1 ][j - 1 ]) % mod
dp[i][i] = 1
ans, fac = 0 , 1
for k in range ( 1 , n + 1 ):
fac * = k
ans = (ans + (fac * dp[n][k]) % mod) % mod
return ans
n = 5
print (operation(n))
|
C#
using System;
using System.Collections.Generic;
class Solution {
static int mod = 1000000007;
static int operation( int n)
{
int [][] dp = new int [n + 1][];
for ( int i = 0; i <= n; i++) {
dp[i] = new int [n + 1];
dp[i][0] = 0;
dp[i][i] = 1;
}
for ( int i = 1; i <= n; i++) {
for ( int j = 1; j < i; j++) {
dp[i][j]
= (j * dp[i - 1][j] + dp[i - 1][j - 1])
% mod;
}
dp[i][i] = 1;
}
long ans = 0, fac = 1;
for ( int k = 1; k <= n; k++) {
fac *= k;
ans = (ans + (fac * dp[n][k]) % mod) % mod;
}
return ( int )ans;
}
static void Main( string [] args)
{
int n = 5;
Console.WriteLine(operation(n));
}
}
|
Javascript
const mod = 10**9 + 7;
function operation(n) {
let dp = Array.from(Array(n+1), () => new Array(n+1).fill(0));
for (let i = 0; i <= n; i++) {
dp[i][0] = 0;
dp[i][i] = 1;
}
for (let i = 1; i <= n; i++) {
for (let j = 1; j < i; j++) {
dp[i][j] = (j * dp[i-1][j] + dp[i-1][j-1]) % mod;
}
dp[i][i] = 1;
}
let ans = 0, fac = 1;
for (let k = 1; k <= n; k++) {
fac *= k;
ans = (ans + (fac * dp[n][k]) % mod) % mod;
}
return ans;
}
let n = 5;
console.log(operation(n));
|
Time Complexity: O(N*N)
Auxiliary Space: O(N*N)
Share your thoughts in the comments
Please Login to comment...