您的位置:首页 > 其它

hdu3652 B-number(数位dp)

2017-09-23 16:37 453 查看
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\n",doit());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: