数位DP是一种计数用的dp,一般就是要统计一个区间 [ l, r ]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位......数的每一位就是数位啦!
也就是说到处理问题时与数的临位数位之间的联系时,可以优先考虑数位DP,注意到记忆化搜索也是可行的,这取决于个人喜好,总之我们通常称之为数位DP问题。
经典例题:Atcoder Beginner Conteset 242 C
给你一个整数n,问 由n位 数字,每一位上的数字在一到九之间,所组成的数中,相邻位的两个数之差的绝对值不大于一的 数有多少个。
设 f[ i ] [ j ] 表示n 位 10 进制整数以 j 开头 的 符合要求的 数的个数;(数位DP最常见的设法)
状态转移方程为 f [ i ] [ j ]=f [ i-1 ] [ j-1 ] +f[ i-1 ] [ j ]+f[ i-1 ] [ j+1 ]
需要注意边界和初始条件。(避免出现数组下标为负数,和初始化赋值问题);
AC 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
const int MOD=998244353;
typedef long long ll;
ll n;
ll ans=0;
ll f[N][10];
int main(){
ll n;
cin>>n;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=9;j++)
{
if(i==1)f[i][j]=1;
else {
if(j==1) f[i][j]=f[i-1][j]+f[i-1][j+1];
if(j==9) f[i][j]=f[i-1][j]+f[i-1][j-1];
else f[i][j]=f[i-1][j-1]+f[i-1][j]+f[i-1][j+1];
f[i][j]%=MOD;
}
}
}
for(int i=1;i<=9;i++)
ans+=f[n][i],ans%=MOD;
cout<<ans<<endl;
return 0;
}