HDU2089 一段区间内数字没有62和4的个数

本文介绍了一种使用数位动态规划(数位DP)的方法来解决车牌号码中不吉利数字的问题。通过递归算法统计指定范围内不含特定不吉利数字(如4或连续62)的有效车牌号码数量。


杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。 
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。 
不吉利的数字为所有含有4或62的号码。例如: 
62315 73418 88914 
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。 
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。 
Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。 
Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。 
Sample Input
1 100
0 0
Sample Output
80

自己写的第一道数位dp

dp[i][j]  i表示剩余要处理的位数(比如5位数45623 i一开始是5 到0就是都处理完了就回溯  也可以开始是4到-1回溯 )    j(0,1,2)0代表吉利 1代表上一位是6 2表示不吉利  j是表示上一层传下来的状态

dfs(int dex,int dt,int p) dex剩余要处理的位数  dt(012)状态 p(01)是否取到了最高位 (抄cjs的微笑)

#include <algorithm>    
#include <iostream>    
#include <cstdlib>    
#include <cstring>    
#include <string>  
#include <cstdio>    
#include <climits>  
#include <cmath>   
#define INF 0x3f3f3f3f  
using namespace std;  
int n,m;  
int dp[11][8];  
int digits[11];  
int dfs(int dex,int dt,int p){  //计算不吉利的数字个数
    int ans=0;  
    if(dex==0) return dt==2;  
    if(dp[dex][dt]!=-1&&!p) return dp[dex][dt];  
    int u=p?digits[dex]:9;  
    for(int i=0;i<=u;i++){  
        if(i==4||dt==1&&i==2||dt==2) ans+=dfs(dex-1,2,p&&i==u);  
        else if(i==6) ans+=dfs(dex-1,1,p&&i==u);  
        else ans+=dfs(dex-1,0,p&&i==u);  
    }  
    if(!p) dp[dex][dt]=ans;  
    return ans;  
      
}  
int digit(int num){  
    int k=0;  
    while(num){  
        digits[++k]=num%10;  
        num/=10;  
    }  
    return dfs(k,0,1);  
}  
int main(){  
    memset(dp,-1,sizeof(dp));  
    while(scanf("%d%d",&n,&m)==2&&(n||m)){  
        int k1=digit(m),k2=digit(n-1);  
        printf("%d\n",m-n+1-(k1-k2));  
    }  
  return 0;  
}  
或者直接求吉利数字的个数(网上看到不知道是哪位大佬写的)


#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n,m,dp[20][2],digit[20];
int dfs(int len,int six,int top)//len剩余处理的位数 上一个数字是否为6 top是否取到最高位
{
	if (!len) return 1;
	if (!top&&dp[len][six]!=-1) return dp[len][six];
	int ans=0,u=top?digit[len]:9;
	for (int i=0;i<=u;++i){
		if (i==4||six&&i==2) continue;//跳过4和62
		ans+=dfs(len-1,i==6,top&&i==u);
	}
	if (!top) 
		dp[len][six]=ans;
	return ans;
}
int slove(int n)
{
	int len=0;
	while (n){
		digit[++len]=n%10;
		n/=10;
	}
	return dfs(len,0,1);
}
int main()
{
	memset(dp,-1,sizeof(dp));
	while (scanf("%d%d",&n,&m)>0&&(n||m)){
		printf("%d\n",slove(m)-slove(n-1));
	}
}





























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值