数位dp 至少要会两个基础题目,再做这道题才较容易。
https://cn.vjudge.net/problem/CodeForces-55D (kuangbin数位dp A题)(*推荐看这道题的博客时,思路不用完全看懂,还是代码好懂一点*)
https://blog.csdn.net/wust_zzwh/article/details/52100392 (kuangbin数位dp C题)数位dp入门(不要62)推荐,剩下的进阶版实在是本人能力有限,看不太懂,还是一步一步刷专题吧。以后再看。
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.
InputProcess till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).OutputPrint each answer in a single line.Sample Input
13 100 200 1000Sample Output
1 1 2 2
题意:一个wqb数字或简称B数字是一个非负整数,其十进制形式包含子串“13”,并且可以除以13.例如,130和2613是wqb数字,但是143和 2639不是。 您的任务是计算给定整数n中从1到n有多少个wqb数字。
我的感受:做完这道题感觉数位dp才懂了点皮毛。
思路:有两个条件包含13,并且是13的倍数。那么怎么同时控制两个条件呢,
int dp[pos][sta][num]; pos表示位数,if(sta==0)表示上一位不是1,if(sta==1)表示上一位是1,if(sta==2)表示出现13字符串,num表示%13之后的数字。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <math.h>
#include <queue>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=1e9+7;
const int M=13;
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,int limit)//其他地方就是数位dp板子了
{
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];
int up=limit?a[pos]:9,ans=0;
for(int i=0; i<=up; i++)
ans+=dfs(pos-1,gett(str,i),(num*10+i)%M,limit&&i==up);//str的改变在gett函数中
return limit?ans:dp[pos][str][num]=ans;
}
int slove(int x)
{
int pos=0;
while(x)
{
a[pos++] =x%10;
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));
}