数位DP-001

问题:求a~b中不包含49的数的个数,0 < a、b < 2*10^9

#include<cstdio>
#include<cstring>
int a,b,shu[20],dp[20][2];//数组shu用于记录输入数字的每一位上的数字,
                          //dp[i][0]表示第i+1位不为4的有i位数字的符合要求的数字的个数 
                          //dp[i][1]表示第i+1位为4的有i位数字的符合要求的数字的个数 
int dfs(int digit,bool if4,bool limit)//digit表示位数,if4表示上一位是否等于4,limit表示上一位是否达到极限 
{
	if(digit==0)//digit为0只有一个结果 
		return 1;
	if(!limit&&dp[digit][if4])//上一位没有达到极限可以使用记忆过的内容 
		return dp[digit][if4];
	int count=0,max1=(limit?shu[digit]:9);//max1表示该位上所能取的最大数字
	int i;
	for(i=0;i<=max1;i++)
	{
		if(if4&&i==9)//不满足条件直接跳过 
			continue;
		count+=dfs(digit-1,i==4,limit&&i==max1);//记录满足条件的个数
	}
	return limit?count:dp[digit][if4]=count;//如果上一位达到极限,就不能记忆,因为个数不完整 
}
int solve(int x)//该函数用于计算从0~x的符合要求的数的个数 
{
	memset(shu,0,sizeof(shu));//每次都得将数组shu初始化
	int k=0;
	while(x)//记录数字x每一位上的数字 
	{
		shu[++k]=x%10;
		x/=10;
	}
	return dfs(k,false,true);
}
int main()
{
	scanf("%d%d",&a,&b);
	printf("%d",solve(b)-solve(a-1));//答案等于从0~b的符合要求的数的个数减去从0~a-1的符合要求的数的个数
	return 0;
}

问题:求a~b中不包含62和4的数的个数. 0 < a、b < 2*10^9

#include<cstdio>
#include<cstring>
int a,b,shu[20],dp[20][2];
int dfs(int digit,bool if6,bool limit)
{
	if(digit==0)
		return 1;
	if(!limit&&dp[digit][if6])
		return dp[digit][if6];
	int count=0,max1=(limit?shu[digit]:9);
	for(int i=0;i<=max1;i++)
	{
		if(i==4||if6&&i==2)
			continue;
		count+=dfs(digit-1,i==6,limit&&i==max1);
	}
	return limit?count:dp[digit][if6]=count;
}
int solve(int x)
{
	memset(shu,0,sizeof(shu));
	int k=0;
	while(x)
	{
		shu[++k]=x%10;
		x/=10;
	}
	return dfs(k,false,true);
}
int main()
{
	 scanf("%d%d",&a,&b);
	 printf("%d",solve(b)-solve(a-1));
	 return 0;
}

问题:找出1~n范围内含有13并且能被13整除的数字的个数

#include<cstdio>
#include<cstring>
int a,shu[20],dp[20][20][3];//dp[i][j][k]中i表示位数,j表示余数,k表示状态 
int dfs(int digit,int mod,int state,bool limit)//mod表示余数,求余满足以下规律:
											   //(a*b)%mod=(a%mod)*(b%mod)
											   //(a+b)%mod=(a%mod)+(b%mod)
{
	if(digit==0)
		return mod==0&&state==2;
	if(!limit&&dp[digit][mod][state])
		return dp[digit][mod][state];
	int cnt=0,max1=(limit?shu[digit]:9);
	for(int i=0;i<=max1;i++)
	{
		int b=state;
		if(state!=2&&i!=1)//state=0表示之前的数字中没有13,当前数字不是1 
			b=0;
		if(state!=2&&i==1)//state=1表示之前的数字中没有13,当前数字是1 
			b=1;
		if(state==1&&i==3)//state=2表示上个数字是1,当前数字是3
			b=2;		  //state为2之后就不会在更改,表示已经达到条件 

		cnt+=dfs(digit-1,(mod*10+i)%13,b,limit&&i==max1);
	}					//余数*10再加上当前数字再做除法是除法的运算法则 
	return limit?cnt:dp[digit][mod][state]=cnt;
}
int main()
{
	while(~scanf("%d",&a))
	{	
		memset(shu,0,sizeof(shu));
		memset(dp,0,sizeof(dp));
		int k=0;
		while(a)
		{
			shu[++k]=a%10;
			a/=10;
		}
		printf("%d\n",dfs(k,0,0,1));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值