您的位置:首页 > 编程语言 > C语言/C++

HDU 3652 B-number (数位DP)

2016-07-20 16:07 435 查看
原题地址:传送门   (http://acm.hdu.edu.cn/showproblem.php?pid=3652)

B-number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4435    Accepted Submission(s): 2550


[align=left]Problem Description[/align]
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.
 

[align=left]Input[/align]
Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).
 

[align=left]Output[/align]
Print each answer in a single line.
 

[align=left]Sample Input[/align]

13
100
200
1000

 

[align=left]Sample Output[/align]

1
1
2
2

题目大意就是,求区间 [ 1,n ] 内,包含13,而且能被13整除的数的个数。

dp [ 20 ] [ 13 ] [ 13 ] 分别表示位数,前一位数,和对13的余数 

long long int dfs(int pos,int pre,int mod,bool limit) 自然就是位数,前一位数,对13的余数,界限

这里判断13的倍数,就不需要到最后再判断余数是否为0了。

在遇到有13时,后面的,每13个就必然有一个是13的倍数。这么直接计算要快很多。

比如[1 , 11330 ]

当搜索到113**时,后面还有31个数。11300%13=3。

那么在11310之后的31-13+3=28个数里,每13个便有一个13的倍数。

那么一共便有(3+31) / 13 = 2 个13的倍数。

下面贴代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;

long long int dp[20][13][13];
int digit[20];

long long int dfs(int pos,int pre,int mod,bool limit)
{
if(pos==-1)
{
return 0;
}
if(!limit&&dp[pos][pre][mod]!=-1)
{
return dp[pos][pre][mod];
}
long long int res=0;
int tmp=limit? digit[pos]:9;
for(int i=0;i<=tmp;i++)
{
int Nmod=(mod+i*(long long int)pow(10,pos))%13;
if(pre==1&&i==3&&!(i==digit[pos]&&limit))
{
res+=((long long int)pow(10,pos)+Nmod-1)/13;
if(Nmod==0)
{
res++;
}
}
else if(pre==1&&i==3&&limit&&digit[pos]==3)
{
long long int sum=0;
for(int j=pos-1;j>=0;j--)
{
sum+=digit[j]*(long long int)pow(10,j);
}
res+=(sum+Nmod)/13;
if(Nmod==0)
{
res++;
}
}
else
{
res+=dfs(pos-1,i,Nmod,limit&&i==tmp);
}
}
if(!limit)
{
dp[pos][pre][mod]=res;
}
return res;
}
long long int cal(long long int a)
{
int len=0;
while(a)
{
digit[len++]=a%10;
a=a/10;
}
return dfs(len-1,0,0,1);
}
int main()
{
long long int t,a;
while(~scanf("%I64d",&a))
{
memset(dp,-1,sizeof(dp));
printf("%I64d\n",cal(a));
}
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息