数位dp是一种计数的dp,一般统计满足区间【L,R】内满足条件的一些数的个数,数位就是对一个数的每一位进行dp,即个位,十位,百位。。。数的每一位。一般当数据比较大时就可考虑数位dp,一般是枚举区间【1,R】减去区间【1,L-1】得。下面就是一个简单的基础模板。
#include<bits/stdc++.h>
using namespace std;
int a[50];
int dp[50][50];
int dfs(int num, ,bool limit) //位数,传递条件 ,上界判断
{
if(num==-1)return 0; //最后一位时,根据情况返回1或0
if(!limit && dp[num][ ]!=-1) //已经走过此种状态,记忆化
return dp[num][ ];
int ans=0; //计数
int up=limit?a[num]:9; //上界
//枚举计数
for(int i=0;i<=up;i++){
if()
if()
//... 题目限制条件
ans+=dfs(num-1, ,limit && i== up);//传递,状态转移
}
if(!limit) //判断是否可以储存
dp[num][ ]=ans;
return ans;
}
int solve(int x)
{
int num=0;
while(x){ //将x每一位存入数组中
a[num]=x%b; //b表示进制!!!
num++;
x/=b;
}
return dfs(num-1,/* 题目限制条件 */,true);//传递
}
int main()
{
int l,r;
memset(dp,-1,sizeof(dp));
while(scanf("%d%d",&l,&r)!=EOF)
{
printf("%d\n",solve(r)-solve(l-1));
}
return 0;
}
例题:HDU 2089 不要62代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
typedef long long ll;
int a[20];
ll dp[20][5];
ll dfs(int num,int now,bool limit){
if(num==0){
if(now==2)
return 1;
else
return 0;
}
if(!limit&&dp[num][now]!=-1)
return dp[num][now];
int up=limit?a[num]:9;
ll ans=0;
for(int i=0;i<=up;i++){
if(now==0){
if(i==4)
ans+=dfs(num-1,2,limit&&up==i);
else if(i==6)
ans+=dfs(num-1,1,limit&&up==i);
else
ans+=dfs(num-1,0,limit&&up==i);
}
else if(now==1){
if(i==2)
ans+=dfs(num-1,2,limit&&up==i);
else if(i==6)
ans+=dfs(num-1,1,limit&&up==i);
else if(i==4)
ans+=dfs(num-1,2,limit&&up==i);
else
ans+=dfs(num-1,0,limit&&up==i);
}
else
ans+=dfs(num-1,now,limit&&up==i);
}
if(!limit)
dp[num][now]=ans;
return ans;
}
int main()
{
ll n,m;
while(~scanf("%lld%lld",&n,&m)){
if(n==0&&m==0)
break;
ll x=n,y=m;
memset(dp,-1,sizeof(dp));
int num=0;
a[0]=0;
n--;
while(n){
num++;
a[num]=n%10;
n/=10;
}
ll tmp1=dfs(num,0,true);
//cout<<"tmp1="<<tmp1<<endl;
memset(dp,-1,sizeof(dp));
num=0;
while(m){
num++;
a[num]=m%10;
m/=10;
}
ll tmp2=dfs(num,0,true);
//cout<<"tmp2="<<tmp2<<endl;
printf("%lld\n",y-x+1-(tmp2-tmp1));
}
return 0;
}