看不懂我写的哪个字了,哪句话了,哪段代码了,欢迎提出来啦,大家一起学习一起进步啦
欢迎交流
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
题意:
给你一个数,找这个数中含有13,13必须是连着的数,再一个这个数可以被13整除,给你的数比较大,用数位dp
我觉得要弄懂数位dp关键是要把dfs中的递归弄明白,在大脑中模拟一遍过程,先是
从最高位开始,for循环为0,表示最高位取0,然后进入下层dfs,此时是第二位,for循环为0。。。。。。我感觉好好想想这个地方比较有好处
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include<stdio.h>
#include<string.h>
#include<limits.h>
#include<stdbool.h>
#include<vector>
#include<queue>
#include<map>
#define maxn 1505
using namespace std;
typedef __int64 ll;
int w[50];
ll dp[25][15][3];//dp[i][j][k]表示第i位余数是j,状态是k,关于状态(0表示普通状态,1表示前一位是1,2表示含有13
ll dfs(int pos,int st,bool limit,int mod)
{
if(pos==-1)
{
return st==2&&mod==0 ;//**只有既含有13,最后的余数等于0,才能返回1**
}
if(!limit&&dp[pos][mod][st]!=-1)
{
return dp[pos][mod][st];//记忆化
}
int up=limit?w[pos]:9;
ll ret=0;
for(int i=0;i<=up;i++)//代表的是这一位可以放的数
{
int tmp=(mod*10+i)%13;//余数,下面有详细的解释
if(st==2)
{
ret+=dfs(pos-1,2,limit&&w[pos]==i,tmp);
}
else if(st==1&&i==3)
{
ret+=dfs(pos-1,2,limit&&w[pos]==i,tmp);
}
else if(i==1)
{
ret+=dfs(pos-1,1,limit&&w[pos]==i,tmp);
}
else{
ret+=dfs(pos-1,0,limit&&w[pos]==i,tmp);
}
}
if(!limit)
{
dp[pos][mod][st]=ret;
}
return ret;
}
ll solve(ll n)
{
int len=0;
while(n)
{
w[len++]=n%10;//分解获得每一位
n=n/10;
}
return dfs(len-1,0,1,0);
}
int main()
{
ll n;
memset(dp,-1,sizeof(dp));//之所以初始化为-1是因为前面判断这个dp之前算没算过,上面代码用的着
while(scanf("%lld",&n)!=EOF)
{
printf("%lld\n",solve(n));
}
return 0;
}
int tmp=(mod*10+i)%13;//余数
看下图解释
大家如果有什么疑问欢迎提出来啦,很希望与各位大佬交流,有错误也尽管提出来了,我会尽快回复的啦