Open In App

Find the number of subsequences of N friends

Last Updated : 29 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given two arrays A[] and B[] of length N and M respectively. A[] represents the age of N friends and B[] contains M number of pairs in the form of (X → Y), which denotes X knows Y and vice-versa. Then your task is to output the count of all possible sequences of length N friends with the given condition If (X → Y) and AX < AY, then in the sequence AX must appear before AY.

Note:

  • Since the number of sequences can be large, therefore use modulo 109+7.
  • If three people let say A, B and C are there. Where A → B and B → C, then A →C also hold true.
  • The person who is not known of any other person can appear anywhere in the sequence irrespective of its age.

Examples:

Input: N = 5, M = 5, A[] = {12, 14, 17, 22, 15}, B[] = {{1 → 2}, {2 → 3}, {3 → 4}, {4 → 2}, {3 → 1}}

t1

First Input Test case

Output: 5
Explanation: Following the given constraints there will be 5 such sequences, which are:

  • First sequence of 1 to N friends: [5, 1, 2, 3, 4]. Then age sequence will be: [A5, A1, A2, A3, A4] = {15, 12, 14, 17, 22}
  • Second sequence: [1, 5, 2, 3, 4]. Then age sequence: [A1, A5, A2, A3, A4] = {12, 15, 14, 17, 22}
  • Third sequence: [1, 2, 5, 3, 4]. Then age sequence: [A1, A2, A5, A3, A4] = {12, 14, 15, 17, 22}
  • Fourth sequence: [1, 2, 3, 5, 4]. Then age sequence: [A1, A2, A3, A5, A4] = {12, 14, 17, 15, 22}
  • Fifth sequence: [1, 2, 3, 4, 5]. Then age sequence: [A1, A2, A3, A4, A5] = {12, 14, 17, 22, 15}

It can be seen that 1, 2, 3 and 4 knows each other and their order of age is according to given constraints while 5th is unknown for all others and its order not matters in sequence. This these 5 will be the age sequences according to given constraints. Therefore, output is 5.

Input: N = 2, M = 1, A[] = {2, 2}, B[] = {{1 → 2}}
Output: 2
Explanation: There will be 2 such age sequences possible: {A1, A2} and {A2, A1} . They both have same age and knows each other also. Therefore, there will be two sequences. Note that, if they don’t know each other then also the sequences will be same as this case.

Approach: Implement the idea below to solve the problem

The problem is based on the Graph Theory and Combinatorics. The problem can be solved using concept of DFS and Factorial. In this problem, DFS is used to visit each node exactly once and calculate the number of ways to place each person in the sequence considering their friends who have already been placed. Factorials are used for counting sequences. It represents the number of ways to arrange N distinct items into a sequence, which is why it’s used here.

The final result, which is the total number of sequences counted under the modulo 10^9+7.

Total Arrangements: There are N! ways to arrange all the ages. This comes from the basic principle of permutations in combinatorics, Maintaining Relative Order: The relative sorted ordering of ages of each connected component should be maintained. This means that for each connected component, we divide by X!, where X! is the number of elements in the ith connected component. This is because within each connected component, the elements can be arranged in X! ways, but these arrangements do not produce distinct sequences due to the ordering constraint of ages.

Equal Strengths: Some elements that have ages equal in a connected component can be arranged in Y! ways. Here, Y! is the number of equal ages in the ith connected component. These arrangements produce distinct sequences because the strength ordering constraint does not apply to elements with equal ages.

So, the total number of possible sequences is given by the formula:

  • (N!*Y!/X!)

Steps were taken to solve the problem:

  • Precompute Factorials: Initialize an array let say Fac[] to store the factorial of numbers up to 2e5. This will be used later for combinatorics calculations.
  • Graph Construction: Read the friendship pairs from B[] and construct an adjacency list representation of the graph let say Adj.
  • DFS and Calculation: For each node, If it has not been visited, perform a DFS starting from that node. During the DFS, keep track of the count of each value in a HashMap let say Map. After the DFS, calculate the result using factorials and modular arithmetic.
  • Results: Output the number of ways calculated using factorials.

Code to implement the approach:

C++




// C++ code for the above approach:
#include <iostream>
#include <unordered_map>
#include <vector>
 
using namespace std;
 
// Define the modulo constant
const long long modulo = 1000000007;
 
// Function prototypes
long long power(long long a, long long b,
                long long curr_mod);
void dfs(int i, vector<vector<int> >& adj,
        vector<bool>& vis, vector<long long>& ar,
        unordered_map<long long, long long>& hm);
void Count_sequences(int N, int M, vector<long long>& A,
                    vector<vector<int> >& B,
                    vector<long long>& fac);
 
int main()
{
    // Precompute factorials up to 2e5
    vector<long long> fac(200001, 0);
    fac[0] = 1;
    for (int i = 1; i <= 200000; i++)
        fac[i] = (fac[i - 1] * i) % modulo;
 
    // Read the number of nodes and edges
    int N = 5;
    int M = 5;
    vector<long long> A = { 10, 12, 15, 20, 15 };
    vector<vector<int> > B = {
        { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 2 }, { 3, 1 }
    };
 
    // Function call
    Count_sequences(N, M, A, B, fac);
 
    return 0;
}
 
// Function to output the
// number of sequences
void Count_sequences(int N, int M, vector<long long>& A,
                    vector<vector<int> >& B,
                    vector<long long>& fac)
{
    // Initialize adjacency list,
    // visited array, and ar array
    vector<vector<int> > adj(N);
 
    // Visiting array created for DFS
    vector<bool> Vis(N, false);
 
    // Constructing the graph
    for (int i = 0; i < N; i++)
        adj[i] = vector<int>();
 
    // Creating adjacency list
    for (int i = 0; i < M; i++) {
        int u = B[i][0] - 1;
        int v = B[i][1] - 1;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
 
    // Initialize result and x
    long long res = 1;
    int x = 0;
 
    // Perform DFS and calculate
    // result for each node
    for (int i = 0; i < N; i++) {
        if (!Vis[i]) {
            unordered_map<long long, long long> Map;
            dfs(i, adj, Vis, A, Map);
            long long mul = 1, cn = 0;
            for (const auto& set : Map) {
                cn += set.second;
                long long xx = set.second;
                mul = (mul * fac[xx]) % modulo;
            }
            int inn = static_cast<int>(cn);
            long long y = fac[x + inn];
            long long d1
                = (power(fac[x], modulo - 2, modulo)
                * power(fac[inn], modulo - 2, modulo))
                % modulo;
            long long fraction = (y * d1) % modulo;
            res = (res * ((fraction * mul) % modulo))
                % modulo;
            x += inn;
        }
    }
 
    // Print the result
    cout << res << endl;
}
 
// Function to calculate (a^b) mod curr_mod
// using binary exponentiation
long long power(long long a, long long b,
                long long curr_mod)
{
    if (b == 0)
        return 1;
    long long temp = power(a, b / 2, curr_mod) % curr_mod;
 
    if ((b & 1) == 0)
        return (temp * temp) % curr_mod;
    else
        return (((temp * temp) % curr_mod) * a) % curr_mod;
}
 
// DFS function to traverse the graph
// and update HashMap and Visiting array
void dfs(int i, vector<vector<int> >& adj,
        vector<bool>& vis, vector<long long>& ar,
        unordered_map<long long, long long>& hm)
{
    vis[i] = true;
    hm[ar[i]] += 1;
    for (int it : adj[i]) {
        if (!vis[it])
            dfs(it, adj, vis, ar, hm);
    }
}


Java




// Java code to implement the approach
 
import java.util.*;
 
// Driver Class
class GFG {
    // Define the modulo constant
    static long modulo = 1000000007;
 
    // Driver Function
    public static void main(String[] args)
    {
        // Precompute factorials up to 2e5
        long fac[] = new long[(int)2e5 + 1];
        fac[0] = 1;
        for (int i = 1; i <= (int)2e5; i++)
            fac[i] = (fac[i - 1] * i) % modulo;
 
        // Read the number of nodes and edges
        int N = 5;
        int M = 5;
        long A[] = { 10, 12, 15, 20, 15 };
        int[][] B = {
            { 1, 2 }, { 2, 3 }, { 3, 4 }, { 4, 2 }, { 3, 1 }
        };
 
        // Function call
        Count_sequences(N, M, A, B, fac);
    }
 
    // Method to output the number of sequences
    public static void Count_sequences(int N, int M,
                                       long A[], int[][] B,
                                       long[] fac)
    {
        // Initialize adjacency list, visited array, and ar
        // array
        ArrayList<ArrayList<Integer> > adj
            = new ArrayList<>();
 
        // Visiting array created for DFS
        boolean Vis[] = new boolean[N];
 
        // Constructing the graph
        for (int i = 0; i < N; i++)
            adj.add(new ArrayList<>());
 
        // Creating adjacncy list
        for (int i = 0; i < M; i++) {
            int u = B[i][0] - 1;
            int v = B[i][1] - 1;
            adj.get(u).add(v);
            adj.get(v).add(u);
        }
 
        // Initialize result and x
        long res = 1;
        int x = 0;
 
        // Perform DFS and calculate result for each node
        for (int i = 0; i < N; i++) {
            if (!Vis[i]) {
                HashMap<Long, Long> Map = new HashMap<>();
                dfs(i, adj, Vis, A, Map);
                long mul = 1, cn = 0;
                for (Map.Entry<Long, Long> set :
                     Map.entrySet()) {
                    cn += set.getValue();
                    long xx = set.getValue();
                    mul = (mul * fac[(int)xx]) % modulo;
                }
                int inn = (int)cn;
                long y = fac[x + inn];
                long d1 = (power(fac[x], modulo - 2, modulo)
                           * power(fac[inn], modulo - 2,
                                   modulo))
                          % modulo;
                long fraction = (y * d1) % modulo;
                res = (res * ((fraction * mul) % modulo))
                      % modulo;
                x += inn;
            }
        }
 
        // Print the result
        System.out.println(res);
    }
 
    // Function to calculate (a^b) mod curr_mod using binary
    // exponentiation
    public static long power(long a, long b, long curr_mod)
    {
        if (b == 0)
            return 1;
        long temp = power(a, b / 2, curr_mod) % curr_mod;
 
        if ((b & 1) == 0)
            return (temp * temp) % curr_mod;
        else
            return (((temp * temp) % curr_mod) * a)
                % curr_mod;
    }
 
    // DFS function to traverse the graph and update HashMap
    // and Visiting array
    public static void
    dfs(int i, ArrayList<ArrayList<Integer> > adj,
        boolean vis[], long ar[], HashMap<Long, Long> hm)
    {
        vis[i] = true;
        hm.put(ar[i], hm.getOrDefault(ar[i], 0L) + 1);
        for (int it : adj.get(i)) {
            if (!vis[it])
                dfs(it, adj, vis, ar, hm);
        }
    }
}


Python




# code by Flutterfly
modulo = 1000000007
 
def main():
    fac = [0] * (int(2e5) + 1)
    fac[0] = 1
    for i in range(1, int(2e5) + 1):
        fac[i] = (fac[i - 1] * i) % modulo
     
    N = 5
    M = 5
    A = [10, 12, 15, 20, 15]
    B = [
        [1, 2], [2, 3], [3, 4], [4, 2], [3, 1]
    ]
     
    count_sequences(N, M, A, B, fac)
 
def count_sequences(N, M, A, B, fac):
    adj = [[] for _ in range(N)]
    Vis = [False] * N
     
    for i in range(M):
        u = B[i][0] - 1
        v = B[i][1] - 1
        adj[u].append(v)
        adj[v].append(u)
     
    res = 1
    x = 0
     
    for i in range(N):
        if not Vis[i]:
            Map = {}
            dfs(i, adj, Vis, A, Map)
            mul = 1
            cn = 0
            for key, value in Map.items():
                cn += value
                xx = value
                mul = (mul * fac[xx]) % modulo
            inn = int(cn)
            y = fac[x + inn]
            d1 = (power(fac[x], modulo - 2, modulo) * power(fac[inn], modulo - 2, modulo)) % modulo
            fraction = (y * d1) % modulo
            res = (res * ((fraction * mul) % modulo)) % modulo
            x += inn
     
    print(res)
 
def power(a, b, curr_mod):
    if b == 0:
        return 1
    temp = power(a, b // 2, curr_mod) % curr_mod
    if b % 2 == 0:
        return (temp * temp) % curr_mod
    else:
        return (((temp * temp) % curr_mod) * a) % curr_mod
 
def dfs(i, adj, vis, ar, hm):
    vis[i] = True
    hm[ar[i]] = hm.get(ar[i], 0) + 1
    for it in adj[i]:
        if not vis[it]:
            dfs(it, adj, vis, ar, hm)
 
main()


C#




//code by Flutterfly
using System;
using System.Collections.Generic;
 
class GFG
{
    static long modulo = 1000000007;
 
    public static void Main(string[] args)
    {
 
        long[] fac = new long[(int)2e5 + 1];
        fac[0] = 1;
        for (int i = 1; i <= (int)2e5; i++)
            fac[i] = (fac[i - 1] * i) % modulo;
 
        int N = 5;
        int M = 5;
        long[] A = { 10, 12, 15, 20, 15 };
        int[][] B = {
            new int[] { 1, 2 }, new int[] { 2, 3 }, new int[] { 3, 4 }, new int[] { 4, 2 }, new int[] { 3, 1 }
        };
 
        Count_sequences(N, M, A, B, fac);
    }
 
    public static void Count_sequences(int N, int M,
                                long[] A, int[][] B,
                                long[] fac)
    {
 
 
        List<List<int>> adj
            = new List<List<int>>();
 
        bool[] Vis = new bool[N];
 
        for (int i = 0; i < N; i++)
            adj.Add(new List<int>());
 
        for (int i = 0; i < M; i++)
        {
            int u = B[i][0] - 1;
            int v = B[i][1] - 1;
            adj[u].Add(v);
            adj[v].Add(u);
        }
 
        long res = 1;
        int x = 0;
 
        for (int i = 0; i < N; i++)
        {
            if (!Vis[i])
            {
                Dictionary<long, long> Map = new Dictionary<long, long>();
                dfs(i, adj, Vis, A, Map);
                long mul = 1, cn = 0;
                foreach (KeyValuePair<long, long> set in Map)
                {
                    cn += set.Value;
                    long xx = set.Value;
                    mul = (mul * fac[(int)xx]) % modulo;
                }
                int inn = (int)cn;
                long y = fac[x + inn];
                long d1 = (power(fac[x], modulo - 2, modulo)
                        * power(fac[inn], modulo - 2,
                                modulo))
                        % modulo;
                long fraction = (y * d1) % modulo;
                res = (res * ((fraction * mul) % modulo))
                    % modulo;
                x += inn;
            }
        }
 
        Console.WriteLine(res);
    }
 
 
    public static long power(long a, long b, long curr_mod)
    {
        if (b == 0)
            return 1;
        long temp = power(a, b / 2, curr_mod) % curr_mod;
        if ((b & 1) == 0)
            return (temp * temp) % curr_mod;
        else
            return (((temp * temp) % curr_mod) * a)
                % curr_mod;
    }
 
 
    public static void
    dfs(int i, List<List<int>> adj,
        bool[] vis, long[] ar, Dictionary<long, long> hm)
    {
        vis[i] = true;
        if (hm.ContainsKey(ar[i]))
            hm[ar[i]]++;
        else
            hm[ar[i]] = 1;
        foreach (int it in adj[i])
        {
            if (!vis[it])
                dfs(it, adj, vis, ar, hm);
        }
    }
}


Javascript




// JavaScript code for the above approach:
 
// Function to calculate (a^b) mod curr_mod using binary exponentiation
function power(a, b, curr_mod) {
    if (b === 0n) return 1n;
    const temp = power(a, b / 2n, curr_mod) % curr_mod;
    if (b % 2n === 0n) return (temp * temp) % curr_mod;
    else return (((temp * temp) % curr_mod) * a) % curr_mod;
}
 
// DFS function to traverse the graph and update HashMap and Visiting array
function dfs(i, adj, vis, ar, hm) {
    vis[i] = true;
    hm[ar[i]] = (hm[ar[i]] || 0n) + 1n;
    for (const it of adj[i]) {
        if (!vis[it]) dfs(it, adj, vis, ar, hm);
    }
}
 
// Function to output the number of sequences
function countSequences(N, M, A, B, fac) {
    // Initialize adjacency list, visited array, and ar array
    const adj = new Array(N).fill(null).map(() => []);
    // Visiting array created for DFS
    const vis = new Array(N).fill(false);
 
    // Constructing the graph
    for (let i = 0; i < M; i++) {
        const u = B[i][0] - 1;
        const v = B[i][1] - 1;
        adj[u].push(v);
        adj[v].push(u);
    }
 
    // Initialize result and x
    let res = 1n;
    let x = 0n;
 
    // Perform DFS and calculate result for each node
    for (let i = 0; i < N; i++) {
        if (!vis[i]) {
            const hm = {};
            dfs(i, adj, vis, A, hm);
            let mul = 1n, cn = 0n;
            for (const set in hm) {
                cn += hm[set];
                const xx = hm[set];
                mul = (mul * fac[xx]) % 1000000007n;
            }
            const inn = cn;
            const y = fac[x + inn];
            const d1 = (
                power(fac[x], 1000000005n, 1000000007n) *
                power(fac[inn], 1000000005n, 1000000007n)
            ) % 1000000007n;
            const fraction = (y * d1) % 1000000007n;
            res = (res * ((fraction * mul) % 1000000007n)) % 1000000007n;
            x += inn;
        }
    }
 
    // Print the result
    console.log(res.toString());
}
 
// Precompute factorials up to 2e5
const fac = new Array(200001).fill(0n);
fac[0] = 1n;
for (let i = 1; i <= 200000; i++)
    fac[i] = (fac[i - 1] * BigInt(i)) % 1000000007n;
 
// Read the number of nodes and edges
const N = 5;
const M = 5;
const A = [10, 12, 15, 20, 15];
const B = [
    [1, 2], [2, 3], [3, 4], [4, 2], [3, 1]
];
 
// Function call
countSequences(N, M, A, B, fac);


Output

5

Time Complexity: O(N2), Where N is the number of nodes in the graph. This is because for each node, the code performs a depth-first search (DFS) which can visit each node in the graph, and for each node visited, it performs operations that are linear in the number of nodes.

Auxiliary Space: O(N), This is because it maintains an adjacency list representation of the graph, a visited array to keep track of visited nodes, and an array to store some values associated with each node are used. The HashMap used to keep track of counts during DFS also contributes to the space complexity, but its size is at most N, so it doesn’t change the overall space complexity.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads