基准时间限制:1 秒 空间限制:131072 KB 分值: 10
难度:2级算法题
给出一段区间a-b,统计这个区间内0-9出现的次数。
比如 10-19,1出现11次(10,11,12,13,14,15,16,17,18,19,其中11包括2个1),其余数字各出现1次。
Input
两个数a,b(1 <= a <= b <= 10^18)
Output
输出共10行,分别是0-9出现的次数
Input示例
10 19
以前有一个算数字1的个数,这两个挺像的,这个的递归思路基本上是模仿那个。
传送门:点击打开链接
看懂了那道题,再看这个。
虽然说思路差不多一样,但是我做这个的时候也是看了别人的题解的,因为绕进去确实有点晕。
每一个数字无非就三种影响关系:
①它对低位的影响
②它对高位的影响
③高位对低位的影响
然后在递归中实现这三种关系的计算即可:
代码:
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
#define CLR(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define LL long long
void dp(LL n , LL m , LL *c)
{
LL x = n % 10;
LL y = n / 10;
for (int i = 0 ; i <= x ; i++)
c[i] += m; //当前位对低位的影响,每个都是0~9的范围
for (int i = 0 ; i <= 9 ; i++)
c[i] += m * y; //当前位对的高位影响(高位不为0,在上一个循环中算过)
c[0] -= m; //排除前导0的情况
LL t = y;
while (t) //高位对低位的影响,即都为最大限制数
{
c[t % 10] += (x+1) * m; //算上0
t /= 10;
}
if (y)
dp(y-1 , m*10 , c); //y值在上个while中算过,算下一个未限制数
}
int main()
{
LL r,l;
LL a[10] = {0};
LL b[10] = {0};
scanf ("%lld %lld",&l,&r);
dp(r , 1 , a);
dp(l-1 , 1 , b);
for (int i = 0 ; i <= 9 ; i++)
printf ("%lld\n",a[i]-b[i]);
return 0;
}