数位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\n",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;
}
我不求被他人理解,被理解类似于自我卖淫