数位dp入门(不要62题目)

统计区间 [a,b] 中不含 4 和 62 的数字有多少个。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int f[8][2],bit[8];
/*
f[i][j]:i是位数
j==0,尾位不是6
j==1,尾位是6
*/
int dfs(int pos,bool six,bool limit)
{
    if(pos<=0)return 1;
    if(!limit&&f[pos][six]!=-1)return f[pos][six];
    int up=limit?bit[pos]:9;
    int ans=0;
    for(int i=0;i<=up;i++)
    {
        if(six&&i==2)continue;
        if(i==4)continue;
        ans+=dfs(pos-1,i==6,limit&&i==up);
    }
    if(!limit)f[pos][six]=ans;
    return ans;
}
int solve(int x)
{
    memset(bit,-1,sizeof(bit));
    int len=0;
    while(x)
    {
        bit[++len]=x%10;
        x/=10;
    }
    dfs(len,0,1);
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&a,&b)&&(a+b)){
        printf("%d\n",solve(b)-solve(a-1));
    }
    return 0;

}
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>

#prag\
ma GCC optimize("O3")

using namespace std;

typedef long long LL;

typedef unsigned long long uLL;

#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define mem(a, b) memset((a), b, sizeof(a))

template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }

int read()
{
    register int sum = 0,fg = 0;char c = getchar();
    while(c < '0' || c > '9') { fg |= c == '-'; c = getchar(); }
    while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); }
    return fg ? -sum : sum;
}

const int inf = 1e9;
const int maxn = 100000;

int n,m,num;
int a[maxn];

void fj(int x)
{
    num = 0;
    while(x){a[num++] = x % 10;x/=10;}//分解每个位上数字;
}
int dp[1010][2];//dp[i][j]表示dp到i位前一位是不是6?的方案数 

int dfs(int pos,int pre,int flag,bool lim)//数位dp精华 
{
    if(pos == -1)return 1;//搜到叶子节点返回 
    if(!lim && dp[pos][flag] != -1)return dp[pos][flag];//要没有上限才能返回,因为可能引起状重复 
    int up = lim ? a[pos] : 9;//上限 ,每个数对应的上限
    int sum = 0;
    REP(i,0,up)
    {
        if(pre == 6 && i == 2)continue;
        if(i == 4)continue;//搜索可行状态 //两者都不行
        sum += dfs(pos-1,i,i==6,lim && i == a[pos]); //继续深搜,最后一个语句判断是否有限制;
    }
    if(!lim)dp[pos][flag] = sum;//没限制,
    return sum;//return;
}   

int main()
{
    while(scanf("%d%d",&n,&m) && n + m)
    {
        mem(dp,-1);fj(m);
        int ans = dfs(num-1,-1,0,1);
        fj(n-1);
        ans -= dfs(num-1,-1,0,1);//前缀和思想 //所减区间就是所求;
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lanshan1111/article/details/81940239
今日推荐