HDU-6470 Count (构造矩阵+矩阵快速幂)

题目链接

Problem Description

Farmer John有n头奶牛.
某天奶牛想要数一数有多少头奶牛,以一种特殊的方式:
第一头奶牛为1号,第二头奶牛为2号,第三头奶牛之后,假如当前奶牛是第n头,那么他的编号就是2倍的第n-2头奶牛的编号加上第n-1头奶牛的编号再加上自己当前的n的三次方为自己的编号.
现在Farmer John想知道,第n头奶牛的编号是多少,估计答案会很大,你只要输出答案对于123456789取模.

Input

第一行输入一个T,表示有T组样例
接下来T行,每行有一个正整数n,表示有n头奶牛 (n>=3)
其中,T=104,n<=1018

Output

共T行,每行一个正整数表示所求的答案

Sample Input

5
3
6
9
12
15

Sample Output

31
700
7486
64651
527023

思路

求解过程类似于斐波那契数列,这里的N太大,需要用快速幂的 l o g ( N ) log(N) 来优化。
首先递推公式: F ( N ) = 2 F ( N 2 ) + F ( N 1 ) + N 3 F(N) = 2*F(N-2) + F(N-1) + N^3
下面构造矩阵来优化:

N 3 = ( N 1 + 1 ) 3 = C 3 0 ( N 1 ) 3 + C 3 1 ( N 1 ) 2 + C 3 2 ( N 1 ) 1 + C 3 3 ( N 1 ) 0 \begin{aligned} N^3 &amp;= (N-1 + 1) ^ 3\\ &amp;=C_3^0(N-1)^3 + C_3^1(N-1)^2 +C_3^2(N-1)^1 +C_3^3(N-1)^0\\ \end{aligned}
: { F ( N 2 ) F ( N 1 ) ( N 1 ) 3 ( N 1 ) 2 ( N 1 ) 1 ( N 1 ) 0 } 1 { F ( N 1 ) F ( N ) N 3 N 2 N 1 N 0 } 2 假设我们已知:\left\{ \begin{aligned} F(N-2)\\ F(N-1)\\ (N-1)^3\\ (N-1)^2\\ (N-1)^1\\ (N-1)^0\\ \end{aligned} \right\}_1 需要求:\left\{ \begin{aligned} F(N-1)\\ F(N)\\ N^3\\ N^2\\ N^1\\ N^0\\ \end{aligned} \right\}_2
这是我们需要一个矩阵

{ 0 1 0 0 0 0 2 1 C 3 0 C 3 1 C 3 2 C 3 3 0 0 C 3 0 C 3 1 C 3 2 C 3 3 0 0 0 C 2 0 C 2 1 C 2 2 0 0 0 0 C 1 0 C 1 1 0 0 0 0 0 C 3 3 } \left\{ \begin{matrix} 0 &amp; 1 &amp; 0 &amp; 0 &amp; 0 &amp; 0 \\ 2 &amp; 1 &amp; C_3^0 &amp;C_3^1 &amp;C_3^2&amp;C_3^3 \\ 0 &amp; 0 &amp; C_3^0 &amp;C_3^1 &amp;C_3^2&amp;C_3^3\\ 0 &amp; 0 &amp; 0 &amp;C_2^0 &amp;C_2^1&amp;C_2^2\\ 0 &amp; 0 &amp;0 &amp;0 &amp;C_1^0&amp;C_1^1\\ 0 &amp; 0 &amp; 0 &amp;0 &amp;0&amp;C_3^3\\ \end{matrix} \right\}
这时状态 1 1 就可以通过矩阵得到状态 2 2

{ F ( 1 ) F ( 2 ) 2 3 2 2 2 1 2 0 } 3 初始矩阵\left\{ \begin{aligned} F(1)\\ F(2)\\ 2^3\\ 2^2\\ 2^1\\ 2^0\\ \end{aligned} \right\}_3

A n s = m a t r i x n 2 m a t r i x 3 Ans = matrix^{n-2} * matrix_3

#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#include <time.h>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, a, n) for (int i = a; i <= n; ++i)
const int maxn = 1044373;
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
using namespace std;


const LL mod = 123456789;

// 定义矩阵 重载*
struct ac{
    LL a[6][6];
    ac operator * (ac b) {
        ac t;
        for (int i = 0; i < 6; ++i) {
            for (int j = 0; j < 6; ++j) {
                t.a[i][j] = 0;
                for (int k = 0; k < 6; ++k) {
                    t.a[i][j] = (t.a[i][j] + (a[i][k] * b.a[k][j] % mod)) % mod;
                }
            }
        }
        return t;
    }
}g, m;
// 矩阵快速幂
ac quick(ac tmp, LL x) {
    ac t;
    mem(t.a, 0);
    for (int i = 0; i < 6; ++i) t.a[i][i] = 1;
    while (x) {
        if (x & 1) t = t * tmp;
        tmp = tmp * tmp;
        x >>= 1; 
    }
    return t;
}

int main() {
#ifndef ONLINE_JUDGE
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T;
    scanf("%d", &T);
    g.a[0][1] = 1;
    g.a[1][0] = 2;
    g.a[1][2] = g.a[1][1] = 1;
    g.a[1][3] = g.a[1][4] = 3;
    g.a[1][5] = g.a[2][2] = 1;
    g.a[2][3] = g.a[2][4] = 3;
    g.a[2][5] = g.a[3][3] = 1;
    g.a[3][4] = 2;
    g.a[3][5] = g.a[4][4] = g.a[4][5] = g.a[5][5] = 1;

    m.a[0][0] = 1;
    m.a[1][0] = 2;
    m.a[2][0] = 8;
    m.a[3][0] = 4;
    m.a[4][0] = 2;
    m.a[5][0] = 1;

    while (T--) {
        LL n;
        scanf("%lld", &n);
        if (n == 1 || n == 2) {
            printf("1\n");
            continue;
        }
        ac t = quick(g, n-2);
        ac ans = t * m;      

        printf("%lld\n", ans.a[1][0]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/88621961