Challenge: Longest Increasing Subsequence Arrays

Subdomeniu: Combinatorics (combinatorics)

Scor cont: 50.0 / 50

Submission status: Accepted

Submission score: 1.0

Submission ID: 464734674

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/longest-increasing-subsequence-arrays/problem

Cerinta

We define the following:

- A *subsequence* of an array is an ordered subset of the array's elements having the same sequential ordering as the original array. For example, the subsequences of array $[1, 2, 3]$ are $\{1\}$, $\{2\}$, $\{3\}$, $\{1, 2\}$, $\{2, 3\}$, $\{1, 3\}$, and $\{1, 2, 3\}$.
- The [longest increasing subsequence](https://en.wikipedia.org/wiki/Longest_increasing_subsequence) of an array of numbers is the longest possible subsequence that can be created from its elements such that all elements are in increasing order.

Victoria has two integers, $m$ and $n$. She builds unique arrays satisfying the following criteria:

- Each array contains $m$ integers.
- Each integer is $\in [1, n]$.
- The longest increasing subsequence she can create from the array has length $n$.

Given $p$ pairs of $m$ and $n$ values, print the number of arrays Victoria creates for each pair on a new line. As this number can be quite large, print your answer modulo $(10^9+7)$.

Input Format

The first line contains a single positive integer, $p$, denoting the number of pairs. 		
Each line $i$ of the $p$ subsequent lines contains two space-separated integers describing the respective $m$ and $n$ values for a pair.

Output Format

On a new line for each pair, print a single integer denoting the number of different arrays Victoria creates modulo $(10^9+7)$.

Constraints

- $1 \leq p \leq 50$
- $1 \leq m \leq 5 \times 10^5$
- $1 \leq n \leq 10^5$
- $n \leq m$

Cod sursa

// Problem: Longest Increasing Subsequence Arrays
// Link: https://www.hackerrank.com/challenges/longest-increasing-subsequence-arrays/problem
// Author: Mai Thanh Hiep
// Complexity: O(T * M), where T <= 50 is number of testcases, M <= 5*10^5 is number elements in each array.

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;

#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)

class Combinatorics {
    vector<ll> fact;
    vector<ll> factInv;
    int MOD;
    ll fastPow(ll base, int power) { // base^power % MOD
        if (base == 0) return 0;
        if (power == 0) return 1;
        ll res = fastPow(base, power / 2);
        res = (res * res) % MOD;
        if (power & 1)
            res = (res * base) % MOD;
        return res;
    }

    vector<int> getPresentation(int num, int base) {
        vector<int> p;
        while (num > 0) {
            p.push_back(num % base);
            num /= base;
        }
        return p;
    }
public:
    Combinatorics(int mod) {
        this->MOD = mod;
    }

    void computeFactsAndInvFacts(int n) { // fact[i] = i! % MOD
        fact.assign(n + 1, 0);
        factInv.assign(n + 1, 0);

        fact[0] = 1;
        for (int i = 1; i <= n; ++i) {
            fact[i] = (fact[i - 1] * i) % MOD;
        }

        factInv[n] = fastPow(fact[n], MOD - 2);
        for (int i = n - 1; i >= 0; --i) {
            factInv[i] = factInv[i+1] * (i+1) % MOD;
        }
    }

    ll nCkInverseModulo(int n, int k) { // C(n, k) % MOD, it works if and only if n! and MOD are co-prime!
        ll res = fact[n];
        res = (res * factInv[k]) % MOD;
        res = (res * factInv[n - k]) % MOD;
        return res;
    }

    ll nCkInverseModuloForLucas(int n, int k) { // C(n, k) % MOD, it works if and only if n! and MOD are co-prime!
        ll div = fact[n-k] * fact[k] % MOD;
        return fact[n] * fastPow(div, MOD - 2) % MOD;
    }

    ll nCkLucas(int n, int k) { // C(n, k) % MOD, MOD must be a prime number, use it when MOD < n
        vector<int> pN = getPresentation(n, MOD);
        vector<int> pK = getPresentation(k, MOD);
        ll res = 1LL;
        for (int i = 0; i < pK.size(); ++i) {
            res = (res * nCkInverseModuloForLucas(pN[i], pK[i])) % MOD;
        }
        return res;
    }
};

const int MAX_M = 5e5 + 5;
const int MOD = 1e9 + 7;
ll POW_N[MAX_M], POW_N1[MAX_M];

int main() {
//    fin;
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    Combinatorics combinatorics(MOD);
    combinatorics.computeFactsAndInvFacts(MAX_M);

    int T, m, n;
    cin >> T;
    while (T--) {
        cin >> m >> n;

        POW_N[0] = POW_N1[0] = 1LL;
        for (int i = 1; i <= m - n; ++i) {
            POW_N[i] = POW_N[i-1] * n % MOD;
            POW_N1[i] = POW_N1[i-1] * (n-1) % MOD;
        }

        ll res = 0;
        for (int x = 0; x <= m - n; ++x) {
            ll mul = combinatorics.nCkInverseModulo(m-x-1, n-1);
            mul = mul * POW_N[x] % MOD;
            mul = mul * POW_N1[m-n-x] % MOD;
            res = (res + mul) % MOD;
        }
        cout << res << '\n';
    }

    return 0;
}
HackerRank Combinatorics – Longest Increasing Subsequence Arrays