dp系列中还有一类叫做数位dp,那么今天结合这道HDU3652来看一看数位dp到底是什么。
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
题意:找出1~n范围内含有13并且能被13整除的数字的个数。
数位dp一般应用于:
求出在给定区间[A,B]内,符合条件P(i)的数i的个数。
条件P(i)一般与数的大小无关,而与数的组成有关。
而且[A,B]通常很大,无法模拟。所以说这种题目看起来跟dp八竿子打不着,但它还真是dp了。
好,关于这道题我们需要使用记忆化深搜来记录状态,配合数位DP来解决,详情看代码。
Code:
#include
#include
#include
using namespace std;
int num[15],dp[15][15][3];//dp[i][j][k]表示 i:数位 j:余数 k:3种操作状况,0:末尾不是1,1:末尾是1,2:含有13
int dfs(int pos,int mod,int have,int uplim)//uplim记录上限,前三个跟dp数组一样
{
if(pos<=0)return mod==0&&have==2;
if(!uplim&&dp[pos][mod][have]!=-1)//没有上限并且已被访问过
return dp[pos][mod][have];
int k=uplim?num[pos]:9;//假设该位是2,下一位是3,如果现在算到该位为1,那么下一位是能取到9的,如果该位为2,下一位只能取到3
int ans=0;
for(int i=0;i<=k;i++)
{
int mod_x=(mod*10+i)%13;//看是否能整除13,而且由于是从原来数字最高位开始算,可以发现事实上这个过程就是一个除法过程
int have_x=have;
if(have==0&&i==1)have_x=1;//末尾不是1,现在加入的是1,则标记为末尾是1
if(have==1&&i!=1)have_x=0;//末尾是1,现在加入的不是1,则标记为末尾不是1
if(have==1&&i==3)have_x=2;//末尾是1,现在加入的是3,则标记为含有13
ans+=dfs(pos-1,mod_x,have_x,uplim&&i==k);//uplim&&i==k,在最开始,取出的k是最高位,所以如果i比k小,那么i的下一位都可以到达9,而i==k了,最大能到达的就只有num[pos-1]
}
if(!uplim)dp[pos][mod][have]=ans;
return ans;
}
int main()
{
int n,len;
while(~scanf("%d",&n))
{
memset(dp,-1,sizeof(dp));
len=0;
while(n)
{
num[++len]=n%10;
n/=10;
}
printf("%d\n",dfs(len,0,0,1));
}
return 0;
}