D. Magic Gems
题意:
输入
n
(
1
e
18
)
,
m
(
1
e
2
)
n(1e18),m(1e2)
n(1e18),m(1e2)
一个魔法宝石可以占用一个空间,也可以变成
m
m
m个普通宝石占用
m
m
m个空间,开始只有魔法宝石,问有多少种不同的方式(魔法宝石个数不同,或变成普通宝石的魔法宝石不同)使它占用
n
n
n空间。
题解:
很容易就可以列出
d
p
dp
dp方程:
d
p
[
i
]
=
d
p
[
i
−
1
]
+
d
p
[
i
−
m
]
dp[i]=dp[i-1]+dp[i-m]
dp[i]=dp[i−1]+dp[i−m]
这个方程不是和斐波拉契很像吗?然后按套路矩阵快速幂一下就好了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=109;
const int mod=1e9+7;
int a[N][N];
ll n,m;
void jzc(int a[N][N],int b[N][N],int c){
int ans[N][N];
memset(ans,0,sizeof(ans));
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=m;k++)ans[i][j]=(1ll*a[i][k]*b[k][j]+ans[i][j])%c;
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)a[i][j]=ans[i][j];
}
void jzksm(int a[N][N],ll b,int c){
int ans[N][N],base[N][N];
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++){
if(i==j)ans[i][j]=1;else ans[i][j]=0;
base[i][j]=a[i][j];
}
while(b){
if(b&1)jzc(ans,base,c);
jzc(base,base,c);
b>>=1;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)a[i][j]=ans[i][j];
}
int main(){
//freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
cin>>n>>m;
if(n<m){cout<<1<<endl;return 0;}
for(int j=1;j<=m;j++){
if(j==1)a[1][j]=a[m][j]=1;
else a[j-1][j]=1;
}
jzksm(a,n-m+1,mod);
int ans=0;
for(int i=1;i<=m;i++)ans=(ans+a[i][1])%mod;
cout<<ans<<endl;
return 0;
}