Challenge: Mutual Recurrences

Subdomeniu: Fundamentals (fundamentals)

Scor cont: 40.0 / 40

Submission status: Accepted

Submission score: 1.0

Submission ID: 464730033

Limbaj: cpp14

Link challenge: https://www.hackerrank.com/challenges/mutual-recurrences/problem

Cerinta

Since you know [how to compute large Fibonacci numbers quickly](https://www.hackerrank.com/contests/infinitum10/challenges/fibonacci-finding-easy) using *matrix exponentiation*, let's take things to the next level.  

Let $a$, $b$, $c$, $d$, $e$, $f$, $g$ and $h$ be positive integers. We define two bi-infinite sequences
$$(\ldots, x_{-2}, x_{-1}, x_0, x_1, x_2, \ldots)$$
and
$$(\ldots, y_{-2}, y_{-1}, y_0, y_1, y_2, \ldots)$$
as follows:  

$$x_n = \begin{cases}
x_{n-a} + y_{n-b} + y_{n-c} + n\cdot d^n & \text{if $n \ge 0$} \\\
1 & \text{if $n < 0$}
\end{cases}$$

and  

$$y_n = \begin{cases}
y_{n-e} + x_{n-f} + x_{n-g} + n\cdot h^n & \text{if $n \ge 0$} \\\
1 & \text{if $n < 0$}
\end{cases}$$

Given $n$ and the eight integers above, find $x_n$ and $y_n$. Since these values can be very large, output them modulo $10^9$.  

This link may help you get started: http://fusharblog.com/solving-linear-recurrence-for-programming-contest/

Input Format

The first line of input contains $T$, the number of test cases.  
Each test case consists of a single line containing nine space separated integers: $a$, $b$, $c$, $d$, $e$, $f$, $g$, $h$ and $n$, respectively.  

**Constraints**  
$1 \leq T \leq 100$  
$1 \leq a,b,c,d,e,f,g,h < 10$  
$1 \leq n \leq 10^{18}$

Output Format

For each test case, output a single line containing two space separated integers, $x_n \bmod 10^9$ and $y_n \bmod 10^9$.

Cod sursa

// Mathematics > Fundamentals > Mutual Recurrences
// Compute terms in a mutual recurrence.
//
// https://www.hackerrank.com/challenges/mutual-recurrences/problem
// https://www.hackerrank.com/contests/infinitum14/challenges/mutual-recurrences
// challenge id: 15898
//

#include <bits/stdc++.h>
using namespace std;

#pragma GCC diagnostic ignored "-Wsign-conversion"

constexpr long MOD = 1e9;

class Vecteur
{
    vector<long> a;
    size_t n;

  public:
    Vecteur(size_t n)
    {
        this->n = n;
        a.resize(n, 0L);
    }

    size_t dim() const
    {
        return n;
    }

    long operator()(size_t x) const
    {
        assert(x < n);
        return a[x];
    }

    long &operator()(size_t x)
    {
        assert(x < n);
        return a[x];
    }
};

class Matrice
{
    vector<long> a;
    size_t n;

  public:
    Matrice(size_t n)
    {
        this->n = n;
        a.resize(n * n, 0L);
    }

    static Matrice I(size_t n)
    {
        Matrice M(n);
        for (size_t i = 0; i < n; ++i)
            M(i, i) = 1;
        return M;
    }

    long operator()(size_t x, size_t y) const
    {
        assert(x < n && y < n);
        return a[x + y * n];
    }

    long &operator()(size_t x, size_t y)
    {
        assert(x < n && y < n);
        return a[x + y * n];
    }

    Matrice &operator%=(long m)
    {
        for (auto &&i : a)
            i %= m;
        return *this;
    }

    Matrice &operator*=(const Matrice &B)
    {
        assert(n == B.n);

        Matrice &A = *this;
        Matrice C(n);

        for (size_t x = 0; x < n; ++x)
        {
            for (size_t y = 0; y < n; ++y)
            {
                long s = 0;
                for (size_t i = 0; i < n; ++i)
                    s += (A(i, y) * B(x, i)) % MOD;
                C(x, y) = s % MOD;
            }
        }
        a = C.a;
        return *this;
    }

    Vecteur operator*(const Vecteur &V) const
    {
        assert(n == V.dim());
        const Matrice &A = *this;
        Vecteur C(n);

        for (size_t y = 0; y < n; ++y)
        {
            long s = 0;
            for (size_t i = 0; i < n; ++i)
                s += (A(i, y) * V(i)) % MOD;
            C(y) = s % MOD;
        }

        return C;
    }

    Matrice &operator^=(unsigned long k)
    {
        if (k == 1)
            return *this;

        Matrice &M = *this;
        Matrice P = Matrice::I(n);

        while (k != 0)
        {
            if (k % 2 == 1)
                P *= M;
            M *= M;
            k /= 2;
        }

        a = P.a;
        return *this;
    }

    void print() const
    {
        const Matrice &A = *this;

        for (size_t y = 0; y < n; ++y)
        {
            cout << ((y == 0) ? '[' : ' ');
            for (size_t x = 0; x < n; ++x)
            {
                cout << A(x, y);
                if (x == n - 1)
                {
                    if (y == n - 1)
                        cout << "]\n";
                    else
                        cout << "\n";
                }
                else
                {
                    cout << " ";
                }
            }
        }
    }
};

long fibonacci_easy(long a, long b, unsigned long n)
{
    Matrice A(2);

    A(0, 0) = 1;
    A(0, 1) = 1;
    A(1, 0) = 1;
    A(1, 1) = 0;

    A ^= n;

    Vecteur F(2);
    F(0) = b;
    F(1) = a;

    F = A * F;

    return F(1);
}

// Complete the solve function below.
void solve(int a, int b, int c, int d, int e, int f, int g, int h, unsigned long n)
{
    Matrice A(20 + 4);

    A(a - 1, 0) += 1;      // x(n) =  x(n - a)
    A(10 + b - 1, 0) += 1; //                  + y(n - b)
    A(10 + c - 1, 0) += 1; //                             + y(n - c)
    A(20 + 2, 0) += 1;     //                                        + n * d ** n

    A(10 + e - 1, 10) += 1; // y(n) = y(n - e)
    A(f - 1, 10) += 1;      //                 + x(n - f)
    A(g - 1, 10) += 1;      //                             + x(n - g)
    A(20, 10) += 1;         //                                        + n * h ** n

    for (size_t i = 1; i < 10; ++i)
    {
        A(i - 1, i) += 1;
        A(10 + i - 1, 10 + i) += 1;
    }

    A(20, 20) = h;
    A(20 + 1, 20) = h;
    A(20 + 1, 20 + 1) = h;

    A(20 + 2, 20 + 2) = d;
    A(20 + 3, 20 + 2) = d;
    A(20 + 3, 20 + 3) = d;

    //A.print();

    Vecteur F(20 + 4);
    for (size_t i = 0; i < 20 + 4; ++i)
        F(i) = 1;
    F(20) = 0;
    F(20 + 2) = 0;

    A ^= (n + 1);
    F = A * F;
    cout << F(0) << " " << F(10) << endl;
}

int main()
{
    // cerr << fibonacci_easy(2, 4, 9) << endl;        // [55, 34, 34, 21]  178

    int t;
    cin >> t;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');

    while (t--)
    {
        int a, b, c, d, e, f, g, h;
        unsigned long n;
        cin >> a >> b >> c >> d >> e >> f >> g >> h >> n;
        solve(a, b, c, d, e, f, g, h, n);
    }

    return 0;
}
HackerRank Fundamentals – Mutual Recurrences