HDU - 3652 B-number(数位dp+ 记忆话搜索)

http://acm.hdu.edu.cn/showproblem.php?pid=3652

题意:

就是找数字中包含13并且正整除与13的数字的个数

思路:

数位dp,dp[pos][m][status],pos代表为谁,m代表对13的取模,status代表是否对13整除
status==0数字中没有13,status== 1对前一位为1,status==2数字中已经有13

LL dfs(LL pos, LL m, LL status, bool limit) {
    if(!pos) return status == 2 && m == 0;//如果pos(位数)为0,即最后一位,并且前面对13取模的值为0
    if(!limit && dp[pos][m][status]) return dp[pos][m][status];//这时前面的所有位数遍历完,并且dp[pos][m][status]有值,即搜索过,直接输出
    LL end = limit ? num[pos] : 9;//上界,limit 表示前面的数都是极限值
    LL sum = 0;
    for (LL i = 0; i <= end; i ++) {
        LL a = m;
        LL flag = status;
        if(flag == 0 && i == 1) flag = 1;
        if(flag == 1 && i == 3) flag = 2;
        if(flag == 1 && i != 1 && i != 3) flag = 0;
        sum += dfs(pos - 1, (a * 10 + i) % 13, flag, limit && i == end);
    }
    return limit ? sum : dp[pos][m][status] = sum;
}

AC代码

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define LL long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define maxn 1005
#define eps 0.00000001
#define PI acos(-1.0)
#define M 1000000007

LL dp[20][15][4], num[20];


//status==1 前一位为1, status == 2 前面有13
//limit是前面的数已经都是极限值
LL dfs(LL pos, LL m, LL status, bool limit) {
    if(!pos) return status == 2 && m == 0;//如果pos(位数)为0,即最后一位,前面并且对13取模的值为0
    if(!limit && dp[pos][m][status]) return dp[pos][m][status];//这时前面的所有位数遍历完,并且do[pos][m][status]有值,即搜索过,直接输出
    LL end = limit ? num[pos] : 9;//上界,limit 表示前面的数都是极限值
    LL sum = 0;
    for (LL i = 0; i <= end; i ++) {
        LL a = m;
        LL flag = status;
        if(flag == 0 && i == 1) flag = 1;
        if(flag == 1 && i == 3) flag = 2;
        if(flag == 1 && i != 1 && i != 3) flag = 0;
        sum += dfs(pos - 1, (a * 10 + i) % 13, flag, limit && i == end);
    }
    return limit ? sum : dp[pos][m][status] = sum;
}

LL solve(LL n) {
    num[0] = 0;
    memset(dp, 0, sizeof(dp));
    while(n) {
        num[++ num[0]] = n % 10;
        n /= 10;
    }
    return dfs(num[0], 0, 0, 1);
}

int main(int argc, const char * argv[]) {
    LL n;
    while(scanf("%lld", &n) != EOF) {
        printf("%lld\n", solve(n));
    }


    return 0;
}

你可能感兴趣的:(题解,数位dp)