【Kickstart】2018 Round B - No Nine

解法

首先,把问题转化成要求f[x],既小于等于x的合法数字的个数。这样在FL之间的数就可以用f[F]-f[L]+1来得到了。

如果我们从0开始,用9进制表示整个自然数数列,我们可以得到:

012……89……n
012……810……m

观察这个数列,我们可以发现第n+1个数,就是mmn的9进制表示。
在9进制数列里,数字都是9个9个一组的,个位分别是0-8,十位及以后的位上有9的,就以组为单位丢掉了,比如90-98910-918
而在这9个数里,每个数mod 9的值都不同,总会有一个为0,也就是说,每组里只会有1个数是9的倍数

现在回到f[x]的求解,首先,我们设 x = d n d n − 1 . . . d 0 = ∑ i = 0 n d i ⋅ 1 0 i x=d_nd_{n-1}...d_0=\sum_{i=0}^n{d_i\cdot10^i} x=dndn1...d0=i=0ndi10i
由题目条件可知,它一定是个合法数字,所以它没有9。
我们把它当成一个9进制的数,转回十进制之后,得到 y = ∑ i = 0 n d i ⋅ 9 i y = \sum_{i=0}^n{d_i\cdot9^i} y=i=0ndi9i,就能知道它是第y+1个数,但是这时候有个问题,y+1 = 9a+b包含了a个整组和b个单独的数,容易知道 b = ( d 0 + 1 ) % 9 b=(d_0+1)\%9 b=(d0+1)%9,所以:

  1. 如果 d 0 = 8 d_0=8 d0=8,那么刚好a整组
  2. 如果 d 0 &lt; 8 d_0&lt; 8 d0<8,那么需要对这 d 0 + 1 d_0+1 d0+1个数单独check一下是不是9的倍数
  • 为了方便,可以直接把 [ x − d 0 , x ] [x-d_0,x] [xd0,x] 都check一下,不用管 d 0 d_0 d0是不是等于8。
  • x − d 0 x-d_0 xd0刚好是第 y − d 0 + 1 y-d_0+1 yd0+1个数,所以在它前面,也就是 [ 0 , x − d 0 ) [0,x-d_0) [0,xd0)里有 y − d 0 y-d_0 yd0个数,它应该刚好能分成 ∑ i = 1 d i ⋅ 9 i − 1 \sum_{i=1}d_i\cdot9^{i-1} i=1di9i1个组,每个组8个合法数字
#!/usr/bin/env python
# -*- coding: utf-8 -*-

def find(x):
    ans = 0
    y = x-x%10
    for i in xrange(y,x+1):
        if i%9!=0:
            ans += 1

    y /= 10
    i = 0
    mid = 0
    while y>0:
        mid += (y%10)*9**i
        i += 1
        y /= 10
    mid = mid<<3
    return mid+ans

def solve(f,l):
    return find(l)-find(f)+1

if __name__ == '__main__':
    t = input()
    for round in xrange(1,t+1):
        print "Case #%d: %d" %(round,solve(*map(int, raw_input().split())))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值