HDU - 2089 不要62(数位DP)
详细见https://blog.csdn.net/HowardEmily/article/details/54744573
题目:

思路:
数据量这么大遍历是不可能的,这道题其实是数位DP的经典题。
数位DP:
数位:个、十、百、千等就是数位
实质:暴力枚举加记忆化
适用范围:在一段数的区间内找出满足某些条件的数的个数
此题思路:
用二维数组dp[i][j],其中i表示位数,j表示首位数字
得到状态转移方程:

详细见代码,但是值得注意的是:
因为求得的是小于n的数,所以求[0,n]之 间的数需要求n+ 1.
#include<bits/stdc++.h> typedef long long ll; using namespace std; int dp[10][10]; void preprocess()//预处理dp[i][j] 即首位是j有i位数的数满足条件的个数 { dp[0][0]=1; for (int i=1;i<=7;i++) for (int j=0;j<=9;j++) { if (j==4) continue; for (int k=0;k<=9;k++) if (!(j==6&&k==2)) dp[i][j]+=dp[i-1][k]; } } int cal(int n) //计算0~n之间有多少满足条件的数 { int d[10],len=0; int ans=0; while (n) //所求的0~n之间满足条件的数一位位进行分离 { d[++len]=n%10; n/=10; } d[len+1]=0; for (int i=len;i;i--) //进行状态转移 { for (int j=0;j<d[i];j++) if (d[i+1]!=6||j!=2) ans+=dp[i][j]; if (d[i]==4||(d[i+1]==6&&d[i]==2)) break; } return ans; } void solve() { int n,m; preprocess(); while ((cin>>n)&&(cin>>m)) { if (n==0&&m==0) return; cout<<(cal(m+1)-cal(n))<<endl; } } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); solve(); return 0; }

浙公网安备 33010602011771号