题解:石头放置
考虑设 $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"