HDU-3652-B-number(数位DP)

题目:传送门

题解:代码里写了很清楚,可以把代码copy过去看后面一句句的解释,这里记录一下,判断一个很大数能够整除某个数的方法可以用 mod_x=(mod*10+i)%k  其中mod表示上一位的余数,i表示当前这一位,k是除数,mod_x一直累计下来,到所有位数用完之后判断mod_x是不是0,是0就是能够整除

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int n;
int a[20],f[20][20][3];//f[i][j][k],i表示位数,j表示余数,k表示末尾是1、末尾不是1、含有13
//j位一定要开到大于13的,因为余数<=12
int dfs(int num,int mod,int k,int limit)
{
	int up,ans=0,mod_x,k_x;
	if(num==0)return (mod==0&&k==2);
	//余数为0,k=2表示含有13所以当前情况可以,返回1
	if(!limit && f[num][mod][k]!=-1)return f[num][mod][k];
	// 如果没有上限,并且被访问过
	if(!limit)up=9;
	else up=a[num];
	//如果有上限,只能取到当前位数,如果没上限,可取到9
    //假设该位是2,下一位是3,如果现在算到该位为1,那么下一位是能取到9的,如果该位为2,下一位只能取到3
	for(int i=0;i<=up;i++)
	{
		mod_x=(mod*10+i)%13;
		//该位的每种情况对13取模,实际上就是前面的部分已经能把13除尽了,还有剩下的加上当前位置加上的看能不能除尽13
		k_x=k;
		if(k==0&&i==1)k_x=1;//末位是1
		if(k==1&&i!=1)k_x=0;//末位已经为1了,后面如果还是1,那么k_x就不变,还为1
		if(k==1&&i==3)k_x=2;//末位已经为1,现在加3
		ans+=dfs(num-1,mod_x,k_x,limit&&i==a[num]);
		//之前全部取的上界,现在又选上界
	}
	if(!limit)f[num][mod][k]=ans;
	// cout<<ans<<endl;
	return ans;
}
int slove(int x)
{
	memset(a,0,sizeof(a));
	int num=0;
	while(x!=0)
	{
		a[++num]=x%10;
		x/=10;
	}
	return dfs(num,0,0,1);
}	
int main()
{
	memset(f,-1,sizeof(f));
	while(~scanf("%d",&n))
	{
		printf("%d\n",slove(n));
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值