题目如下:
最基础的数位dp题目,半年前学的就已经忘得差不多了,比赛的时候写了快两个小时。。。
思路很容易想到,即求0~l-1中符合要求的数,再求0~r中符合要求的数,两个减一下就是区间[l,r]中符合要求的数
我用的是先求出0~n中不含6的个数,减一下就能得到含6的个数,这道题的数位dp只需要两步;
1.先求出dp数组,dp[i][j]的值代表最高位i为j时0~jXXX...包含6的个数,具体的步骤网上有解释,这里不写了
2.从高位到低位逐位计算0到...(a[i+2])(a[i+1])(a[i]-1)XXX...中不含6的数,计算到最低位即可得到0~n-1中不含6的个数,注意到若该位为6则不必则中止,因为计算到该位时已经保证前面的高位已知,高位含有6即不满足条件。
最后按照上面的步骤就能得到结果。
代码如下:
#include <iostream> #include <cstdio> #include <cstring> #define ll long long using namespace std; int a[20]; ll dp[20][20]; ll solve(ll x){ ll tmp = x; int len=0; ll ans=0; while(x){ a[++len] = x%10; x/=10; } a[len+1]=0; for(int i=len;i>=1;i--){ for(int j=0;j<a[i];j++){ ans += dp[i][j]; } if(a[i]==6) break; } return tmp-ans; } int main() { long long l,r; cin >> l >> r; memset(dp,0,sizeof(dp)); for(int i=0;i<10;i++) dp[1][i] = 1; dp[1][6] = 0; for(int i=2;i<20;i++)//初始化数位dp数组,计算最高位i为j时从0到i999...中不包含6的个数 for(int j=0;j<10;j++) for(int k=0;k<10;k++) if(j!=6 && k!=6) dp[i][j] += dp[i-1][k]; cout << solve(r+1) - solve(l) << endl; return 0; }