1. 程式人生 > >hdu2089 不要62 數位dp模板

hdu2089 不要62 數位dp模板

題意:數字中包含62或者4的數是壞數字,現在要你求[n,m]中有多少個好數字。

題意:數位dp,套模板(寫這篇主要是粘個板子)。

程式碼:

#include<bits/stdc++.h>
#define debug cout<<"aaa"<<endl
#define d(a) cout<<a<<endl
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define MIN_INT (-2147483647-1)
#define MAX_INT 2147483647
#define MAX_LL 9223372036854775807i64
#define MIN_LL (-9223372036854775807i64-1)
using namespace std;

const int N = 1000000 + 5;
const int mod = 1000000000 + 7;
const double eps = 1e-8;
int dp[10][15][3],DIG[10];

int dfs(int pos,int pre,bool status,bool limit){
	//已搜到盡頭,返回"是否找到了答案"這個狀態
	if(pos<1){
		return status;
	} 
    //DP裡儲存的是完整的,也不受限的答案,所以如果滿足的話,可以直接返回。
	if(!limit&&dp[pos][pre][status]!=-1){
		return dp[pos][pre][status];
	}
	int end=limit?DIG[pos]:9;
	int ret=0;
	//往下搜的狀態表示的很巧妙,status用||是因為如果前面找到了答案那麼後面
    //還有沒有答案都無所謂了。而limti用&&是因為只有前面受限、當前受限才能
    //推出下一步也受限,比如567,如果是46X的情況,雖然6已經到盡頭,但是後面的
    //個位仍然可以隨便取,因為百位沒受限,所以如果個位要受限,那麼前面必須是56。
    //
    //這裡用"不要62和4"一題來做例子。
    for(int i=0;i<=end;i++){
    	ret+=dfs(pos-1,i,status||(pre==6&&i==2)||i==4,limit&&(i==end));
    }
    //DP裡儲存完整的、取到盡頭的資料
    if(!limit){
    	dp[pos][pre][status]=ret;
    }
    return ret;
}
//計算出[0-x]有多少個壞數字 
int solve(int x){
	mem(dp,-1),mem(DIG,0);
	int p=1;
	while(x){
		DIG[p++]=x%10;
		x/=10;
	}
	p--;
	return dfs(p,-1,0,1);
}

int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		if(n==0&&m==0){
			break;
		}
		printf("%d\n",(m-n+1)-(solve(m)-solve(n-1)));
	}
	return 0;
}