Count the number of special permutations
Given two positive integers n and k, the task is to count the number of special permutations. A special permutation P is defined as a permutation of first n natural numbers in which there exists at least (n – k) indices such that Pi = i.
Prerequisite: Derangements
Examples:
Input: n = 4, k = 2
Output: 7
{1, 2, 3, 4}, {1, 2, 4, 3}, {4, 2, 3, 1}, {2, 1, 3, 4}, {1, 4, 3, 2}, {1, 3, 2, 4} and {3, 2, 1, 4} are the only possible special permutations.
Input: n = 5, k = 3
Output: 31
Approach: Let the function fx denote the number of special permutations in which there exists exactly x indices such that Pi = i. Hence, the required answer will be:
f(n – k) + f(n – k + 1) + f(n – k + 2) + … + f(n – 1) + fn
Now, fx can be calculated by choosing x indices from n where Pi = i and calculating the number of derangements for (n – i) other indices as for them Pi should not be equal to i then multiplying the result by nCx as there can be different ways to select x indices from n.
Steps to solve the problem:
- Define a function nCr to calculate the number of combinations of n items taken r at a time using the formula n! / (r! * (n-r)!)
- Define a function countDerangements to calculate the number of derangements of n items using the formula der(n) = (n-1) * (der(n-1) + der(n-2)) where der(0) = 1 and der(1) = 0.
- Define a function countPermutations to calculate the number of permutations of n items where no more than k items are in their original positions using the following steps.
- Initialize a variable ans to 0.
- Loop through i from n-k to n.
- Calculate the number of ways to choose i items from n items using the nCr function.
- Calculate the number of derangements of n-i items using the countDerangements function.
- Multiply the number of ways and the number of derangements and add the result to and.
- Return ans as the result of the function.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
int nCr( int n, int r)
{
int ans = 1;
if (r > n - r)
r = n - r;
for ( int i = 0; i < r; i++) {
ans *= (n - i);
ans /= (i + 1);
}
return ans;
}
int countDerangements( int n)
{
int der[n + 1];
der[0] = 1;
der[1] = 0;
der[2] = 1;
for ( int i = 3; i <= n; i++)
der[i] = (i - 1) * (der[i - 1]
+ der[i - 2]);
return der[n];
}
ll countPermutations( int n, int k)
{
ll ans = 0;
for ( int i = n - k; i <= n; i++) {
int ways = nCr(n, i);
ans += ways * countDerangements(n - i);
}
return ans;
}
int main()
{
int n = 5, k = 3;
cout << countPermutations(n, k);
return 0;
}
|
Java
public class GFG{
static int nCr( int n, int r)
{
int ans = 1 ;
if (r > n - r)
r = n - r;
for ( int i = 0 ; i < r; i++) {
ans *= (n - i);
ans /= (i + 1 );
}
return ans;
}
static int countDerangements( int n)
{
int der[] = new int [ n + 3 ];
der[ 0 ] = 1 ;
der[ 1 ] = 0 ;
der[ 2 ] = 1 ;
for ( int i = 3 ; i <= n; i++)
der[i] = (i - 1 ) * (der[i - 1 ]
+ der[i - 2 ]);
return der[n];
}
static int countPermutations( int n, int k)
{
int ans = 0 ;
for ( int i = n - k; i <= n; i++) {
int ways = nCr(n, i);
ans += (ways * countDerangements(n- i));
}
return ans;
}
public static void main(String []args)
{
int n = 5 , k = 3 ;
System.out.println(countPermutations(n, k)) ;
}
}
|
Python3
def nCr(n, r):
ans = 1
if r > n - r:
r = n - r
for i in range (r):
ans * = (n - i)
ans / = (i + 1 )
return ans
def countDerangements(n):
der = [ 0 for i in range (n + 3 )]
der[ 0 ] = 1
der[ 1 ] = 0
der[ 2 ] = 1
for i in range ( 3 , n + 1 ):
der[i] = (i - 1 ) * (der[i - 1 ] +
der[i - 2 ])
return der[n]
def countPermutations(n, k):
ans = 0
for i in range (n - k, n + 1 ):
ways = nCr(n, i)
ans + = ways * countDerangements(n - i)
return ans
n, k = 5 , 3
print (countPermutations(n, k))
|
C#
using System;
public class GFG{
static int nCr( int n, int r)
{
int ans = 1;
if (r > n - r)
r = n - r;
for ( int i = 0; i < r; i++) {
ans *= (n - i);
ans /= (i + 1);
}
return ans;
}
static int countDerangements( int n)
{
int []der = new int [ n + 3];
der[0] = 1;
der[1] = 0;
der[2] = 1;
for ( int i = 3; i <= n; i++)
der[i] = (i - 1) * (der[i - 1]
+ der[i - 2]);
return der[n];
}
static int countPermutations( int n, int k)
{
int ans = 0;
for ( int i = n - k; i <= n; i++) {
int ways = nCr(n, i);
ans += (ways * countDerangements(n- i));
}
return ans;
}
public static void Main()
{
int n = 5, k = 3;
Console.WriteLine(countPermutations(n, k)) ;
}
}
|
Javascript
<script>
function nCr(n, r) {
var ans = 1;
if (r > n - r) r = n - r;
for ( var i = 0; i < r; i++) {
ans *= n - i;
ans /= i + 1;
}
return ans;
}
function countDerangements(n) {
var der = [...Array(n + 1)];
der[0] = 1;
der[1] = 0;
der[2] = 1;
for ( var i = 3; i <= n; i++)
der[i] = (i - 1) * (der[i - 1] + der[i - 2]);
return der[n];
}
function countPermutations(n, k) {
var ans = 0;
for ( var i = n - k; i <= n; i++) {
var ways = nCr(n, i);
ans += ways * countDerangements(n - i);
}
return ans;
}
var n = 5,
k = 3;
document.write(countPermutations(n, k));
</script>
|
PHP
<?php
function nCr( $n , $r )
{
$ans = 1;
if ( $r > $n - $r )
$r = $n - $r ;
for ( $i = 0; $i < $r ; $i ++)
{
$ans *= ( $n - $i );
$ans /= ( $i + 1);
}
return $ans ;
}
function countDerangements( $n )
{
$der = array ( $n + 1);
$der [0] = 1;
$der [1] = 0;
$der [2] = 1;
for ( $i = 3; $i <= $n ; $i ++)
$der [ $i ] = ( $i - 1) *
( $der [ $i - 1] +
$der [ $i - 2]);
return $der [ $n ];
}
function countPermutations( $n , $k )
{
$ans = 0;
for ( $i = $n - $k ; $i <= $n ; $i ++)
{
$ways = nCr( $n , $i );
$ans += $ways * countDerangements( $n - $i );
}
return $ans ;
}
$n = 5;
$k = 3;
echo (countPermutations( $n , $k ));
?>
|
Time Complexity: O(N^2), since there runs a loop inside another loop.
Auxiliary Space: O(N), since N extra space has been taken.
Efficient approach : Space optimization O(1)
In previous approach we the current value dp[i] is only depend upon the previous 2 values i.e. dp[i-1] and dp[i-2]. So to optimize the space we can keep track of previous and current values by the help of three variables prev1, prev2 and curr which will reduce the space complexity from O(N) to O(1).
Implementation Steps:
- Create 2 variables prev1 and prev2 to keep track o previous values of DP.
- Initialize base case prev1 = 0 and prev2 = 1.
- Create a variable curr to store current value.
- Iterate over subproblem using loop and update curr.
- After every iteration update prev1 and prev2 for further iterations.
- At last return curr.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
int nCr( int n, int r)
{
int ans = 1;
if (r > n - r)
r = n - r;
for ( int i = 0; i < r; i++) {
ans *= (n - i);
ans /= (i + 1);
}
return ans;
}
int countDerangements( int n)
{
int prev0=1 , prev1=0 , prev2=1;
int curr;
if (n == 0)
return prev0;
if (n == 1)
return prev1;
if (n == 2)
return prev2;
for ( int i = 3; i <= n; i++){
curr = (i-1) * ( prev2 + prev1 ) ;
prev1 = prev2;
prev2 = curr;
}
return curr;
}
ll countPermutations( int n, int k)
{
ll ans = 0;
for ( int i = n - k; i <= n; i++) {
int ways = nCr(n, i);
ans += ways * countDerangements(n - i);
}
return ans;
}
int main()
{
int n = 5, k = 3;
cout << countPermutations(n, k);
return 0;
}
|
Java
import java.util.*;
public class Main {
public static int nCr( int n, int r) {
int ans = 1 ;
if (r > n - r)
r = n - r;
for ( int i = 0 ; i < r; i++) {
ans *= (n - i);
ans /= (i + 1 );
}
return ans;
}
public static int countDerangements( int n) {
int prev0= 1 , prev1= 0 , prev2= 1 ;
int curr;
if (n == 0 )
return prev0;
if (n == 1 )
return prev1;
if (n == 2 )
return prev2;
for ( int i = 3 ; i <= n; i++){
curr = (i- 1 ) * ( prev2 + prev1 ) ;
prev1 = prev2;
prev2 = curr;
}
return prev2;
}
public static long countPermutations( int n, int k) {
long ans = 0 ;
for ( int i = n - k; i <= n; i++) {
int ways = nCr(n, i);
ans += ways * countDerangements(n - i);
}
return ans;
}
public static void main(String[] args) {
int n = 5 , k = 3 ;
System.out.println(countPermutations(n, k));
}
}
|
Python
import math
def nCr(n, r):
ans = 1
if (r > n - r):
r = n - r
for i in range (r):
ans * = (n - i)
ans / / = (i + 1 )
return ans
def countDerangements(n):
prev0, prev1, prev2 = 1 , 0 , 1
if n = = 0 :
return prev0
if n = = 1 :
return prev1
if n = = 2 :
return prev2
for i in range ( 3 , n + 1 ):
curr = (i - 1 ) * (prev2 + prev1)
prev1 = prev2
prev2 = curr
return curr
def countPermutations(n, k):
ans = 0
for i in range (n - k, n + 1 ):
ways = nCr(n, i)
ans + = ways * countDerangements(n - i)
return ans
if __name__ = = '__main__' :
n = 5
k = 3
print (countPermutations(n, k))
|
C#
using System;
public class Program
{
static int nCr( int n, int r)
{
int ans = 1;
if (r > n - r)
r = n - r;
for ( int i = 0; i < r; i++)
{
ans *= (n - i);
ans /= (i + 1);
}
return ans;
}
static int CountDerangements( int n)
{
int prev0 = 1, prev1 = 0, prev2 = 1;
int curr = 0;
if (n == 0)
return prev0;
if (n == 1)
return prev1;
if (n == 2)
return prev2;
for ( int i = 3; i <= n; i++)
{
curr = (i - 1) * (prev2 + prev1);
prev1 = prev2;
prev2 = curr;
}
return curr;
}
static long CountPermutations( int n, int k)
{
long ans = 0;
for ( int i = n - k; i <= n; i++)
{
int ways = nCr(n, i);
ans += ways * CountDerangements(n - i);
}
return ans;
}
public static void Main()
{
int n = 5, k = 3;
Console.WriteLine(CountPermutations(n, k));
}
}
|
Javascript
function nCr(n, r) {
let ans = 1;
if (r > n - r)
r = n - r;
for (let i = 0; i < r; i++) {
ans *= (n - i);
ans /= (i + 1);
}
return ans;
}
function countDerangements(n) {
let prev0 = 1, prev1 = 0, prev2 = 1;
let curr;
if (n === 0)
return prev0;
if (n === 1)
return prev1;
if (n === 2)
return prev2;
for (let i = 3; i <= n; i++) {
curr = (i - 1) * (prev2 + prev1);
prev1 = prev2;
prev2 = curr;
}
return curr;
}
function countPermutations(n, k) {
let ans = 0;
for (let i = n - k; i <= n; i++) {
let ways = nCr(n, i);
ans += ways * countDerangements(n - i);
}
return ans;
}
let n = 5, k = 3;
console.log(countPermutations(n, k));
|
Time Complexity: O(N^2), since there runs a loop inside another loop.
Auxiliary Space: O(1), since no extra space is used.
Last Updated :
02 Oct, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...