洛谷 P2602 [ZJOI2010]数字计数 数位DP

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_44343213/article/details/102729797

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

输入格式
输入文件中仅包含一行两个整数a、b,含义如上所述。

输出格式
输出文件中包含一行10个整数,分别表示0-9在[a,b]中出现了多少次。

输入输出样例
输入 #1
1 99
输出 #1
9 20 20 20 20 20 20 20 20 20
说明/提示
30%的数据中,a<=b<=10^6;

100%的数据中,a<=b<=10^12。

解法:记忆化搜索

#include<iostream>
#include<cstring>
#define ll long long
#define re register int
using namespace std;
ll a,b,num[15],f[15][2][15][2];
//len表示当前搜索的位数  issmall为当前位是否与num[len]相等  0相等 1不相等
//sum表示当前数字d出现的次数  zero表示之前是否是前导0  0是 1不是 
//d为当前的数字 
inline ll dfs(ll len,bool issmall,ll sum,bool zero,ll d) {
	ll res=0;
	if(!len) return sum;
	if(f[len][issmall][sum][zero]!=-1) return f[len][issmall][sum][zero];
	for(re i=0;i<10;i++) {
		if(!issmall&&i>num[len]) break;
		res+=dfs(len-1,issmall||i<num[len],sum+
			((!zero||i)&&(i==d)),zero&&(!i),d);
	}
	f[len][issmall][sum][zero]=res;
	return res;
}
inline ll solve(ll x,ll d) {
	ll len=0;
	while(x) {
		num[++len]=x%10;
		x/=10;
	}
	memset(f,-1,sizeof(f));
	return dfs(len,0,0,1,d);
//从最高位开始搜索  与最高位相等  当前数字还没有出现
//之前不是前导0  当前搜索d 
}
int main() {
	cin>>a>>b;
	for(re i=0;i<10;i++) {
		cout<<solve(b,i)-solve(a-1,i)<<" ";
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_44343213/article/details/102729797