在线编程例题练习, HR姐姐看人

可以发现我们可以用一个递推公式来计算, S(N=4) = S(N=3) +new_points

new_points是新加的点中没有被原来点挡住的点

第一步:

仔细想来,如何判断一个点会不会被原来的点挡住 --> 相当于判断这个点的两个坐标是不是互质的

点(8,4)很明显会被点(4,2),而点(8,7)和点(8,1)就不会被之前的点挡住

第二步:

其实新增的点只需要算一半就可以了,因为图形和点是关于x=y这条直线对称的,也就是说如果(8,1)没有被挡住,我们直接可以知道(1,8)也一定没有被挡住

这诞生了我们第一版的基于递推和互质的程序

def gcd(x,y):
    if x > y:
        smaller = y
    else:
        smaller = x
    for i in range(1,smaller + 1):
        if((x % i == 0) and (y %i ==0)):
            hcf = i
    return hcf

count = 3
for i in range(2,N+1):
    new_points = 0
    for j in range(1,i):
        if gcd(i,j) == 1:
            new_points = new_points + 1
    count = count + 2*new_points

S = count

print(S)

相当于当从n到n+1,我们遍历一遍(新加入的点的一半),然后算出有几个互质的坐标对,然后乘以2加到S(n)


第二版,我们将求最大公因数的步骤换成辗转相除法:

def gcd(x,y):
    if x == y:
        #print(x)
        return x
    else:
        if x > y:
            x = x - y
        else:
            y = y - x
        return gcd(x,y)
    
    
    count = 3
new_points = 0

for i in range(2,N+1):
    for j in range(1,i):
        if gcd(i,j) == 1:
            new_points += 1
    

S = count + 2*new_points 

print(S)

考虑一下,怎么简化gcd函数,其实不需要递归,只需要一个循环既可

def gcd(a, b):
    while b:
        a, b=b, a%b
    return a

第四版,我们思考能不能不遍历所有的点,这时候考虑用欧拉公式。

即我们直接算出比n小且和n互质的正整数的个数,即我们一直想求的new_points的值。用欧拉公式我们不需要遍历:

import math

N=1000
def phi(n):
    amount = 0        
    for k in range(1, n + 1):
        if math.gcd(n, k) == 1:
            amount += 1
    return amount

count = 3
new_points = 0

for i in range(2,N+1):
    new_points += phi(i)
    

S = count + 2*new_points 

print(S)

但是上面这个是伪欧拉公式,实际上还是用gcd遍历来做的


第五版,我们自己来写正真的欧拉公式,发现一个简便的表达形式,稍后证明:

def isPrime(a):
    return not ( a < 2 or any(a % i == 0 for i in range(2, int(a ** 0.5) + 1)))

def phi(n):
    y = n
    for i in range(2,n+1):
        if isPrime(i) and n % i  == 0 :
            y -= y/i
        else:
            continue
    return int(y)

https://www.cnblogs.com/linyujun/p/5194170.html

借鉴上面这个blog,可以将欧拉函数写成:

def phi(n):
    y = n
    #print(round(n**0.5)+1)
    for i in range(2,round(n**0.5)+1):
        if n % i  == 0 :
            y -= y/i
            while (n % i ==0):
                n /= i
        else:
            continue
    if (n>1):
        y -= y/n
    return int(y)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值