题意:给两个数l,r,求[l,r]区间内这么多数包含多少个"0" "1" "2"..."9"。 比如[1 10] 除了"1"有2个,其余数字均只有1个。
思路:数的范围为1e8,又是数的统计,一看就是数位dp。设dp[ i ] [ pos ] [ cnt ]为当前考虑数字为i,且当前考虑pos位,之前的位已经
有cnt个数字i,之后(pos+1)位与之前数位组合含数字i的个数。那么除了数字“0”需要考虑前导零之外,其他的正常求就可以了。详见代码:
/*********************************************************
file name: poj2282.cpp
author : kereo
create time: 2015年01月22日 星期四 19时06分00秒
*********************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int N=10;
const int MAXN=100000+50;
const int inf=0x3fffffff;
const double eps=1e-8;
const int mod=100000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define PII pair<int, int>
#define mk(x,y) make_pair((x),(y))
int n,m;
int bit[N];
ll num[N],ans1[N],ans2[N],dp[N][N][N]; //dp[i][pos][cnt]表示当前考虑的是i,考虑当前位置pos,之前i的个数为cnt
ll dfs(int cur,int pos,int cnt,int pre,int flag){
if(pos == -1) return cnt;
if(flag && dp[cur][pos][cnt]!=-1){
if(cur != 0)
return dp[cur][pos][cnt];
else if(pre)
return dp[cur][pos][cnt];
}
ll ans=0;
int x=flag ? 9 : bit[pos];
for(int i=0;i<=x;i++){
if(cur == 0)
ans+=dfs(cur,pos-1,cnt+(pre && i == cur),pre || i,flag || i<x);
else
ans+=dfs(cur,pos-1,cnt+(i == cur),pre || i,flag || i<x);
}
if(flag){
if(cur != 0)
return dp[cur][pos][cnt]=ans;
else if(pre)
return dp[cur][pos][cnt]=ans;
}
return ans;
}
void solve(int x){
int len=0;
if(!x)
bit[len++]=x;
while(x){
bit[len++]=x%10;
x/=10;
}
for(int i=0;i<10;i++)
num[i]=dfs(i,len-1,0,0,0);
}
int main(){
while(~scanf("%d%d",&n,&m) && n+m){
memset(dp,-1,sizeof(dp));
if(n>m)
swap(n,m);
solve(n-1);
for(int i=0;i<10;i++)
ans1[i]=num[i];
solve(m);
for(int i=0;i<10;i++)
ans2[i]=num[i];
for(int i=0;i<10;i++){
if(i == 0)
printf("%lld",ans2[i]-ans1[i]);
else
printf(" %lld",ans2[i]-ans1[i]);
}
printf("\n");
}
return 0;
}