『The Counting Problem 数位dp』

2023-04-23,,

<更新提示>

<第一次更新>


<正文>

The Counting Problem

Description

求 [L,R]内每个数码出现的次数。

Input Format

若干行,一行两个正整数 L 和 R。

最后一行 L=R=0,表示输入结束。

Output Format

若干行,对于每个询问做出回答,每行 10 个整数,依次表示 0 至 9 出现的次数。

输入的最后一行不属于询问,因此不必对此做出回答。

Sample Input

1 10
114 514
233 666
19260421 19260817
19190504 19890605
0 0

Sample Output

1 2 1 1 1 1 1 1 1 1
80 167 180 180 181 95 80 80 80 80
83 83 150 191 194 194 158 83 83 83
476 475 476 80 159 180 577 180 97 476
350124 1059618 450020 450020 450021 450117 450026 450020 440626 1050224

解析

考虑数位\(dp\),设\(f[i][j][k]\)代表长度为\(i\)的数中,最高位为\(j\),数码\(k\)的出现次数和。以长度作为阶段,可以轻松转移:

\[f[i][j][k]=\sum_{p=0}^9f[i-1][p][k]
\]

当然,对于\(j=k\)的情况,还要加上\(10^{i-1}\),作为最高位数码的贡献。

然后考虑对于一个具体的数值\(x\),求出\(1-x\)的答案。

首先我们可以利用预处理的\(dp\)数组快速得到长度小于\(x\)的长度的答案。然后考虑计算长度等于\(x\)的长度的答案。

从高位到低位枚举,如果当且位小于\(x\)的这一位的话,后面的数字可以随便填,直接累加答案即可,反之累加当前位贡献,继续考虑下一位。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int SIZE = 13;
int cnt,num[SIZE];
long long f[SIZE][10][10],ans[10][2];
inline long long quickpow(long long a,long long b)
{
long long res = 1;
for ( ; b ; a = a * a , b>>=1 )
if ( 1 & b ) res = res * a;
return res;
}
inline void Prepdp(void)
{
for (int i=0;i<=9;i++) f[1][i][i] = 1;
for (int i=2;i<=12;i++)
for (int j=0;j<=9;j++)
{
for (int k=0;k<=9;k++)
for (int l=0;l<=9;l++)
f[i][j][l] += f[i-1][k][l];
f[i][j][j] += quickpow( 10 , i-1 );
}
}
inline void solve(long long x,int id)
{
memset( num , 0 , sizeof num );
cnt = 0; long long y = x;
while ( x ) num[++cnt] = x % 10 , x /= 10;
for (int i=0;i<cnt;i++)
for (int j=1;j<=9;j++)
for (int k=0;k<=9;k++)
ans[k][id] += f[i][j][k];
for (int i=cnt;i>=1;i--)
{
for (int j=0;j<num[i];j++)
{
if ( i == cnt && j == 0 ) continue;
for (int k=0;k<=9;k++)
ans[k][id] += f[i][j][k];
}
ans[num[i]][id] += y % quickpow( 10 , i-1 ) + 1;
}
}
int main(void)
{
Prepdp();
long long a,b;
while ( scanf("%lld%lld",&a,&b) && a && b )
{
solve( a-1 , 0 ) , solve( b , 1 );
for (int i=0;i<=9;i++)
printf("%lld%c",ans[i][1]-ans[i][0]," \n"[i==9]);
memset( ans , 0 , sizeof ans );
}
return 0;
}

<后记>

『The Counting Problem 数位dp』的相关教程结束。

《『The Counting Problem 数位dp』.doc》

下载本文的Word格式文档,以方便收藏与打印。