数位DP之数字计数

数位DP之数字计数

嗯,这将是我本人写的第一篇博客。
不知怎的,学到数位dp,又恰好A掉了数字计数,就想开设自己的博客了。
算了,废话少说,进入正题了。
题目链接.

给定两个正整数 a和b,求在[a,b]中的所有整数中,每个数码 (digit) 各出现了多少次。

题意大概是给定两个数a,b,求区间[a,b]内0 ~ 9这些数码出现的次数,其中a,b可能爆int,因而要开long long。
本题思路也不算复杂,若完全按照数位dp的思想,在记忆化搜索时传递记录10个数码出现次数的结构体,多开一位数组记录前几位固定的数的总数,每次搜索处理本位上数字的出现次数,并吸收下层搜索结果。
搜索用10来处理前导零。到了搜索边界后,使个位上对应的数字总数+1即可。
最后,求出1 ~ a,1 ~ b的情况后,再用差分思想即可得出最终答案。
本人蒟蒻,明明这么简单的题还调了四个多小时。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;
struct node{
	ll tot[11];
	node() {//构造函数 
		for ( int i = 0 ; i <= 10 ; i++ ) {
			tot[i] = 0;
		}
	}
}f[25][25];
int num[15];
ll a , b;
node dfs( int pos , int nu , bool pd ) {
	if ( pos <= 0 ) {
		node an;
		if ( nu == 10 ) {
			an.tot[10] = 0;
		} else {
			an.tot[10] = 1;
			an.tot[nu] = 1;//处理个位 
		} 
		return an;
	}
	if ( ~f[pos][nu].tot[10] && !pd ) {
		return f[pos][nu];
	}
	node an;
	int end = pd ? num[pos] : 9;
	for ( int i = 0 ; i <= end ; i++ ) {
		node ans;
		if ( nu == 10 && i == 0 ) {
			ans = dfs( pos - 1 , 10 , pd && ( i == end ) );//处理前导零 
		} else {
			ans = dfs( pos - 1 , i , pd && ( i == end ) );
		}
		an.tot[10] += ans.tot[10];//计次数 
		for ( int j = 0 ; j <= 9 ; j++ ) {
			an.tot[j] += ans.tot[j];//吸收下层搜索结果 
		}
	}
	an.tot[nu] += an.tot[10];//前几位数字固定的数不止一个,会使本位数重复出现 
	if ( !pd ) {
		f[pos][nu] = an;//记忆化 
	}
	return an;
}
node solve ( ll x ) {
	int tot = 0;
	while ( x ) {
		num[++tot] = x % 10;
		x /= 10;
	}
	return dfs( tot , 10 , true );
}
int main () {
	//freopen( ".in" , "r" , stdin );
	scanf("%lld%lld",&a,&b);
	memset( f , -1 , sizeof(f) );
	node aa = solve(a - 1);//差分 
	node bb = solve(b);
	int f = 1;
	for ( int i = 0 ; i <= 9 ; i++ ) {
		if (f) f = 0;
		 else printf(" ");
		printf("%lld",bb.tot[i] - aa.tot[i]);
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值