Description
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有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是什么意思,而且该怎么解……模板每一句话的意思与作用……
下面是数位通用模板的代码与解释:
int dfs(int i, int s, bool e) { if (i==-1) return s==target_s; if (!e && ~f[i][s]) return f[i][s]; int res = 0; int u = e?num[i]:9; for (int d = first?1:0; d <= u; ++d) res += dfs(i-1, new_s(s, d), e&&d==u); return e?res:f[i][s]=res; }
f为记忆化数组; i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数); s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t); 在这题中s==0时表示即不含有6和4的,s==1时表示含有6不含有4的,s==2时表示含有4或者62的 e表示之前的数是否是上界的前缀(即后面的数能否任意填)。
#include <iostream> #include <map> #include <deque> #include <queue> #include <stack> #include <string> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <map> #include <set> using namespace std; int n,m,f[10][10],num[10]; int dfs(int i,int s,bool e) //i为第几个数,s为每个数的状态,在本题中共设0,1,2三个状态,上面已经说过 { if(i==-1) return 1; //因为4和62的情况continue掉了,所以返回s==0||s==1肯定是真的,真就是返回1 if(!e&&f[i][s]!=-1) return f[i][s]; //记忆哪个数时前面已经有多少个符合的数,直接返回就行 int res=0; int u=e?num[i]:9; //下一个数可以取多少 for(int d=0; d<=u; ++d) //有时候d不得取0,那么判断一下看看得不得取 { if(s==6&&d==2) continue; else if(d==4) continue; else res+=dfs(i-1,d,e&&d==u); } return e?res:f[i][s]=res; } int open(int x) { int k=0; while(x) { num[k++]=x%10; //从后往前取每位的数存入数组中 x/=10; } return k; } int gets(int n) { int mm=open(n); return dfs(mm-1,0,1); } void solve() { printf("%d\n",(gets(m)-gets(n-1))); } int main() { memset(f,-1,sizeof(f)); while(scanf("%d%d",&n,&m)&&(n||m)) solve(); return 0; }