HDU 3652 B-number (数位DP)
2016-07-20 16:07
435 查看
原题地址:传送门 (http://acm.hdu.edu.cn/showproblem.php?pid=3652)
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;
}
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;
}
相关文章推荐
- 封装好的Folyd建图,C++源码
- matlab与c/c++混合编程
- matlab与c/c++混合编程——c/c++调用matlab
- TYVJ1193 括号序列解题报告
- TYVJ上一些DP的解题报告
- C/C++常用的调试宏
- VC内存泄露检查工具:VisualLeakDetector
- 内联函数总结
- usb体系结构
- VC结构体实现类似数组的下标操作符功能
- C/C++ 嵌套结构体动态内存管理实现
- C++调用gSoap编写的WEBSERVICE与C#.NET间接口自定义结构体不能重复使用
- 处理VC开发的webservice在C#.NET中中文乱码问题
- gcc使用入门
- C/C++ Linux 程序员必须了解的 10 个工具
- 递归遍历数组
- 用C/C++打印*号图案
- C++之四书五经(上)
- C++中const的使用
- *p++和*++p的区别