HDU 3652——B-number

HDU 3652——B-number

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

题意:让你找小于等于n的数里有多少个数里含'13‘而且可以被13整除

一看是否含13,数位dp,再往后看,可以被13整除,这咋做嘛

别慌,数位dp也是ok的,除了用%判断是否整除,我们还能怎么搞?而且是按位来算的

想到了吗,模拟除法呀,这样我们只需要存上次计算的余数就可以了(算是一个状态),当含13且能被13整除答案才累加

再来一个状态存是否含13就可以了

dp[pos][num][mod]  状态为 dp[当前搜到第几位][是否含13][上一位的余数]

num=0 啥也不是

num=1 上一位是1

num=2 含13

上代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 ll a[1000009];
 5 ll dp[20][3][19];
 6 ll check(ll num,ll i)
 7 {
 8     if(num==0&&i==1||num==1&&i==1) return 1;
 9     if(num==1&&i==3||num==2) return 2;
10     return 0;
11 }
12 ll dfs(ll pos,ll num,ll mod,bool limit)
13 {
14     if(!limit&&dp[pos][num][mod]!=-1) return dp[pos][num][mod];
15     if(pos==0) return num==2&&mod==0;
16     ll up=limit?a[pos]:9;
17     ll res=0;
18     for(ll i=0; i<=up; i++)
19     {
20         res+=dfs(pos-1,check(num,i),(mod*10+i)%13,limit&&i==a[pos]);
21     }
22     if(!limit) dp[pos][num][mod]=res;
23     return res;
24 }
25 ll solve(ll x)
26 {
27     ll pos=0;
28     while(x)
29     {
30         a[++pos]=x%10;
31         x/=10;
32     }
33     return dfs(pos,0,0,1);
34 }
35 int main()
36 {
37     memset(dp,-1,sizeof(dp));
38     ll a,t;
39     while(scanf("%lld",&a)!=EOF)
40     {
41         printf("%lld
",solve(a));
42     }
43     return 0;
44 }
原文地址:https://www.cnblogs.com/YangKun-/p/12633180.html