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
分析:
题目大意就是找到一些数字,能被13整除,同时数字中还要出现13
看起来是道数位dp
但是这个%13==0的限制有点烦
有点像啊
现在进入了看每道题都觉得有以前做过的题的影子,
这就进入了刷题第二阶段之似懂非懂
只有继续修炼,才能从似懂非懂上升到看出算法
是否能整除十三好像有一个简便算法:
先划去这个数的末一位数,
然后用剩余数字所表示的数加上所划数的4倍,
不断地重复这一操作,直到数字变成一个两位数
如果最后得到的数能被13整除,那么,这个数就能被13整除
这个数的末三位数与末三位以前的数字所组成的数之差能被13整除, 那么原数就可以被13整除
f[i][j][k][0/1][0/1] //第i位是j,第i-1位是k,数字中有没有13,是否卡边界
这样可以很简单的转移出满足第二个条件的数字
然并卵
看到网上的前辈说随便搞,我就有点害怕
于是就想了一个状态:
f[i][j][k][0/1][0/1] //第i位是j,当前数字%13的余数,数字中有没有13,是否卡边界
事实证明,这是正确的O(∩_∩)O~
tip
不要忘了初始化
今天状态真的不大好:
两处手残查了半个小时,而且全都是初始化写错:
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,len,a[20],b[20];
int f[20][11][20][2][2];
int doit()
{
int i,j,k,l,s,c;
memset(f,0,sizeof(f));
for (i=0;i<=a[1];i++) f[1][i][i%13][0][i==a[1]]=1; //
for (i=1;i<len;i++)
for (j=0;j<=9;j++)
for (k=0;k<13;k++)
for (l=0;l<=1;l++)
for (s=0;s<=1;s++)
if (f[i][j][k][l][s])
{
int tt=9;
if (s) tt=a[i+1];
for (c=0;c<=tt;c++)
{
int x=(k*10)%13+c;
x%=13;
f[i+1][c][x][l|(j==1&&c==3)][s&(c==a[i+1])]+=f[i][j][k][l][s];
}
}
int ans=0;
for (i=0;i<=9;i++)
for (j=0;j<=1;j++)
ans+=f[len][i][0][1][j];
return ans;
}
int main()
{
while (scanf("%d",&n)!=EOF)
{
len=0;
while (n)
{
len++;
b[len]=n%10;
n/=10;
}
for (int i=1;i<=len;i++) a[i]=b[len-i+1];
printf("%d
",doit());
}
return 0;
}