题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3652
题目大意:
给定一个整数n,求取闭区间1--n中B-number数的个数。(1 <= n <= 1000000000)
B-number指的是该数可以被13整除,并且该数字中包含连续的13。
解题思路:
很经典的数位DP。
定义2个数组:
dp1[i][j][k]:共i位数,最高位是j,模13等于k并且包含连续的13的数字个数。
dp2[i][j][k]:共i位数,最高位是j,模13等于k但是不包含连续的13的数字的个数。
对dp数组进行预处理:
dp2[0][i][i]=1
dp1[i][j][k]+=dp1[i-1][t][z]
当出现了13的时候,需要加上dp2
if(j==1 && t==3)
dp1[i][j][k]+=dp2[i-1][t]][z];
else
dp2[i][j][k]+=dp[i-1][t][z];
接下来就是计算的过程:
假设数字n的长度为len,用date数组存储每一位的值。
第1部分:
可以计算出0--len-2位的所有的dp1
ans+=dp1[i][j][0]
第2部分:
当第len-1位的取值为1---date[len-1]时,
ans+=dp1[len-1][i][0]
第3部分:
当最高位取值为date[len-1]时,通过枚举下面的位以及位置上的取值,求得更多的合法数字。具体见代码。
源代码:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
int date[10];
int shi[11]; //存储10的i次方
int dp1[12][10][15]; //共i位数字,最高位是j,模13为k,包含连续数字13
int dp2[12][10][15]; //不包含连续出现的13
void shishi()
{
int i;
memset(shi,0,sizeof(shi));
shi[0]=1;
for(i=1;i<=10;i++)
{
shi[i]=shi[i-1]*10;
}
return;
}
int DP(int x)
{
int i,j,k,t,yu,ans,len,flag;
ans=len=0;
while(x)
{
date[len++]=x%10;
x=x/10;
}
date[len]=0;
//第1部分,先求取1-len-1位的所有个数
for(i=1;i<len-1;i++)
{
for(j=1;j<=9;j++) //枚举最高位的值,不能有前导0
{
ans+=dp1[i][j][0];
}
}
//第2部分,枚举最高位的值
for(i=1;i<date[len-1];i++)
{
ans+=dp1[len-1][i][0];
}
//第3部分,最高为date[len-1]
t=date[len-1]*shi[len-1];
flag=0;
for(i=len-2;i>=0;i--) //枚举位数
{
for(j=0;j<date[i];j++) //枚举当前最高位的值
{
for(k=0;k<=12;k++) //枚举余数
{
yu=(t+k)%13;
if(yu==0)
{
ans+=dp1[i][j][k];
if(flag) ans+=dp2[i][j][k];
else if(j==3 && date[i+1]==1) ans+=dp2[i][j][k];
}
}
}
if(date[i]==3 && date[i+1]==1) flag=1;
t+=date[i]*shi[i];
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
int i,j,k,t,yu,n;
shishi();
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
//预处理dp数组的值
for(i=0;i<=9;i++)
{
dp2[0][i][i]=1;
}
for(i=1;i<=9;i++) //枚举位数
{
for(j=0;j<=9;j++) //枚举最高位
{
for(k=0;k<=9;k++) //枚举上一状态的最高位
{
for(t=0;t<=12;t++) //枚举上一状态的余数
{
yu=(j*shi[i]+t)%13;
dp1[i][j][yu]+=dp1[i-1][k][t];
if(j==1 && k==3) dp1[i][j][yu]+=dp2[i-1][k][t];
else dp2[i][j][yu]+=dp2[i-1][k][t];
}
}
}
}
while(scanf("%d",&n)==1)
{
printf("%d\n",DP(n+1));
}
return 0;
}