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;
}