【BZOJ 1833】【数位DP】 ZJOI2010 count【求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次】

来源:互联网 发布:linux递归创建目录 编辑:程序博客网 时间:2024/06/06 03:02

传送门:1833: [ZJOI2010]count 数字计数

描述:

1833: [ZJOI2010]count 数字计数

Time Limit: 3 Sec  Memory Limit: 64 MB
Submit: 2766  Solved: 1226
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

1 99

Sample Output

9 20 20 20 20 20 20 20 20 20

HINT

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

Source

Day1

题意:

求[a,b]间所有的整数中0~9每个数字出现了几次

思路:

设dp[i][j][k]表示长度为i,开头为j的数中k的个数

分开统计答案,对于位数小于当前数的直接全部加上,剩余的拆分统计

代码:

#include <bits/stdc++.h>using  namespace  std;typedef long long ll;const int maxn=20;ll a,b;ll dp[maxn][maxn][maxn];//长度为i,开头为j的数中k的个数ll bin[maxn];//i位中所有首位为i的数的个数ll res[maxn];//记录0~9个数int d[maxn];void init(){//递推计算出每个整数  bin[1]=1;  for(int i=2; i<=13; i++)bin[i]=bin[i-1]*10;  for(int i=0; i<=9; i++)dp[1][i][i]=1;  for(int i=2; i<=13; i++)    for(int j=0; j<=9; j++)      for(int z=0; z<=9; z++){        for(int k=0; k<=9; k++)           dp[i][j][z]+=dp[i-1][k][z];        dp[i][z][z]+=bin[i-1];      }}void solve(ll x,int flag){ //计算1~x的所有整数  int dnum=0;//记录当前数的位数  ll tmpn=x;  memset(d, 0, sizeof(d));  while(x){ d[++dnum]=x%10; x/=10;}  for(int i=1; i<=dnum-1; i++)//位数小于当前数的位数    for(int j=1; j<=9; j++)      for(int k=0; k<=9; k++)        res[k]+=(dp[i][j][k]*flag);  int tmp=dnum;  while(tmp){//位数等于当前数的位数,拆分统计这里可以举一个120的例子仔细思考一下过程    for(int i=0; i<d[tmp]; i++){      if(!i && tmp==dnum)continue;//不能重复计算      for(int j=0; j<=9; j++)        res[j]+=(dp[tmp][i][j]*flag);    }    res[d[tmp]]+=(tmpn%bin[tmp]+1)*flag;    tmp--;  }}int  main(){  /*  #ifndef ONLINE_JUDGE  freopen("in.txt","r",stdin);  #endif*/  init();  scanf("%lld%lld",&a,&b);  solve(b, 1);solve(a-1, -1);   for(int i=0; i<=9; i++)    printf("%lld%c",res[i],i==9?'\n':' ');  return 0;}



0 0