题解:Sam 数
朴素数位 DP
一个显然的 DP:设 \(\textit{dp}_{i,j},i\in[1,k],j\in[0,9]\) 为 \(i\) 位且最高位为 \(j\) 的 Sam 数的个数。
则有:
\[\textit{dp}_{i,j}=\sum_{\max(j-2,0)}^{\min(j+2,9)}\textit{dp}_{i-1,j}
\]
最终答案 \(\textit{ans}\) 为:
\[\textit{ans}=\sum_{i=1}^9\textit{dp}_{k,i}+[k=1]\textit{dp}_{k,0}
\]
因为当 \(k\neq1\) 时,最高位不能取 \(0\)。只有 \(k=1\) 时,Sam 数为一位数,最高位可以是 \(0\)。
而边界情况即 \(k=1\) 时的答案:
\[\textit{dp}_{1,i}=1
\]
这样的复杂度是 \(\mathcal O(k)\) 的。
矩阵加速 DP
考虑到 \(1\leq k\leq10^{18}\),这个 DP 需要优化。
容易发现 \(\textit{dp}_{i,j}\) 只与常数级别的其他值有关,且是线性递推,且每次转移都是确定的,因此可以考虑矩阵加速 DP。
根据上面的递推式,可以构矩阵:
\[\begin{bmatrix}
1&1&1&0&0&0&0&0&0&0\\
1&1&1&1&0&0&0&0&0&0\\
1&1&1&1&1&0&0&0&0&0\\
0&1&1&1&1&1&0&0&0&0\\
0&0&1&1&1&1&1&0&0&0\\
0&0&0&1&1&1&1&1&0&0\\
0&0&0&0&1&1&1&1&1&0\\
0&0&0&0&0&1&1&1&1&1\\
0&0&0&0&0&0&1&1&1&1\\
0&0&0&0&0&0&0&1&1&1\\
\end{bmatrix}
\begin{bmatrix}
dp_{i,0}\\dp_{i,1}\\dp_{i,2}\\dp_{i,3}\\dp_{i,4}\\dp_{i,5}\\dp_{i,6}\\dp_{i,7}\\dp_{i,8}\\dp_{i,9}
\end{bmatrix}
=
\begin{bmatrix}
dp_{i+1,0}\\dp_{i+1,1}\\dp_{i+1,2}\\dp_{i+1,3}\\dp_{i+1,4}\\dp_{i+1,5}\\dp_{i+1,6}\\dp_{i+1,7}\\dp_{i+1,8}\\dp_{i+1,9}
\end{bmatrix}
\]
因此,可以直接得出:
\[\begin{bmatrix}
1&1&1&0&0&0&0&0&0&0\\
1&1&1&1&0&0&0&0&0&0\\
1&1&1&1&1&0&0&0&0&0\\
0&1&1&1&1&1&0&0&0&0\\
0&0&1&1&1&1&1&0&0&0\\
0&0&0&1&1&1&1&1&0&0\\
0&0&0&0&1&1&1&1&1&0\\
0&0&0&0&0&1&1&1&1&1\\
0&0&0&0&0&0&1&1&1&1\\
0&0&0&0&0&0&0&1&1&1\\
\end{bmatrix}^{k-1}
\begin{bmatrix}
dp_{1,0}\\dp_{1,1}\\dp_{1,2}\\dp_{1,3}\\dp_{1,4}\\dp_{1,5}\\dp_{1,6}\\dp_{1,7}\\dp_{1,8}\\dp_{1,9}
\end{bmatrix}
=
\begin{bmatrix}
dp_{k,0}\\dp_{k,1}\\dp_{k,2}\\dp_{k,3}\\dp_{k,4}\\dp_{k,5}\\dp_{k,6}\\dp_{k,7}\\dp_{k,8}\\dp_{k,9}
\end{bmatrix}
\]
又注意到 \(\textit{dp}_{1,0}=\textit{dp}_{1,2}=\cdots=\textit{dp}_{1,9}=1\),因此可以 \(\mathcal O\left(\log k\right)\) 求出答案。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int V=10,P=1e9+7;
ll n;
//n 行 m 列
struct Matrix{
int n,m;
//下标从 1 开始.
int a[V+1][V+1];
Matrix(){
memset(a,0,sizeof(a));
}
Matrix(int nn,int mm=-1){
memset(a,0,sizeof(a));
n=nn;m=mm;
if(m==-1){
m=n;
}
}
void print(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cerr<<a[i][j]<<' ';
}
cerr<<endl;
}
}
};
Matrix operator *(Matrix A,Matrix B){
Matrix C(A.n,B.m);
for(int i=1;i<=A.n;i++){
for(int j=1;j<=B.m;j++){
for(int k=1;k<=A.m;k++){
C.a[i][j]=(C.a[i][j]+1ll*A.a[i][k]*B.a[k][j])%P;
}
}
}
return C;
}
Matrix qpow(Matrix base,ll n){
Matrix ans(base.n);
for(int i=1;i<=base.n;i++){
ans.a[i][i]=1;
}
while(n){
if(n&1){
ans=ans*base;
}
base=base*base;
n>>=1;
}
return ans;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n;
Matrix A(V,V);
for(int i=1;i<=V;i++){
for(int j=max(i-2,1);j<=min(i+2,V);j++){
A.a[i][j]=1;
}
}
A=qpow(A,n-1);
Matrix B(V,1);
for(int i=1;i<=V;i++){
B.a[i][1]=1;
}
B=A*B;
int ans=0;
for(int i=1+(n!=1);i<=V;i++){
ans=(ans+B.a[i][1])%P;
}
cout<<ans<<'\n';
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号