HDU 3652 B-number(数位dp&记忆化搜索)

来源:互联网 发布:查外文最全的数据库 编辑:程序博客网 时间:2024/06/13 19:01

题目链接:[kuangbin带你飞]专题十五 数位DP G - B-number

题意

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

思路

首先,了解这样一个式子:a%m == ((b%m)*c+d)%m;
式子的正确是显然的,就不证明了。
那么判断数是否可以被13整除就可以分解为一位一位进行处理。
当然,我们也只需要储存取余后的值。
dfs(len, num, mod, flag)
mod记录数字对13取余后的值
len表示当前位数
num==0 不含13且上一位不为1
pre==1 不含13且上一位为1
pre==2 含13
flag表示是否可以任意取值(判断范围)。
如此,记忆化搜索即可得解。

代码

#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cstdlib>#include <vector>using namespace std;#define LL long long#define MOD 13LL 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;}
1 0