hdu3652(数位dp

统计区间 [1,n] 中含有 '13' 且模 13 为 0 的数字有多少个。

就是把情况用状态表示出来,几维不是问题,终点是把所有的状态表示出来。

转移就是枚举该位是多少,根据这个位是多少,改变下一个dfs的参数,转移到下一位就好

边界:注意只有当所有的情况都符合的时候,i==0时才能把方案数置为1,否则,就像这道题,如果到最后没有13,且余数不为0,那么就应该返回方案数0


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;

int f[11][2][2][13];
int n,li[11];
int remain[11];
int dfs(int i,bool state,bool have,int k,bool limit)
{
	if (i==0&&k==0&&have) return 1;//边界
	if (i==0) return 0;
	
	if (!limit && f[i][state][have][k]) return f[i][state][have][k];//数位dp的limit必须加,因为,在边界最大值的情况是要注意处理的
	
	int up=limit ? li[i]:9,ans=0;
	for (int j=0;j<=up;j++)
	{
		int h=((k-(j*remain[i]))%13+13)%13;
		ans+=dfs(i-1 ,
		j==1?true:false ,
		have||(state&&j==3) ? true:false,
		h ,
		limit&& j==up?true :false
		);
	}
	if (!limit) f[i][state][have][k]=ans;//相对应上面的limit
	return ans;
}

void work(int n)
{
	memset(f,0,sizeof(f));
	memset(li,0,sizeof(li));
	int tot=0;
	while (n)
	{
		li[++tot]=n%10;
		n=n/10;
	}
	
	printf("%d\n",dfs(tot,false,false,0,true));
}

int main()
{
	remain[1]=1;
	for (int i=2;i<11;i++ ) remain[i]=remain[i-1]*10%13;
	
	while (scanf("%d",&n)!=EOF) work(n);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值