HDU 3652 B-number(数位dp)

题意:B数的定义是有字符串“13”且能被整数13整除的数,求[1,n]内的B数个数。

题解:这是数位DP,我也就是刚入门,前两天看到了非递归写法,好麻烦。所以我建议写dfs的方法,容易理解,代码还简短。

在这说一下整除13的事,比如1523这个数,你把它用手自己模拟一遍,发现是15先%13==2,之后是(2*10+2)%13==9 ……,以此类推,最后mod==0&&ok==1,才返回1,(ok标记的是 是否出现过“13”)。

AC代码:

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int INF=0x3f3f3f3f;
typedef long long ll;
typedef unsigned long long ull;
#define prN printf("
")
#define SI(N) scanf("%d",&(N))
#define SII(N,M) scanf("%d%d",&(N),&(M))
#define SIII(N,M,K) scanf("%d%d%d",&(N),&(M),&(K))
#define cle(a,val) memset(a,(val),sizeof(a))
#define rep(i,b) for(int i=0;i<(b);i++)
#define Rep(i,a,b) for(int i=(a);i<=(b);i++)
#define reRep(i,a,b) for(int i=(a);i>=(b);i--)
const int MAX_N= 1000+5 ;
const double eps= 1e-9 ;

int n,dp[20][10][13][2],digit[20];
int dfs(int pos,int pre,int mod,bool limit,bool ok)
{
    //结束判断
    if (pos==0) return ok&&mod==0;
    //记忆化判断
    if (dp[pos][pre][mod][ok]!=-1&&!limit) return dp[pos][pre][mod][ok];
    int top=limit?digit[pos]:9;
    int cnt=0;
    for (int i=0;i<=top;i++)
    {
        if (i==3&&pre==1) cnt+=dfs(pos-1,i,(mod*10+i)%13,limit&&i==top,1);
        else cnt+=dfs(pos-1,i,(mod*10+i)%13,limit&&i==top,ok);
    }
    if (!limit) dp[pos][pre][mod][ok]=cnt;
    return cnt;
}
int main()
{
    while(~SI(n))
    {
        cle(dp,-1);
        int len=0;
        while(n)
        {
            digit[++len]=n%10;
            n/=10;
        }
        printf("%d
",dfs(len,0,0,1,0));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/s1124yy/p/5546783.html