HDU 3652 - B-number - [数位DP]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3652

Problem Description
A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.
 
Input
Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).
 
Output
Print each answer in a single line.
 
Sample Input
13
100
200
1000
 
Sample Output
1
1
2
2
 
题意:
给出一个数N,问1~N这N个数中,含有“13”并且能被13整除的数(例如13,1313,2613)有多少个。
 
题解:
N达到1e9,使用数位DP;
(做了许多数位DP了,题解什么的不想再仔细写了,建议在有数位DP基础的情况下阅读以下内容)
dfs(pos, mod, pre, have13, limit):
  ①pos,不讲了……
  ②mod,表示之前位除以13所得的余数;
  ③pre,记录前一位;
  ④have13,记录曾经是否出现过“13”;
  ⑤limit,不讲了……
dp数组直接无修改记忆化:即定义为dp[pos][mod][pre][have13],空间管够~
 
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int dig[12];
ll dp[12][13][10][2];
ll N;

ll dfs(int pos,int mod,int pre,bool have13,bool limit)
{
    if(pos==0) return have13 && mod==0;

    if(!limit && dp[pos][mod][pre][have13]!=-1) return dp[pos][mod][pre][have13];

    int up=limit?dig[pos]:9;
    ll ans=0;
    for(int i=0;i<=up;i++)
    {
        if(pre==1 && i==3) ans+=dfs(pos-1,(mod*10+i)%13,i,1,limit && i==up);
        else ans+=dfs(pos-1,(mod*10+i)%13,i,have13,limit && i==up);
    }

    if(!limit) dp[pos][mod][pre][have13]=ans;

    return ans;
}
ll solve(ll x)
{
    int len=0;
    while(x)
    {
        dig[++len]=x%10;
        x/=10;
    }
    return dfs(len,0,0,0,1);
}

int main()
{
    while(scanf("%I64d",&N)!=EOF)
    {
        memset(dp,-1,sizeof(dp));
        printf("%I64d\n",solve(N));
    }
}

 

posted @ 2018-03-08 20:30  Dilthey  阅读(357)  评论(0编辑  收藏  举报