题 意:给你一个区间,问这个区间有多少个数字,满足不含前导0,且满足两个数位之间的差值最少位2.
输入范围
1<=l<=r<=1e6
输入样例:
【输入样例一】
1 10
【输入样例二】
25 50
输出样例:
【输出样例一】
9
【输出样例二】
20
思 路:还是一样的数位dp,状态定义dp[i][j] 枚举到第i位,前一位是j的所有数目。
忽略不能忽略前导0的常规操作。如果是除了前导0的第一位数字,则令它的前导等于一位不会出现的数字。
收获:明白了不能忽略前导0的常规操作,加一个前导0的状态
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 20;
int dp[maxn][maxn];
int a[maxn];
int l,r;
void init(){
memset(dp,-1,sizeof(dp));
}
int fab(int x){
if(x<0)return -x;
else return x;
}
int dfs(int pos,int pre,int sta,bool limit){
if(pos <= -1) return 1;
if(!limit && dp[pos][pre]!=-1) return dp[pos][pre];
int up = limit?a[pos]:9;
int ans = 0;
for(int i=0;i <= up;i++){
if(!(sta || i)){ //如果没有出现非0数字,sta一直传递下去。
ans += dfs(pos-1,12,0,limit&&i==a[pos]);
}else if(fab(i-pre)>=2){
ans+= dfs(pos-1,i,1,limit&&i==a[pos]);
}
}
if(!limit)dp[pos][pre] = ans;
return ans;
}
int solve(int x){
int pos = 0;
while(x){
a[pos++] = x%10;
x/=10;
}
return dfs(pos-1,12,0,true);
}
int main(){
init();
while(~scanf("%d %d",&l,&r)){
printf("%d\n",solve(r) - solve(l-1));
}
return 0;
}