珍珠项链(土豪送项链)——矩阵加速

目录

一.题目

二.题解

三.参考代码

谢谢!


一.题目

传送门

二.题解

这道题的难点在于找到递推公式。

我们定义长度为i,珍珠种数为j的项链搭配方法总数为f[i][j]

可以得到一个递推公式:f[i][j] = f[i-1][j-1] * (k-j+1)+f[i-1][j]*j

解释:

先解释前一部分:f[i-1][j-1] * (k-j+1)

f[i-1][j-1] * (k-j+1)=f[i-1][j-1]*[k-(j-1)]

就代表已经选了j-1颗珍珠,要在其他的[k-(j-1)]中任选一颗来填充i位置,就有[k-(j-1)]种选法。

后一部分:f[i-1][j]*j

就代表在已选的j颗珍珠选一颗来填充第i个位置,就有j种的选法。

好,那么再把它简化成一维。大家会发现第一位永远是i-1,可以直接省去,就变成了:

f[i] = f[i-1] * (k-i+1)+f[i]*i

矩阵就十分好构造了:

\begin{bmatrix} 1&0 &. &. &. &. &. &. &. &1 \\ 0&1 &0 &. &. &. &. &. &. &0 \\ 0&k-1 &2 &. &. &. &. &. &. &0 \\ .&. &. &. &. &. &. &. &. &. \\ 0&. &0 &k-(j-1) &j &0 &. &. &. &0 \\ .& .& . &. &. &. &. &. &. &. \\ 0& . &. &. &. &. &. &0 &1 &k \end{bmatrix} * \begin{bmatrix} S_{1}\\ f_{1}\\ f_{2}\\ .\\ f_{j}\\ .\\ f_{k}\\ \end{bmatrix} = \begin{bmatrix} S_{1}'\\ f_{1}'\\ f_{2}'\\ .\\ f_{j}'\\ .\\ f_{k}'\\ \end{bmatrix}

三.参考代码

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define mod 1234567891
#define LL long long
int T, n, k;
inline void Read (int &x){
    int f = 1; x = 0; char c = getchar ();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar ();}
    while (c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar ();}
    x *= f;
}
struct node {
    LL r, c, jz[35][35];
    node operator * (const node& rhs) const{
        node ans;
        ans.r = r, ans.c = rhs.c;
        for (register int i = 0; i <= ans.r; i ++)
            for (register int j = 0; j <= ans.c; j ++)
                ans.jz[i][j] = 0;
        for (register int i = 1; i <= r; i ++)
            for (register int j = 1; j <= rhs.c; j ++)
                for (register int k = 1; k <= c; k ++)
                    ans.jz[i][j] = (ans.jz[i][j] + jz[i][k] * rhs.jz[k][j] % mod) % mod;
        return ans;
    }
}A, B, C;
inline node qkpow (node x, LL y){
    node ans;
    ans.r = ans.c = k + 1;
    for (register int i = 1; i <= ans.r; i ++)
        for (register int j = 1; j <= ans.c; j ++)
            if (i != j)
                ans.jz[i][j] = 0;
            else
                ans.jz[i][j] = 1;
    while (y > 0){
        if (y % 2 == 1)
            ans = ans * x;
        x = x * x;
        y /= 2;
    }
    return ans;
}
int main (){
    Read (T);
    while (T --){
        Read (n), Read (k);
        memset (A.jz, 0, sizeof A.jz);
        memset (B.jz, 0, sizeof B.jz);
        memset (C.jz, 0, sizeof C.jz);
        A.r = A.c = k + 1;
        A.jz[1][1] = A.jz[1][k + 1] = A.jz[2][2] = 1;
        for (register int i = 3; i <= k + 1; i ++){
            A.jz[i][i] = i - 1;
            A.jz[i][i - 1] = k - i + 2;
        }
        B.r = k + 1, B.c = 1;
        B.jz[1][1] = 0, B.jz[2][1] = k;
        C = qkpow (A, n) * B;
        printf ("%lld\n", C.jz[1][1]);
    }
    return 0;
}

谢谢!

发布了61 篇原创文章 · 获赞 32 · 访问量 8364

猜你喜欢

转载自blog.csdn.net/weixin_43908980/article/details/89331718