懂了简单模板之后用起来就是舒服,跟着题目的数值和条件改一改就能过
题目链接:HDOJ2089
题目是不要62或者4出现,HDOJ3555是需要49出现,这有什么本质区别吗?
拿着代码改一改就好了
同样的,细节见代码哦
#include<map>
#include<set>
#include<math.h>
#include<time.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cstdlib>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define ll rt<<1
#define rr rt<<1|1
#define LL long long
#define ULL unsigned long long
#define maxn 1050
#define maxnum 1000050
#define eps 1e-6
#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)
/*
dp[len][0]:前len位不含62且不含4
dp[len][1]:前len位不含62且不含4且第len位为2(在加高位的6就可以符合题意了)
dp[len][2]:前len位已有62或者4
*/
__int64 m,n;
int digit[20];
__int64 dp[20][5];
__int64 dfs(int pos,int status,bool flag){
if (pos==0) return status==2;
//pos==0已经枚举完了
//写成if (status==2) return 1;
//else return 0;更好理解吧
if (flag&&dp[pos][status]!=-1) return dp[pos][status];
//dp不是-1是基本记忆化套路
//flag==true就是表示在高位的枚举中有某一位小于n的对应位了,所以这些数在【0,n】 区间内
//需要计数
int num=flag?9:digit[pos];
//如果flag=1,低位可以从0枚举到9
//否则只能枚举到n的相应位的数值
__int64 ans=0;
for(int i=0;i<=num;i++){
if (status==2||(status==1&&i==2)||i==4) ans+=dfs(pos-1,2,flag||i<num);
//原来已经有了62或者4
//或者原来枚举的len-1位是6,且第len位枚举的是2
//或者这次枚举的是4
else if (i==6) ans+=dfs(pos-1,1,flag||i<num);
//第len位枚举的是6,符合status=1
else ans+=dfs(pos-1,0,flag||i<num);
//不是任何特殊情况,那就是status=0
}
if (flag) dp[pos][status]=ans;
//flag=1,说明可以计数
//否则,这个数会大于n,计数没有意义
return ans;
}
__int64 calc(__int64 n){
//标准格式
//将n分解成各个数位,从高到低
int pos=0;
while(n){
digit[++pos]=n%10;
n/=10;
}
return dfs(pos,0,0);
}
int main(){
//input;
while(scanf("%I64d%I64d",&m,&n)!=EOF){
if (!m&&!n) break;
memset(digit,0,sizeof(digit));
memset(dp,-1,sizeof(dp));
printf("%I64d\n",(n-m+1)+calc(m-1)-calc(n));
//HDOJ3555记录的是要49的
//HDOJ2089记录的是不要62或者4的,要看清楚题
//而且要用,【l,r】=【0,r】-【0,l-1】
}
return 0;
}