牛客训练三:处女座和小姐姐(三)(数位dp)

题目链接:传送门

思路:数位dp的记忆化搜索模板

从高位向低位枚举,逐位确定每一位的6的个数,dp[i][s]表示处理到第i条边,状态为s时的数字的个数。

注意,要使用long long类型。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
LL a[50],dp[50][50],x,y;
LL dfs(LL pos,LL statue,bool done) //pos表示位数,statue表示当前的状态(不同的题目改变不同的状态,本题只表示前i位中是否有6),done表示是否处理 
{
    if(pos==-1) return statue; //位数超限 
    if(!done&&~dp[pos][statue]) return dp[pos][statue]; //此状态已存在,直接返回已有的值即可 
    LL i,ans=0,len=(done?a[pos]:9); //len用于找出当前位要处理的个数,如果未标记(done=0)就是0-9,否则0-a[pos]。 
    for(i=0;i<=len;i++){
        ans+=dfs(pos-1,statue||i==6,done&&a[pos]==i); //ans用于求前i位的6的数字之和 
    }
    return (!done)?(dp[pos][statue]=ans):ans; //优化,记录已有的数据。 
} 
LL solve(LL x)
{
    LL pos=0;
    memset(dp,-1,sizeof(dp));
    while(x){
        a[pos++]=x%10; //预处理 
        x/=10;
    }
    return dfs(pos-1,0,true);
}
int main(void)
{
    while(~scanf("%lld%lld",&x,&y)){
        printf("%lld
",solve(y)-solve(x-1));
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/2018zxy/p/10329276.html