数位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;
}

浙公网安备 33010602011771号