HDU 3652 区间有13并且这样整除13 的数量(数位DP)

题目:求1~n的范围里含有13且能被13整除的数字的个数。

分析:

dfs(len, num, mod, flag)
mod记录数字对13取余后的值
len表示当前位数
num==0 不含13且上一位不为1
pre==1 不含13且上一位为1
pre==2 含13
flag表示是否可以任意取值(判断范围)。
如此,记忆化搜索即可得解。

总结:我是在最后才判断是否可以%13 , 但是这是不可以的 , 经过这道题后,理解更好了 ;

 

这里有个式子特别重要 : 关于连加取mod ,      例如: 123%13=(100+20+3)%13 = ((1%13*10+2)%13*10+3)%13; !!!!!  这在数位dp很重要

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>

using namespace std;

#define LL long long
#define MOD 13
LL dp[20][3][13];
int dis[20];

LL dfs(int len, int type, int mod, bool flag)
{
    if(len < 0)
        return type == 2 && mod == 0;
    if(!flag && dp[len][type][mod]!=-1)
        return dp[len][type][mod];
    int end = flag?dis[len]:9;
    int ans = 0;
    for(int i=0; i<=end; i++)
    {
        if(type == 2 || (type == 1 && i == 3))
            ans += dfs(len-1, 2, (mod*10+i)%MOD, flag&&i==end);
        else
            ans += dfs(len-1, i==1?1:0, (mod*10+i)%MOD, flag&&i==end);
    }
    if(!flag)
        dp[len][type][mod] = ans;
    return ans;
}

LL solve(LL n)
{
    int len = 0;
    while(n)
    {
        dis[len++] = n%10;
        n /= 10;
    }
    return dfs(len-1, 0, 0, 1);
}

int main()
{
    int n;
    memset(dp, -1, sizeof(dp));
    while(cin>>n)
        cout<<solve(n)<<endl;
    return 0;
}
View Code

 

posted @ 2018-11-08 20:48  shuai_hui  阅读(257)  评论(0编辑  收藏  举报