ZJOI2010数字计数-数位DP

ZJOI2010数字计数

题目传送

sol:

仍然可以按照记忆化实现的思路来解决此题。

\(pos,lim,lead\)的含义不再申明,不了解可以看这里(含义是一样的),也可以阅读那里面的那篇链接博文。

此题中只需多记录一个变量\(cnt\),表示计算的数\(now\),在\(pos\)位中已经出现了\(cnt\)次。

其上的\(now\)从0~9枚举,相当于分别计算答案。

为什么要记一个\(cnt\)呢。

可以这样理解:当搜索到边界的时候需要返回的值,就是当前所有的位中,\(now\)出现的次数,也即\(cnt\)

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

int len,now,a[15];
LL ans[15],f[15][15];

LL dfs(int pos,int cnt,int lim,int lead) {
	if(pos>len) return cnt;
	if(!lim&&f[pos][cnt]!=-1) return f[pos][cnt];
	RG LL sum=0;
	RG int i,up=lim?a[len-pos+1]:9;
	for(i=0;i<=up;++i)
		if(lead&&i==0) sum+=dfs(pos+1,0,0,1);
		else sum+=dfs(pos+1,cnt+(i==now),lim&&i==up,0);
	
	if(!lim&&!lead) f[pos][cnt]=sum;
	return sum;
}

IL LL getans(LL x) {
	for(len=0;x;x/=10) a[++len]=x%10;
	memset(f,-1,sizeof(f));
	return dfs(1,0,1,1);
}

int main()
{
	RG LL l,r;
	scanf("%lld%lld",&l,&r);
	for(now=0;now<=9;++now)
		printf("%lld ",getans(r)-getans(l-1));
    return 0;
}
posted @ 2019-06-13 17:09  薄荷凉了夏  阅读(189)  评论(0编辑  收藏  举报