数位DP(解释和模板)

其实数位DP就是优化计数的过程。

如果事事用爆破的话就太有病了!!!除非我吃拧了!!!小学生都不会干的傻事!!!

 其实数位dp就是dfs+记忆化数组

 题目会给一个上界或者下界

 然后让你统计范围内符合要求的数量!!!

解题步骤:

1.处理数位函数 cal() solve() ...自己命名 > 将输入的数进行分解

 2.dfs的函数 => 执行的是数位dp(dfs+记忆化搜索)

 

 

例题体面:简单而言就是一个区间内含  49   的数有多少!!!

Bomb

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 23481    Accepted Submission(s): 8845


 

Problem Description

The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the blast would add one point.
Now the counter-terrorist knows the number N. They want to know the final points of the power. Can you help them?

 

Input

The first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.

The input terminates by end of file marker.

Output

For each test case, output an integer indicating the final points of the power.

 

Sample Input

3 1 50 500

Sample Output

0 1 15

Hint

From 1 to 500, the numbers that include the sub-sequence "49" are "49","149","249","349","449","490","491","492","493","494","495","496","497","498","499", so the answer is 15.
#include<iostream> 
using namespace std;
typedef long long LL;

int digit[20];//数位 
LL dp[20][2];//当前数位 含有4时,区间内有多少数 没有49 当前数位不是4时 区间内有多少数 没有49 !!! 


LL dfs(int len,bool if4,bool limit){
	//len表示当前位 !!   if4表示len的上一位是否是4 !!   limit表示当前位的最大约束 !! 
	
    if(len==0) return 1;  //个位数时  满足条件的个数仅为一! 
    
    if(!limit && dp[len][if4]) return dp[len][if4];
    //当前数位的数 没有到达上界,且统计过  则直接返回!! 
    //典型的记忆化 的语句!! 

    LL cnt=0; 

	LL up_bound=(limit?digit[len]:9);//当前位  上界的约束!! 
	
    for(int i=0;i<=up_bound;++i){
        if(if4 && i==9)  // 上一位是4 且 这一位是9  这直接跳过 !! 
            continue;    //剪枝 ! 
            
        cnt+=dfs(len-1,(i==4)?1:0,/*为下一位设上限 !!*/limit&&i==up_bound);
        
    }
    if(!limit) dp[len][if4]=cnt;
    //如果这一位 不含上界则作为完整的数 可以记录下来 !! 
    //统计在数位上  下次dfs时以便遇见直接返回!! 
    return cnt;
}

LL solve(LL num){
    int k=0;
    while(num){//数位的分解 
        digit[++k]=num%10;
        num/=10;
    }
    return dfs(k,false,true);//dfs记忆爆搜 
}

int main(){
    int T;
    LL N;
    cin>>T;
    while(T--){
        cin>>N;
		
		//N+1  是因为 有前导0 但前导0是不需要计入其中的  !! 
        cout<<N+1-solve(N)<<endl;
    }
    return 0;
}

///HDU 2089

不要62

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 58083    Accepted Submission(s): 22807


 

Problem Description

杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有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

题意:不要62和4

///HDU 2089

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

int digit[20];
LL dp[20][2];

///if4=>status(状态)是否是6
LL dfs(int len,bool if6,bool limit){
    if(len==0) return 1ll;
    if(!limit && dp[len][if6]) return dp[len][if6];

    LL cnt=0,up_bound=(limit?digit[len]:9);
    for(int i=0;i<=up_bound;++i){
        if(if6 && i==2)///=>找到一个49
            continue;
        if(i==4) continue;//剪枝
        cnt+=dfs(len-1,i==6,limit&&i==up_bound);
    }
    if(!limit) dp[len][if6]=cnt;
    return cnt;
}
///统计的是没有62的个数
LL solve(LL num){
    int k=0;
    while(num){
        digit[++k]=num%10;
        num/=10;
    }
    return dfs(k,false,true);
}

int main(){

    LL N,M;
    while(cin>>N>>M && N+M){

//注意0 0 的特判  当n=0时,n-1=-1,这时solve(-1)代入跑dfs,得出的结果就还真是0
//所以我感觉这套板子的强度很大!!!   满足卡特判的活!!!
//精髓在   !!!卡特判!!!
        cout<<solve(M)-solve(N-1)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mlm5678/article/details/82708229