HDU 2089 不要62 数位DP
预处理+递推
#include <iostream> using namespace std ; int f[8][10] ;//f[i][j]表示第i位是数j时符合条件的数字数量 int digit[9] ;//digit[i]表示n从右到左第i位是多少 void Init() { f[0][0]=1 ; for(int i=1 ;i<=7 ;i++) { for(int j=0 ;j<10 ;j++)//枚举第i位 { for(int k=0 ;k<10 ;k++)//枚举第i-1位 { if(!(j==6 && k==2) && j!=4)//如果符合条件 f[i][j]+=f[i-1][k] ; } } } } int callen(int n)//计算n的长度 { int cnt=0 ; while(n) { cnt++ ; n/=10 ; } return cnt ; } void caldigit(int n,int len)//计算n的digit数组 { memset(digit,0,sizeof(digit)) ; for(int i=1 ;i<=len ;i++) { digit[i]=n%10 ; n/=10 ; } } int solve(int n)//计算[0,n]区间满足条件的数字个数 { int ans=0 ; int len=callen(n) ; caldigit(n,len) ; for(int i=len ;i>=1 ;i--) { for(int j=0 ;j<digit[i] ;j++)//枚举第i位取值 { if(!(j==2 && digit[i+1]==6) && j!=4)//第i位满足条件 ans+=f[i][j] ; } if(digit[i]==4 || (digit[i]==2 && digit[i+1]==6))//第i位已经不满足条件,则i位以后都不可能满足条件,结束循环 break ; } return ans ; } int main() { Init() ; int n,m ; while(~scanf("%d%d",&n,&m)) { if(n==0 && m==0) break ; printf("%d\n",solve(m+1)-solve(n)) ;//用[0,m]-[0,n)即可得到区间[n,m] } return 0 ; }
记忆化搜索
#include <iostream> using namespace std ; int f[8][2] ;//dp[i][0]:前i位符合要求 dp[i][1]:前i位符合要求且i+1位是6 int digit[9] ;//digit[i]表示n从右到左第i位是多少 int dfs(int i,int s,bool e)//i表示当前位,s表示i位之前的状态,e表示当前位是否可以随意填写 { if(i==0) return 1 ; if(!e && f[i][s]!=-1) return f[i][s] ; int res=0 ; int u=e?digit[i]:9 ; for(int d=0 ;d<=u ;d++) { if(d==4 || (s && d==2)) continue ; res+=dfs(i-1,d==6,e&&d==u) ; } return e?res:f[i][s]=res ; } int callen(int n)//计算n的长度 { int cnt=0 ; while(n) { cnt++ ; n/=10 ; } return cnt ; } void caldigit(int n,int len)//计算n的digit数组 { memset(digit,0,sizeof(digit)) ; for(int i=1 ;i<=len ;i++) { digit[i]=n%10 ; n/=10 ; } } int solve(int n)//计算[0,n]区间满足条件的数字个数 { int len=callen(n) ; caldigit(n,len) ; dfs(len,0,1) ; } int main() { int n,m ; memset(f,-1,sizeof(f)) ; while(~scanf("%d%d",&n,&m)) { if(n==0 && m==0) break ; printf("%d\n",solve(m)-solve(n-1)) ;//用[0,m]-[0,n)即可得到区间[n,m] } return 0 ; }
记忆化搜索 V2
#include<iostream> #include<cstdio> #include<cstring> #include<string> using namespace std; typedef long long ll; int a[20]; int dp[20][2]; int dfs(int pos,int pre,int sta,bool limit) { if(pos==-1) return 1; if(!limit && dp[pos][sta]!=-1) return dp[pos][sta]; int up=limit ? a[pos] : 9; int tmp=0; for(int i=0;i<=up;i++) { if(pre==6 && i==2)continue; if(i==4) continue;//都是保证枚举合法性 tmp+=dfs(pos-1,i,i==6,limit && i==a[pos]); } if(!limit) dp[pos][sta]=tmp; return tmp; } int solve(int x) { int pos=0; while(x) { a[pos++]=x%10; x/=10; } return dfs(pos-1,-1,0,true); } int main() { int le,ri; //memset(dp,-1,sizeof dp);可优化 while(~scanf("%d%d",&le,&ri) && le+ri) { memset(dp,-1,sizeof dp); printf("%d\n",solve(ri)-solve(le-1)); } return 0; }