B-number
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
解题思路:
数位DP。
对于第一个限制出现13 枚举时区分三种状态:
1、前面已经出现过13 记为状态2
2、前面没出现13但前一位是1 记为状态1
3、前面没出现13且前一位不是1 记为状态0
对于第二个限制,在枚举每一位的时候对上一位留下来的数乘10+i再取模,这个想了好久,有一个定理证明的。但是我没想那么多,也就写了几个数发现好像是这样就写了,结果就过了。。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
using namespace std;
int a[20];
int dp[20][20][5];
int dfs(int pos,int pre,int sta,int limit,int flag)
{
if(pos == -1) return (flag == 2 && sta == 0);
if(!limit && dp[pos][sta][flag] != -1) return dp[pos][sta][flag];
int up = limit ? a[pos] : 9;
int tmp = 0;
for(int i = 0 ;i <= up ; i ++)
{
tmp += dfs(pos-1,i,(sta*10+i)%13,limit && a[pos] == i ,
(flag == 2 ? 2 : ((pre == 1 && i == 3) ? 2 : (i == 1 ? 1 : 0) ) ));
}
if(!limit) dp[pos][sta][flag] = tmp;
return tmp;
}
int solve(int x)
{
int pos = 0;
while(x)
{
a[pos++] = x%10;
x /= 10;
}
return dfs(pos-1,0,0,1,0);
}
signed main()
{
int n,a,b;
memset(dp,-1,sizeof(dp));
while(cin>>n)
cout<<solve(n)<<endl;
return 0;
}