传送门
解析:
其实这种只用位数转移的数位 D P DP DP,大概都可以用矩阵快速幂推。本质原因是每层的转移方程与这是第几层无关,比如这道题。
思路:
可以发现一个很显然的情况,就是上面说的,这道题可以矩阵快速幂转移。
不过还是要推一下普通状态转移式子才知道应该怎么构造矩阵。转移方程如下:
d
p
[
i
+
1
]
[
j
]
=
∑
x
=
m
a
x
(
j
−
2
,
0
)
m
i
n
(
0
,
j
+
2
)
d
p
[
i
]
[
x
]
dp[i+1][j]=\sum_{x=max(j-2,0)}^{min(0,j+2)}dp[i][x]
dp[i+1][j]=x=max(j−2,0)∑min(0,j+2)dp[i][x]
其中
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示最高位为
j
j
j的
构造矩阵快速幂递推即可。
注意一个问题,
k
k
k位数是没有前导0的,但是1位数有一个0,所以要特判一下。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
ll getint(){
re ll num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=10;
cs ll mod=1000000007;
struct matrix{
ll a[N][N];
matrix(int sign=0){
memset(a,0,sizeof a);
if(sign)for(int re i=0;i<N;++i)a[i][i]=sign;
}
ll *cs operator[](cs int&offset){
return a[offset];
}
friend matrix operator*(cs matrix &A,cs matrix &B){
matrix C;
for(int re i=0;i<N;++i)
for(int re j=0;j<N;++j)
for(int re k=0;k<N;++k)
C[i][j]=(C[i][j]+A.a[i][k]*B.a[k][j]%mod)%mod;
return C;
}
}A,B,res;
matrix quickpow(matrix a,ll b){
matrix ans(1);
while(b){
if(b&1)ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
ll k;
signed main(){
k=getint();
if(k==1){puts("10");return 0;}
for(int re i=1;i<10;++i)A[0][i]=1;
for(int re i=0;i<10;++i)
for(int re j=0;j<10;++j)if(abs(i-j)<=2)
++B[i][j];
res=A*quickpow(B,k-1);
ll ans=0;
for(int re i=0;i<10;++i)ans=(ans+res[0][i])%mod;
cout<<ans;
return 0;
}