Google Kickstart 2022 Interesting Integers Solution

Google Kickstart 2022 Interesting Integers Solution

Problem

Google Kick Start 2022 Round A Interesting Integers

Solution

假设函数 C o u n t I n t e r e s t i n g I n t e g e r s ( N ) CountInterestingIntegers(N) CountInterestingIntegers(N)为1到N之间的interesting integer的个数,那么,在正整数A到B之间的interesting integer个数为 C o u n t I n t e r e s t i n g I n t e g e r s ( B ) − C o u n t I n t e r e s t i n g I n t e g e r s ( A − 1 ) CountInterestingIntegers(B)−CountInterestingIntegers(A−1) CountInterestingIntegers(B)CountInterestingIntegers(A1)

如果 N < 1 , C o u n t I n t e r e s t i n g I n t e g e r s ( N ) = 0 N<1,CountInterestingIntegers(N)=0 N<1,CountInterestingIntegers(N)=0

首先定义一个函数 f 1 ( L ,    P ,    S ) f_{1}(L,\;P,\;S) f1(L,P,S),返回L位数字中满足 ( P × ∏ i = 1 L d i ) % ( S + ∑ i = 1 L d 1 ) = 0 (P \times {\textstyle \prod_{i=1}^{L}} d_{i}) \% (S + {\textstyle \sum_{i=1}^{L}} d_{1}) = 0 (P×i=1Ldi)%(S+i=1Ld1)=0条件的数字个数,每位数字表示为 d 1 , d 2 , . . . , d L d_{1},d_{2},...,d_{L} d1,d2,...,dL

P表示每位数字相乘之和,初始值为1;S表示每位数字相加之和,初始值为0。

根据上面定义,
如果 L = 0 L = 0 L=0,那么 f 1 ( L ,    P ,    S ) = P % S f_{1}(L,\;P,\;S) = P \% S f1(L,P,S)=P%S,即如果 P % S = 0 P \% S = 0 P%S=0 f 1 ( L ,    P ,    S ) f_{1}(L,\;P,\;S) f1(L,P,S)返回1,否则返回0。
如果 L > 0 L > 0 L>0,那么 f 1 ( L ,    P ,    S ) = ∑ d i g i t = 0 9 f 1 ( L − 1 ,    P × d i g i t ,    S + d i g i t ) f_{1}(L,\;P,\;S) = {\textstyle \sum_{digit=0}^{9}}f_{1}(L -1,\; P \times digit, \; S + digit) f1(L,P,S)=digit=09f1(L1,P×digit,S+digit)

按上面公式递推,直到 L = 0 L = 0 L=0就可以得到所有小于N的interesting Integer的个数。同时,把上面不同参数组合的中间结果缓存下来,可以提升算法执行速度,避免重复计算。

然后,从左至右遍历N的每一位可能的数字,得到所有小于N的一个集合,递归调用 f 1 f_{1} f1,最终得到 C o u n t I n t e r e s t i n g I n t e g e r s ( N ) CountInterestingIntegers(N) CountInterestingIntegers(N)的结果。以下是官方给的伪代码实现

def CountInterestingIntegers(N):
  if N == 0:
    return 0
  count = 0
  for L in (1 to (CountDigits(N) - 1)):
    count += CountInterestingIntegersWithNumberOfDigits(L)
  count += CountInterestingIntegersWithPrefixOfN(N, P=1, S=0, digit_index=0, is_first_digit=True)
  return count

# L位数字中所有的Interesting Integer数量,不限制数字大小。
def CountInterestingIntegersWithNumberOfDigits(L):
  count = 0
  for digit in (1 to 9):
    count += f1(L - 1, P=digit, S=digit)
  return count

# L位数字中所有的Interesting Integer数量,限制结果大小,必须小于N
def CountInterestingIntegersWithPrefixOfN(N, P, S, digit_index, is_first_digit):
  if digit_index == CountDigits(N):
    return 1 if S > 0 and P % S == 0 else 0

  if is_first_digit:
    digit_start = 1
  else:
    digit_start = 0

  count = 0
  for digit in (digit_start to (GetIthDigit(N, digit_index) - 1)):
    count += f1(CountDigits(N) - digit_index - 1, P * digit, S + digit)

  count += CountInterestingIntegersWithPrefixOfN(N,
                                                 P * GetIthDigit(N, digit_index),
                                                 S + GetIthDigit(N, digit_index),
                                                 digit_index + 1, is_first_digit=False)
  return count

假设M为从A到B范围内数字中位数的最大值,从 { 1 , 2 , 3 , … , 9 } \{1,2,3,…,9\} {1,2,3,,9}中选出M个可重复的数字,有 ( M + 9 − 1 ) ! ( 9 − 1 ) ! M ! + 1 \frac{(M+9−1)!}{(9−1)!M!} + 1 (91)!M!(M+91)!+1种可能的组合,加1是考虑乘积为0的情况。

那么 f 1 ( L ,    P ,    S ) f_{1}(L,\;P,\;S) f1(L,P,S)可能参数组合的数量上限为 M × ( ( M + 9 − 1 ) ! ( 9 − 1 ) ! M ! + 1 ) × ( 9 × M ) M \times (\frac{(M+9−1)!}{(9−1)!M!} + 1) \times (9 \times M) M×((91)!M!(M+91)!+1)×(9×M)。在有缓存情况下, f 1 ( L ,    P ,    S ) f_{1}(L,\;P,\;S) f1(L,P,S)返回只需要 O ( 1 ) O(1) O(1)时间复杂度。因此, f 1 ( L ,    P ,    S ) f_{1}(L,\;P,\;S) f1(L,P,S)整体时间复杂度就是 O ( M × ( ( M + 9 − 1 ) ! ( 9 − 1 ) ! M ! + 1 ) × ( 9 × M ) O(M \times (\frac{(M+9−1)!}{(9−1)!M!} + 1) \times (9 \times M) O(M×((91)!M!(M+91)!+1)×(9×M)

从题目描述中,有 A , B ≤ 1 0 12 A,B\le 10^{12} AB1012。所以这里M的最大值就是13,代入公式 13 × 203 , 491 × ( 9 × 13 ) = 309 , 509 , 811 13\times203,491\times(9\times13) = 309,509,811 13×203,491×(9×13)=309,509,811,这个计算量已经不算小了,全部都计算一遍就无法满足题目中的时间限制了。

或者,以一种更严格方式来预估参数空间的大小,即 O ( ∑ L = 1 M ( ( L + 9 − 1 ) ! ( 9 − 1 ) ! L ! + 1 ) × ( 9 × L ) ) O({\textstyle \sum_{L=1}^{M}}(\frac{(L+9−1)!}{(9−1)!L!} + 1) \times (9 \times L)) O(L=1M((91)!L!(L+91)!+1)×(9×L)) M = 13 M = 13 M=13时,参数空间大小是 52 , 379 , 145 52,379,145 52,379,145,虽然已经是上面空间的 1 6 \frac{1}{6} 61,但仍是千万级别的。

通过Prime Factorization优化参数空间

因为 f 1 ( L ,    P ,    S ) f_{1}(L,\;P,\;S) f1(L,P,S)中参数P总是几个数相乘结果(这点很重要),那么P就可以表示为 P = 2 w × 3 x × 5 y × 7 z P = 2^{w} \times 3^{x} \times 5^{y} \times7^{z} P=2w×3x×5y×7z。因为从1~9都可以用上面公式来表示,所以它们之间的乘积也可以用上面公式表示;但对于乘积为0的情况,需要单独去处理。

参数S最大可能的值为 9 × M 9 \times M 9×M,而 P = 2 w × 3 x × 5 y × 7 z P = 2^{w} \times 3^{x} \times 5^{y} \times7^{z} P=2w×3x×5y×7z,那么,如果 2 w > 9 M 2^{w} \gt 9M 2w>9M时, P % S = 0 P\%S=0 P%S=0,则一定有 S ≤ 9 M S \le 9M S9M ( P / 2 ) % S = 0 (P/2)\%S=0 (P/2)%S=0。接下来,就可以把这规则应用于上面质因数公式中了。

因为 P % S = ( 2 w × 3 x × 5 y × 7 z ) % S = ( ( 2 w % S ) × ( ( 3 x × 5 y × 7 z ) % S ) ) % S = 0 P\%S=(2^{w} \times 3^{x} \times 5^{y} \times7^{z}) \% S=((2^{w}\%S) \times ((3^{x} \times 5^{y} \times7^{z})\%S))\%S=0 P%S=(2w×3x×5y×7z)%S=((2w%S)×((3x×5y×7z)%S))%S=0

  • 如果 ( 3 x × 5 y × 7 z ) % S = 0 (3^{x} \times 5^{y} \times7^{z})\%S=0 (3x×5y×7z)%S=0,那么 2 w 2^{w} 2w可以是任何值;
  • 如果 ( 3 x × 5 y × 7 z ) % S ≠ 0 (3^{x} \times 5^{y} \times7^{z})\%S\ne0 (3x×5y×7z)%S=0,有两种情况,
    • 2 w % S = 0 2^{w}\%S=0 2w%S=0,则只需要保证 2 w 2^{w} 2w不小于S的最大值9M即可;
    • 2 w % S ≠ 0 2^{w}\%S\ne0 2w%S=0,因为 P % S = 0 P\%S=0 P%S=0,所以S也一定可以写成 2 w × 3 x × 5 y × 7 z 2^{w} \times 3^{x} \times 5^{y} \times7^{z} 2w×3x×5y×7z,因此,同上,保证 2 w 2^{w} 2w不小于S的最大值9M即可。

其它3,5,7最大幂也可以按上面方式计算出来。~~

通过限制质数幂范围,这样就可以进一步减小参数空间。我们定义一个函数 C a p I n t e r e s t i n g P r i m e F a c t o r s ( P ) CapInterestingPrimeFactors(P) CapInterestingPrimeFactors(P) P P P转换为另一个等价的 P ′ {P}' P,它需要完成以下工作:

  1. 计算 P = 2 w × 3 x × 5 y × 7 z P=2^{w} \times 3^{x} \times 5^{y} \times7^{z} P=2w×3x×5y×7z的各个指数值 w , x , y , z w,x,y,z w,x,y,z
  2. 任何一个质因子 p p p,指数为 v v v,计算一个最大值 v ′ {v}' v,满足 p v ′ ≤ 9 M p^{{v}'} \le 9M pv9M,以及 v ′ < v {v}'<v v<v
  3. 构建一个 P ′ = 2 w ′ × 3 x ′ × 5 y ′ × 7 z ′ {P}' = 2^{{w}'} \times 3^{{x}'} \times 5^{{y}'} \times7^{{z}'} P=2w×3x×5y×7z

接下来,我们就可以把 f 1 ( L , P , S ) f_{1}(L,P,S) f1(L,P,S)替换为 f 1 ( L , C a p I n t e r e s t i n g P r i m e F a c t o r s ( P ) , S ) f_{1}(L,CapInterestingPrimeFactors(P),S) f1(L,CapInterestingPrimeFactors(P),S)。因为S可能的值总共有 9 × 13 = 117 9\times13=117 9×13=117(由Test2的用例定义)。由上面定义,取上限之后 P ′ {P}' P的最大值为 2 6 × 3 4 × 5 2 × 7 2 2^{6}\times3^{4}\times5^{2}\times7^{2} 26×34×52×72,那么 C a p I n t e r e s t i n g P r i m e F a c t o r s ( P ) CapInterestingPrimeFactors(P) CapInterestingPrimeFactors(P)的值有 7 × 5 × 3 × 3 = 315 7\times5\times3\times3=315 7×5×3×3=315个。

至此, f 1 ( L , P ′ , S ) f_{1}(L,{P}',S) f1(L,P,S)的参数空间为 13 × 315 × ( 9 × 13 ) = 479 , 115 13\times315\times(9\times13)=479,115 13×315×(9×13)=479,115,相比如52,379,145,是一个巨大的提升。

Code

Java实现 Github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值