#sWDPybttg050304. 1588:数字游戏

1588:数字游戏

好的,我将这道题整理为清晰的题面格式,并补充样例解释、数据范围与时空限制:


题目描述

由于科协里最近真的很流行数字游戏,某人又命名了一种取模数,这种数字必须满足各位数字之和 modN\bmod N00。现在大家又要玩游戏了,指定一个整数闭区间 [a,b][a,b],问这个区间内有多少个取模数。


输入格式

题目有多组测试数据。每组只含三个整数 a,b,Na, b, N

输入以文件结束(EOF)为终止。


输出格式

对于每组测试数据,输出一行,表示各位数字和 modN\bmod N00 的数的个数。


样例

样例输入

1 19 9

样例输出

2

样例解释

N=9N=9,要求各位数字和能被 99 整除。

[1,19][1,19] 中:

  • 数字 99:各位和 9mod9=09 \bmod 9 = 0,符合;
  • 数字 18181+8=9mod9=01+8=9 \bmod 9 = 0,符合;
  • 其他数字各位和 mod 9 不为 0,如 1010 和为 1,1111 和为 2,等等。

所以共 22 个取模数。


数据范围

对于全部数据:

  • 1ab23111 \le a \le b \le 2^{31}-1
  • 1N<1001 \le N < 100

时空限制

  • 时间:1000 ms1000 \text{ ms}
  • 内存:524288 KB524288 \text{ KB}

提示
此题为 数位 DP 问题。

状态设计:dp[pos][sum]dp[pos][sum] 表示处理到第 pospos 位(从高位到低位),当前各位数字之和模 NNsumsum 时的方案数。

转移:枚举当前位数字 dd0099(若有限制则到 digit[pos]digit[pos]),更新 sum=(sum+d)modNsum' = (sum + d) \bmod N

初始状态:dfs(0,0,true,true)dfs(0, 0, true, true),其中第一个 true 表示受上限限制,第二个 true 表示前面全是前导零(但这里前导零不影响数字和,可以忽略)。

最终要求 sum=0sum = 0,且排除数字 00(如果 a>0a>0 则不影响,但若区间包含 0000 的数字和为 00NN00,需要根据题意判断是否算取模数。一般题目中取模数是正整数,所以 00 不算)。

具体实现

  1. 将数字 nn 拆成数位数组;
  2. DFS(pos, sum_mod, limit, lead):
    • pos:当前位;
    • sum_mod:当前数字和模 NN
    • limit:是否受上限限制;
    • lead:是否前面全是前导零。
  3. 记忆化:dp[pos][summod]dp[pos][sum_mod]limitlimitleadlead 不记忆,但当 limit=0limit=0lead=0lead=0 时记忆化。
  4. 当 pos 到达末尾时,如果 lead 为真,则返回 0(排除数字 0),否则返回 sum_mod==0 ? 1 : 0。
  5. 转移:枚举当前位数字,如果 lead 为真且 d==0,则继续 lead 为真;否则 lead 变为假。

最终答案为:calc(b) - calc(a-1)。

复杂度:状态数 O(位数×N)O(\text{位数} \times N)N100N \le 100,位数不超过 10(23112^{31}-1 约 10 位),可以快速计算。

注意NN 可能为 1,此时所有数都符合,但要注意区间内数字个数计算。