B-number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 10837 Accepted Submission(s): 6431
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
Author
wqb0039
Source
2010 Asia Regional Chengdu Site —— Online Contest
题目链接:hdu-3652
题解:我把叙述都写在代码里面了 注释
#include <cstring>
#include <cstdio>
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
const int N =1e5+100;
int dp[15][3][15];//dp[pos][str][num];
int a[15];//存数字 每一位
int gett(int str,int i)//上一位状态和这一位数字
{//作用就是更新数位状态
if(str==0)//上一位不是1
{
if(i==1) return 1;//若这位为1,则return 1
else return 0;//若这位不是1 ,则return 0
}
else if(str==1)//上一位为1
{
if(i==1) return 1;//若这位为1,则return 1
if(i==3) return 2;//若这位为3,则return 2
return 0;//否则,return 0
}
return 2;//出现过13,则 return 2
}
int dfs(int pos,int str,int num,bool limit)//pos是数位 str表示上一位是不是1 0表示不是1 1表示是1 2表示已经出现13 num是%13之后的数字 limit表示当前位的上界
{
if(pos==-1) return num==0&&str==2;//**(重点)**题目有两个条件,num%13==0并且str==2(包含13);这样的数字才计数。
if(!limit&&~dp[pos][str][num]) return dp[pos][str][num];//这里就是说未达到边界并且这个数已经记录过 如果记录过了那就直接加上 这就是记忆化的作用
//这里特别提一下按位取反~和逻辑取反!的区别 如果是~就是每一位取反 针对整数类型的操作 !是针对bool类型的操作
int up_bound=limit?a[pos]:9,ans=0;//up_bound是上届 这个操作就是更新一下上界
for(int i=0; i<=up_bound; i++)//这里应该是遍历下一位 可以从下面看出 它会和本位一起做一些判断 例如判断是否出现13 是否达到上界
ans+=dfs(pos-1,gett(str,i),(num*10+i)%13,limit&&i==up_bound);//str的改变在gett函数中
//pos-1是进行下一个数位计算 str可以标记当前数什么状态 具体上面说了 num的计算就是每一位不停%13记录余数 这里并不会影响最后结果 也就是说可以计算整个数的%13余数
//我们从最高位开始第一次记录了当前位的上界 并且我们遍历到这个地方的时候我们就会更新一下下一位的上界 i==up_bound就是当前遍历至上界的标志
return limit?ans:dp[pos][str][num]=ans;//如果未达到上界我们用一下dp数组记录本位的情况 如果达到了 直接返回ans 递归之下就会增加总答案数
}
int slove(int x)
{
int pos=0;
while(x)
{
a[pos++] =x%10;//a数组逆序存储每一位
x/=10;
}
return dfs(pos-1,0,0,1);//从最高位开始搜索
}
int main()
{
int n;
mem(dp, -1);
while(~scanf("%d",&n)) {
printf("%d\n", slove(n));
}
return 0;
}