【题目描述】题目题目题目
原题来自:HDU 2089
杭州人称那些傻乎乎粘嗒嗒的人为 62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有 4 或 62 的号码。例如:62315,73418,88914 都属于不吉利号码。但是,61152 虽然含有 6 和 2,但不是 62 连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今后又要实际上给多少辆新的士车上牌照了。
【输入格式】
输入的都是整数对 n,m,如果遇到都是 0 的整数对,则输入结束。
【输出格式】
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
【样例输入】
1 100
0 0
【样例输出】
80
【数据范围与提示】
对于全部数据,0<n≤m<10^7。
思路:我真的不想说了
就一句话:一位一位模拟
不懂的话就直接看代码吧,我解释的很清楚了
我会摆出两个代码,一个是暴力,一个是标程
【代码实现1:暴力】
//暴力做法
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int ans[21000000];//因为是10^7,所以就定义2000万
int a,b;
int check(int x)//判断当前的数是不是有不吉利的数字
{
while(x>0)
{
if(x%10==4 || x%100==62) return 0;//一位或者两位一起判断
x/=10;//每一次判断都要除以10,进行下一次的判断
}
return true;//如果是吉利,就范围
}
int main()
{
while(scanf("%d%d",&a,&b)!=EOF)//多组数据
{
for(int i=a;i<=b;i++) //枚举a~b的范围就够了
{
ans[i]=ans[i-1]+check(i);//继承状态,上一个数+判断当前这一个数,如果是吉利的数,就加上当前这一个数
}
if(a==0 && b==0) break;//如果是0,就直接退出
printf("%d\n",ans[b]-ans[a-1]);//最后输出b的吉利数字减去a的吉利数字,就是 a~b的范围的答案
}
return 0;
}
【代码实现2:dfs】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
ll f[2100][2100];//f[i][j]表示以i为最高位的j位数的吉利数字有多少个
ll x,y;
ll a[2100],len;//len表示当前这个数的最高位,a数组是记录数位的
void dfs()
{
for(int i=0;i<=9;i++) if(i!=4) f[i][1]=1;//一位数的情况,只要不为4,这种情况就是成立的
for(int i=2;i<=10;i++)//数位的循环(2^31是十位数)
{
for(int j=0;j<=9;j++) if(j!=4)//从当前的最高位开始循环
{
for(int k=0;k<=9;k++) if(k!=4 && (j!=6 || k!=2))//次高位,只要不是4或者最高位和次高位联合起来不是62就可以
{
f[j][i]+=f[k][i-1];//当前的以j为最高位的i位数 继承的是 以次高位的k为最高位的i-1位数的状态(当前是i位,前一个就是i-1)
}
}
}
}
ll solve(int t)//寻找合适的数 //t表示当前要计算的是 //用函数表示是为了代码的简洁,不用x计算一次,y又计算一次
{
ll sum=0;//记录答案
len=0;//数位最开始要初始化(注意:不能为了方便在上面将len初始化,这样每一次计算就会归0)
if(t==0) return 1;
while(t>0)
{
a[++len]=t%10;
t/=10;
}//分离数位存储在a数组里面
a[len+1]=0;//a数组也要初始化,不用担心会计算不了,因为a[++len]会覆盖
for(int i=len;i>=1;i--)//从当前这个数的最高位开始循环,i表示的是位数
{
for(int j=0;j<a[i];j++)//保证不会超出范围 //j就是第i位数的数字
//比如说,如果是4321,a[i]=4,那么j就表示 0~3999,如果=a[i]就是0~4999 就超出了要求的数的范围了
{
if(j!=4 && (a[i+1]!=6 || j!=2)) sum+=f[j][i];
//当前这一位a[i]也可以表示为j不是4就可以继续判断,
//而且,当前这一位的上一位的数字不能为6,而且当前这一位a[i]也可以表示为j的不是2就不能凑出62,就是成立的
}
if(a[i]==4 || (a[i]==2 && a[i+1]==6)) break;
//如果循环到这个数的某一位是4,或者当前的某一位和前面一位是62,就退出,因为不符合条件
if(i==1) sum++;//如果一直循环到最后一位,就是一位数仍然成立,就记录这一种答案
}
return sum;
}
int main()
{
dfs();
while(scanf("%lld%lld",&x,&y)!=EOF)
{
if(x==0 && y==0) break;//如果x==0 并且 y==0,就没有成立的,不输出答案,直接退出
printf("%lld\n",solve(y)-solve(x-1));
}
return 0;
}
难度大概就是6吧,我是按照之前打过类似的来判断难度的