数位dp(模板&&以hdu2092为例)
数位一般来说是求在一段范围内的满足某些条的数,假如说在[ri,le]的条件下满足一定条件的数的话,那么我们就可以采用差分的方法:
就是count = solve(le) - solve(ri-1);或者count = solve(le) - solve(ri) + check(ri);
即就是满足[0,le]的数 -满足 [0,ri-1]的数;
数位dp通俗的讲就是按位上的暴力搜索然后求得的答案,我们需要从高位到低位这样搜索下去假如说我们要求满足[0,123456789]之间
某个条件的数那么我们需要先从最高位开始搜索即(1)所在的位置也就是在这个例子中的第9位在这个位置上我们可以搜索的数有(0,1)
然后我们再搜索第8位,第7位....一直到第1位,但是同时我们有不能超过所给的数字范围,所以我们在每次搜索的时候需要一个limit波尔类型
判断的数来判断他们是否达到搜索的最大值,即我们就要判断limit在上一层是否已经到达1在这层是否到达最大值的时候。其实总而言之就是dfs
对于位数上的暴力查找,然后用数组来存一下来减少一些不必要的查找。
一般来说,模板如下,这里我们以hdu2092为例
题解:我们就是从最高位开始dfs如果遇到了4就continue,如果前一位为6而遍历到这一为2时continue;最后用dp数组来存一下这时候的结果
#include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int INF = 0x3f3f3f3f; int dp[11][11][2][2]; int len; string s,t; string s_mo; int dfs(int cur,int x,bool limit,bool g)//cur位数 x代表前一位的数字 limit代表是否到达上界 g代表前置是否为零 { if(cur==len) return 1; if(!limit&&dp[cur][x][limit][g]!=-1) return dp[cur][x][limit][g]; int v = 9; if(limit) { v = s_mo[cur] - '0'; } int ans = 0; for(int i=0;i<=v;i++) { if(g==1)//前导为0的情况下 { if(i==0) { ans+=dfs(cur+1,0,limit&&i==v,1); } else if(i==4){ continue; } else{ ans+=dfs(cur+1,i,limit&&i==v,0); } } else{//前导不为0的情况下 if((x==6&&i==2)||i==4) continue; else{ ans+=dfs(cur+1,i,limit&&i==v,0); } } } return dp[cur][x][limit][g] = ans; } int solve(string ss) { mem(dp,-1); len = ss.size(); s_mo = ss; return dfs(0,0,1,1); } bool chk(string ss) { bool flag = 0; for(int i=0;i<ss.length();i++) { if(s[i]=='4') flag = 1; else if(s[i]=='6'&&s[i+1]=='2'){ flag = 1; } } return 1-flag ; } int main() { int n,m; while(cin>>s>>t)//输入字符串类型有利于从最高位开始遍历 { if(s=="0"&&t=="0") break; int ans = solve(t) -solve(s) + chk(s); cout<<ans<<endl; } return 0; }