B-number

题目链接:https://vjudge.net/problem/HDU-3652

题意:如果一个数是13的倍数且数中含有13,那这个数是一个b数,问你1到n里有多少个b数。

思路:普通的数位dp,因为数中要含有13,可以用state来记录13状态,如果已经含有13了,那state=2,如果末尾是1,state=1,否则state=0。用mod记录前len位%13的结果,其他和模板差不多。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dp[20][20][5];
int a[20];
//len代表当前枚举的位,mod代码前len%13的值,state代表是否已经含有13的状态,flag代表是否还是处于上边界
int dfs(int len,int mod,int state,bool flag)
{
    if(len==0)
        return mod==0&&state==2;
    int up=flag?a[len]:9;//决定你枚举的上界是多少
    if(!flag&&dp[len][mod][state]!=-1)
        return dp[len][mod][state];//如果不是处于上边界并且之前求过了值的话可以直接返回
    int tmp=0;
    for(int i=0; i<=up; i++)
    {
        int mo=(mod*10+i)%13;
        int sta=state;
        if(state==0&&i==1)
            sta=1;
        else if(state==1&&i!=1&&i!=3)
            sta=0;
        else if(state==1&&i==3)
            sta=2;
        tmp+=dfs(len-1,mo,sta,flag&&i==a[len]);
    }
    if(!flag)
        dp[len][mod][state]=tmp;//求了值用dp存下,下次可以使用
    return tmp;
}
int suan(int x)
{
    int pos=0;
    while(x)
    {
        a[++pos]=x%10;
        x/=10;
    }
    return dfs(pos,0,0,true);
}
int main()
{
    int n;
    memset(dp,-1,sizeof(dp));
    while(~scanf("%d",&n))
    {
        cout<<suan(n)<<endl;
    }
}
原文地址:https://www.cnblogs.com/zcb123456789/p/13669180.html