分析:这道题并不像它的题目看上去那么复杂,核心在于寻找\(a_0,a_1,a_2\)等项之间的递推关系,找到这个递推关系后我们就可以很方便的计算连分数表示的周期。经搜索相关文献,我们发现在这个维基词条已经非常详细的描述了各个\(a\)项之间的递推关系,简述如下:对于某个非完全平方数\(S\),其平方根为无理数且有周期,设\(a_0=\lfloor{\sqrt{S}}\rfloor,m_0=0,d_0=1\),则三项的递推关系如下:
\[m_{n+1}=d_na_n-m_n,\ d_{n+1}=\frac{S-m_{n+1}^2}{d_n},\ a_{n+1}=\bigg\lfloor{\frac{a_0+m_{n+1}}{d_{n+1}}}\bigg\rfloor\]
此外根据文献推论3.3,当\(a_i=2a_0\)时循环周期即结束。如对于\(\sqrt{13}\)\(a_5=6=2a_0\),此时循环周期终止,其循环周期长度为五。因此,当我们计算连分数表示时,当计算到某一项是首项的二倍时,就不需要再往下计算了,此时可以直接计算出该连分数表示的循环周期长度。

使用以上原理,我们计算小于等于一万的非完全平方数的平方根的连分数表示的循环周期长度,对于完全平方数我们则可以直接路过,加快筛选的速度。最后我们统计计算出来的循环周期长度中的奇数值,即为题目所求,代码如下:

# time cost = 285 ms ± 3.41 ms

def square_root_period(n):
    a0 = int(n**0.5)
    if a0**2 == n:
        return 0
    else:
        a,m,d,arr = a0,0,1,[a0]
        while arr[-1] != 2*a0:
            m = d*a - m
            d = (n - m**2)//d
            a = int((a0+m)/d)
            arr.append(a)
    return len(arr)-1

def main(N=10000):
    c = 0
    for i in range(1,N+1):
        if square_root_period(i) % 2 == 1:
            c += 1
    return c
01-06 21:16