题目大意:xht37有很多魔法宝石。每颗魔法宝石可以分解成 m m m颗普通宝石,魔法宝石和普通宝石都占据 1 1 1体积的空间,但普通宝石不能再被分解。
xht37想要使一些魔法宝石分解,使得所有宝石占据的空间恰好为 n n n单位体积。显然,一个魔法宝石分解后会占据 m m m体积空间,不分解的魔法宝石仍占据 1 1 1体积空间。
现在xht37想要求出有多少种分解方案,可以让最后得到的宝石恰好占据 n n n单位体积。两种分解方案不同当且仅当分解的魔法宝石数量不同,或者是所用的宝石的编号不同。
数据范围: 1 ≤ n ≤ 1 0 18 , 2 ≤ m ≤ 100 1 \le n\le 10^{18},2\le m\le 100 1≤n≤1018,2≤m≤100
思路:显然易见的
d
p
dp
dp做法。用
d
p
[
i
]
dp[i]
dp[i]表示占据
i
i
i个体积空间时的分解方案,可以写出转移方程为:
{
d
p
[
i
]
=
d
p
[
i
−
1
]
i
<
m
d
p
[
i
]
=
d
p
[
i
−
1
]
+
d
p
[
i
−
m
]
i
≥
m
\begin{cases} dp[i]=dp[i-1]\qquad i\lt m \\ dp[i]=dp[i-1]+dp[i-m]\qquad i\ge m \end{cases}
{dp[i]=dp[i−1]i<mdp[i]=dp[i−1]+dp[i−m]i≥m
考虑到本题的
n
≤
1
0
18
n\le 10^{18}
n≤1018,线性递推必然超时,因此我们考虑用矩阵快速幂优化,把复杂度降低到
l
o
g
log
log级别。
我们考虑这样两个向量:
F
(
n
)
=
[
d
p
n
d
p
n
−
1
⋅
⋅
⋅
d
p
n
−
m
+
1
]
F(n)=\begin{bmatrix} dp_n& dp_{n-1}& ···& dp_{n-m+1}\end{bmatrix}
F(n)=[dpndpn−1⋅⋅⋅dpn−m+1]
F
(
n
−
1
)
=
[
d
p
n
−
1
d
p
n
−
2
⋅
⋅
⋅
d
p
n
−
m
]
F(n-1)=\begin{bmatrix} dp_{n-1}& dp_{n-2}& ···& dp_{n-m}\end{bmatrix}
F(n−1)=[dpn−1dpn−2⋅⋅⋅dpn−m]
如何找到一个矩阵
A
A
A,使得
F
(
n
)
=
F
(
n
−
1
)
∗
A
F(n)=F(n-1)*A
F(n)=F(n−1)∗A
得到 A A A之后,我们把这个递推柿子一直写下去就可以得到: F ( n ) = F ( m − 1 ) ∗ A n − m + 1 F(n)=F(m-1)*A^{n-m+1} F(n)=F(m−1)∗An−m+1
由于 F ( m − 1 ) = [ d p m − 1 d p m − 2 ⋅ ⋅ ⋅ d p 0 ] F(m-1)=\begin{bmatrix} dp_{m-1}& dp_{m-2}& ···& dp_{0}\end{bmatrix} F(m−1)=[dpm−1dpm−2⋅⋅⋅dp0] 由于 d p 0 = 1 dp_0=1 dp0=1,通过转移方程可得: F ( m − 1 ) = [ 1 1 ⋅ ⋅ ⋅ 1 1 ] F(m-1)=\begin{bmatrix} 1& 1& ···& 1& 1\end{bmatrix} F(m−1)=[11⋅⋅⋅11]为一个已知的全 1 1 1向量
那我们通过矩阵快速幂求出 A n − m + 1 A^{n-m+1} An−m+1之后就可以得到 F ( n ) F(n) F(n),而它的第一项就是所要求的答案 d p n dp_n dpn
下面我们讲一下如何求出矩阵
A
A
A,我们由转移方程可以得到:
{
d
p
[
n
]
=
1
∗
d
p
[
n
−
1
]
+
1
∗
d
p
[
n
−
m
]
d
p
[
n
−
1
]
=
1
∗
d
p
[
n
−
1
]
⋅
⋅
⋅
⋅
⋅
⋅
d
p
[
n
−
m
]
=
1
∗
d
[
n
−
m
]
\begin{cases} dp[n]=1*dp[n-1]+1*dp[n-m]\\ dp[n-1]=1*dp[n-1]\\ \qquad\qquad······\\ dp[n-m]=1*d[n-m] \end{cases}
⎩⎪⎪⎪⎨⎪⎪⎪⎧dp[n]=1∗dp[n−1]+1∗dp[n−m]dp[n−1]=1∗dp[n−1]⋅⋅⋅⋅⋅⋅dp[n−m]=1∗d[n−m]
显然这个
m
×
m
m\times m
m×m的矩阵
A
A
A的各行各列值即为上面
m
m
m个柿子的系数,得:
A
=
[
1
0
0
⋅
⋅
⋅
0
0
1
1
0
0
⋅
⋅
⋅
0
0
0
0
1
0
⋅
⋅
⋅
0
0
0
0
0
1
⋅
⋅
⋅
0
0
0
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
⋅
0
0
0
⋅
⋅
⋅
0
0
1
]
A=\begin{bmatrix} 1& 0& 0& ··· &0 &0 &1 \\ 1& 0& 0& ··· &0 &0 &0 \\ 0& 1& 0& ··· &0 &0 &0 \\ 0& 0& 1& ··· &0 &0 &0 \\ ···&···&···&···&···&···&···\\ 0& 0& 0& ··· &0 &0 &1 \\ \end{bmatrix}
A=⎣⎢⎢⎢⎢⎢⎢⎡1100⋅⋅⋅00010⋅⋅⋅00001⋅⋅⋅0⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅⋅0000⋅⋅⋅00000⋅⋅⋅01000⋅⋅⋅1⎦⎥⎥⎥⎥⎥⎥⎤
至此,本题就可以在
O
(
m
3
l
o
g
n
)
O(m^3logn)
O(m3logn)的复杂度过了
PS:注意 n < m n<m n<m时,直接输出 1 1 1即可,不单独讨论的话,会超时…
Code:
#include <bits/stdc++.h>
using namespace std;
const int N=1e2+10,mod=1e9+7;
typedef long long ll;
ll n,m;
struct Mat{
ll mat[N][N];
Mat() {memset(mat,0,sizeof(mat));}
Mat operator*(const Mat &b)const {
Mat res;
for(int i=0;i<100;i++){
for(int j=0;j<100;j++){
for(int k=0;k<100;k++){
res.mat[i][j]+=mat[i][k]*b.mat[k][j]%mod;
res.mat[i][j]%=mod;
}
}
}
return res;
}
}base,ans;
void mat_power(ll k){
for(;k;k>>=1){
if(k&1) ans=ans*base;
base=base*base;
}
return ;
}
int main(){
scanf("%lld%lld",&n,&m);
if(n<m) cout<<"1"<<endl;
else{
for(int i=0;i<m;i++) ans.mat[0][i]=1;
base.mat[0][0]=base.mat[0][m-1]=1;
for(int i=1;i<m;i++) base.mat[i][i-1]=1;
mat_power(n-m+1);
printf("%lld",ans.mat[0][0]);
}
return 0;
}