[动态规划][数位dp]不要62
Problem 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
思路:似乎可以暴力?稍微修改一下,假定n,m<1e12把;进行数位dp,设状态f[i][j]表示位数为i,最高位为j的所有数中满足题意的数有多少,则状态转移方程为:
if(j==4) f[i][j]=0
else if(j!=6) f[i][j]=sum{f[i-1][k]}(k=0,1,2,3,4,5,...,9)
else f[i][j]=sum{f[i-1][k] }(k=0,1,3,4,5,...,9)
那区间[0,n)中满足题意的数就为sum{f[i][k]}(k=0~a[i]-1)(a[i]表示n的第i位数字),再减去其中包含的一些不吉利数的个数;
AC代码1:
#include <iostream> #include<cstdio> typedef long long ll; using namespace std; ll n,m; ll dp[15][15]; void get_dp(){ dp[0][0]=1; for(ll i=1;i<=12;i++){ for(ll j=0;j<=9;j++){ dp[i][j]=0; if(j==4) continue; else{ for(ll k=0;k<=9;k++) dp[i][j]+=dp[i-1][k]; if(j==6) dp[i][j]-=dp[i-1][2]; } } } } ll len=0,a[15]; void depart(ll x){ len=0; while(x){ a[++len]=x%10; x/=10; } } ll cal(ll x){ depart(x);//将x的各个位拆开 ll ret=0; for(ll i=len;i>=1;i--){ if(i<len&&a[i+1]==4) break; if(i<len-1&&a[i+1]==2&&a[i+2]==6) break; for(ll j=a[i]-1;j>=0;j--){ if(i==len) ret+=dp[i][j]; else{ if(!(a[i+1]==6&&j==2)) ret+=dp[i][j]; } } } return ret; } int main() { while(scanf("%lld%lld",&n,&m)!=EOF&&(n||m)){ get_dp(); printf("%lld\n",cal(m+1)-cal(n)); } return 0; }
AC代码2:(数位dp的dfs写法--实质是记忆化搜索,建议看一下这个教程:https://www.bilibili.com/video/av27156563?from=search&seid=6478279662422300327)
#include<cstdio> #include<algorithm> typedef long long ll; ll n,m; ll dp[15][2];//dp[i][0]表示当第i+1位不为6时,i位数中吉利数的个数;dp[i][1]表示当第i+1位为6时,i位数中吉利数的个数 ll digit[20]; ll dfs(ll len,bool last_6,bool limit){ if(len==0) return 1; if(!limit && dp[len][last_6]) return dp[len][last_6]; ll sum=0; for(ll i=0;i<=(limit?digit[len]:9);i++){ if(i!=4 && !(last_6&&i==2)) sum+=dfs(len-1,i==6,limit&&i==digit[len]); } if(!limit) dp[len][last_6]=sum; return sum; } ll solve(ll x){ digit[0]=0;//用digit[0]代替了len while(x){ digit[++digit[0]]=x%10; x/=10; } return dfs(digit[0],false,true); } int main(){ while(scanf("%lld%lld",&n,&m)&&(n+m)) printf("%lld\n",solve(m)-solve(n-1)); return 0; }
转载请注明出处:https://www.cnblogs.com/lllxq/