思路:逐位处理,在依次遍历十进制的每一位数字的基础上不断更新状态,从而求解dp[i][s]表示第i位,状态为s的数字的个数。
例题一:传送门
思路:求和,然后对N取余。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long LL; LL A,B,N,a[120],dp[50][120]; LL dfs(LL pos,LL stu,bool done) { if(pos==-1) return stu%N==0?1:0; if(!done&&~dp[pos][stu]) return dp[pos][stu]; LL tp,len=(done?a[pos]:9),i,ans=0; for(i=0;i<=len;i++){ tp=(stu+i)%N; ans+=dfs(pos-1,tp,done&&(i==len)); } if(!done) dp[pos][stu]=ans; return ans; } LL solve(LL x) { memset(dp,-1,sizeof(dp)); LL pos=0; while(x){ a[pos++]=x%10;x/=10; } return dfs(pos-1,0,true); } int main(void) { while(~scanf("%lld%lld%lld",&A,&B,&N)){ printf("%lld ",solve(B)-solve(A-1)); } return 0; }
例题二(hdu-2089):传送门
思路:判断62(前一个状态和后一个状态),判断4。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int dp[120][50],a[50],n,m; int dfs(int pos,int stu,bool done) { if(pos==-1) return 1; if(!done&&~dp[pos][stu]) return dp[pos][stu]; int tp,len=(done?a[pos]:9),i,ans=0; for(i=0;i<=len;i++){ if(i==4||(stu==6&&i==2)) continue; ans+=dfs(pos-1,i,done&&(len==i)); } if(!done) dp[pos][stu]=ans; return ans; } int solve(int x) { memset(dp,-1,sizeof(dp)); int pos=0; while(x){ a[pos++]=x%10; x/=10; } return dfs(pos-1,0,true); } int main(void) { while(~scanf("%d%d",&n,&m)&&(n+m)){ if(n>m){ int tp=n;n=m;m=tp; } printf("%d ",solve(m)-solve(n-1)); } return 0; }