数位DP

概念

数位DP往往都是这样的题型,给定一个闭区间[ l , r ] [l,r][l,r],让你求这个区间中满足某种条件的数的总数。而这个区间可能很大

其他

细节都在代码里

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; 
const int N = 63;
ll dp[N][N],a[N];



// 当前是第几位 //  (去掉前导零)有几个数字 // 有没有前导零 // 目前这意味是否到达限制(即:前面的数都取到了最大)

ll dfs(ll pos,ll num,bool lead,bool limit){
	ll sum = 0;
	if(pos == 0) return num;
	//加记忆化,且仅存在于没有前导零和没有限制的时候
	if(!lead && !limit && dp[pos][num]!=-1) return dp[pos][num];
	//是否存在限制
	int up = (limit?a[pos]:9);
	for(int i = 0;i<=up;i++){
		//有前导零
		if(i == 0 && lead) sum+=dfs(pos-1,num,true,(limit && i == up));
		else if(i == 0) sum+=dfs(pos-1,num+1,false,(limit && i == up));
		else if(i!=0) sum+=dfs(pos-1,num,false,(limit && i == up));	
	}
	//   到第几位  /   有几个数
	//记忆化 
	//没有前导零 // 没有限制
	if(!lead && !limit) dp[pos][num] = sum;
	return sum;
}


ll js(ll x){
	if(x<0) return 0;
	if(x == 0) return 1;
	ll len = 0;
	//拆分这个数
	while(x){
		a[++len] = x%10;
		x/=10;
	}
	memset(dp,-1,sizeof dp);
	return dfs(len,0,true,true);
}

void solve(){
	ll l,r;
	while(scanf("%lld%lld",&l,&r)!=EOF){
		if(l<0 && r<0) return;
		if(l == 0 && r == 0) cout<<1<<endl;
		else if(l == 0) cout<<js(r)+1<<endl;
		// 前缀和的思想
		else cout<<js(r)-js(l-1)<<endl;
	} 
}

int main(){
	solve();
	return 0;
}