数位dp的题目(1)

昨天我们讲了数位dp当然我没有写博客,然后今天我是上完了地理课再过来的,时间少了点,就只做了一道题,但是这道题啊,因为讲过了的,所以我不想把它放在星期天的博客里面,所以我就决定今天在为数不多的时间里面写一篇博客。我时间不多的原因是因为我的数学老师zb丧心病狂地不知了四页作业,相当于一张半数学卷子

不要62

Description

杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。不吉利的数字为所有含有4或62的号码。例如:62315 73418 88914,都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。

Input

输入的都是整数对n、m,如果遇到都是0的整数对,则输入结束。

Output

对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。

Sample Input

1 100
0 0

Sample Output

80

Analysis

首先,用脑子想就可以知道,枚举是不行的,因为如果枚举可以我就不会写数位dp了。
所以说来说一说这一道题
首先设f[i][j]表示前i位的第一位是j,根据题意,那么所有的j是4的,都可以直接设置成为0了
那么不是4的应该怎么处理呢,实际上对于所有不是4的,那么这一个f的值就是

[f[i][j]=sum^{k=9}_{k=1}f[i-1][k] ]

但是题目中还有一个条件,就是题目中62不连续的在一起,所以说要在上面的式子的基础上减掉这一种情况
最后在输出答案的时候呢,还需要一个函数,用来得到正确答案。

Code

#include<bits/stdc++.h>
#define Int64 long long
using namespace std;

Int64 n,m;
Int64 f[12][10];
int tmp[12];

void init();
Int64 run(Int64 x);
inline Int64 read();

int main(){
	init();
	n=read(),m=read();
	while(n&&m){
		printf("%lld
",run(m+1)-run(n));
		n=read(),m=read();
	}
	return 0;
}

inline Int64 read(){
	Int64 sign=1,res=0;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-')sign=-1;
		c=getchar();
	}
	res=c-48;
	while((c=getchar())>='0'&&c<='9'){
		res=res*10+c-48;
	}
	return res*sign;
}

void init(){
	memset(f,0,sizeof(f));
	f[0][0]=1;
	for(int i=1;i<12;i++){
		for(int j=0;j<10;j++){
			if(j==4)f[i][j]=0;
			else{
				for(int k=0;k<=9;k++){
					f[i][j]+=f[i-1][k];
				}
				if(j==6)f[i][j]-=f[i-1][2];
			}		
		}
	}
	return ;
}

Int64 run(Int64 x){
	int cnt=0;
	Int64 ans=0;
	while(x){
		tmp[++cnt]=x%10;
		x/=10;
	}
	tmp[cnt+1]=0;
	for(int i=cnt;i>=1;i--){
		for(int j=0;j<tmp[i];j++){
			if(j==4||(j==2&&tmp[i+1]==6))continue;
			ans+=f[i][j];
		}
		if(tmp[i]==4||(tmp[i]==2&&tmp[i+1]==6))break;
	}
	return ans;
}
原文地址:https://www.cnblogs.com/perisino/p/10458055.html