题解:石头放置


考虑设 $f,i,0/1,0/1$ 表示当前处理到第 $i$ 条边,开头是否填石头 ,末尾是否填石头的方案数, 则有
$f_{i,0,0} = (f_{i-1,0,0} + f_{i-1,1,0} )\times C_{k}^{d-1}$
$f_{i,1,0} = (f_{i-1,0,1} + f_{i-1,1,1} )\times C_{k-1}^{d-1} $
$f_{i,1,1} = (f_{i-1,0,1} + f_{i-1,1,1} )\times C_{k-2}^{d-1} $
$ f_{i,0,1} = (f_{i-1,0,0} + f_{i-1,1,0} )\times C_{k-1}^{d-1} $
将其写成矩阵型式有
$\begin{pmatrix}f_{i,0,0}\\f_{i,1,0}\\f_{i,1,1}\\f_{i,0,1}\end{pmatrix}= \begin{pmatrix} C_{k}^{d-1} & C_{k}^{d-1} & 0 & 0\\0 & 0 & C_{k-1}^{d-1} & C_{k-1}^{d-1}\\0 & 0 & C_{k-2}^{d-1} & C_{k-2}^{d-1}\\C_{k-1}^{d-1} & C_{k-1}^{d-1} & 0 &0\end{pmatrix} \begin{pmatrix}f_{i-1,0,0}\\f_{i-1,1,0}\\f_{i-1,1,1}\\f_{i-1,0,1}\end{pmatrix}$
但是我们在处理最后一条边的时候并不知道第一条边最后一个点是否被放置,所以我们可以强制赋值(采用类似与环形DP的处理方法)
令 $G = \begin{pmatrix} C_{k}^{d-1} & C_{k}^{d-1} & 0 & 0\\0 & 0 & C_{k-1}^{d-1} &C_{k-1}^{d-1}\\0 & 0 & C_{k-2}^{d-1} & C_{k-2}^{d-1}\\C_{k-1}^{d-1} & C_{k-1}^{d-1} & 0 &0\end{pmatrix}^{n-1}$
$A = \begin{pmatrix} C_{k}^{d-1} \\ 0\\ 0\\ C_{k-1}^{d-1} \end{pmatrix}$ ,$B = \begin{pmatrix} 0\\ C_{k-1}^{d-1} \\ C_{k-2}^{d-1}\\ 0 \end{pmatrix}$
$A \gets G *A$ , $B \gets G * B$
$ans \gets A[1][1] + A[2][1] + B[3][1] +B[4][1]$
然后求$G$使用矩阵快速幂即可, 注意计算组合数在取模时需要使用逆元。

$Code :$

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll N = 1e5 + 5;
const ll MOD = 998244353;
ll f[N];
ll Ine(ll a, ll b)
{
    ll ans = 1, base = a;
    while (b)
    {
        if (b & 1)
            ans = ans * base % MOD;
        base = base * base % MOD;
        b >>= 1;
    }
    return ans;
}
ll ComBin(ll n, ll i)
{
    ll a = f[n], b = f[i], c = f[n - i];
    ll d = Ine(b, MOD - 2);
    ll f = Ine(c, MOD - 2);
    return max(0ll, a * d % MOD * f % MOD);
}
ll n, d;
struct JZ
{
    ll g[8][8];
    ll H, L;
    JZ()
    {
        memset(g, 0, sizeof g);
        H = L = 0;
    }
    void build(ll k)
    {
        g[1][1] = g[1][2] = ComBin(d - 1, k);
        g[4][1] = g[4][2] = g[2][3] = g[2][4] = ComBin(d - 1, k - 1);
        g[3][3] = g[3][4] = ComBin(d - 1, k - 2);
    }
    JZ operator*(const JZ b) const
    {
        JZ ans;
        ans.H = H, ans.L = b.L;
        for (ll k = 1; k <= L; k++)
            for (ll i = 1; i <= H; i++)
                for (ll j = 1; j <= b.L; j++)
                    ans.g[i][j] = (ans.g[i][j] + g[i][k] * b.g[k][j] % MOD) % MOD;
        return ans;
    }
};
signed main()
{
    f[0] = 1;
    for (ll i = 1; i <= 1e4; i++)
        f[i] = (i * f[i - 1]) % MOD;
    scanf("%lld%lld", &n, &d);
    ll ans = 0;
    for (ll k = 0; k <= d + 1; k++)
    {
        JZ A, Ans, INIT, B;
        INIT.build(k);
        INIT.H = INIT.L = 4;
        Ans.H = 4, Ans.L = 4;

        A.H = 4, A.L = 1;
        A.g[1][1] = ComBin(d - 1, k);
        A.g[4][1] = ComBin(d - 1, k - 1);
        A.H = 4, B.L = 1;
        B.g[2][1] = ComBin(d - 1, k - 1);
        B.g[3][1] = ComBin(d - 1, k - 2);

        for (ll i = 1; i <= 4; i++)
            Ans.g[i][i] = 1;
        ll q = n - 1;
        while (q)
        {
            if (q & 1)
                Ans = Ans * INIT;
            INIT = INIT * INIT;
            q >>= 1;
        }
        A = Ans * A;
        B = Ans * B;
        ans = (ans + A.g[1][1] % MOD + A.g[2][1] % MOD + B.g[3][1] % MOD + B.g[4][1] % MOD) % MOD;
        // cout << ans << endl;
    }
    printf("%lld", ans);
    return 0;
}

下为验证码。

var code = "80653215-117a-4d14-a639-178f710842ee"

posted @ 2023-08-17 08:52  Saka_Noa  阅读(7)  评论(0)    收藏  举报  来源