|
发表于 2017-9-1 15:33:00
|
显示全部楼层
本帖最后由 chunchun2017 于 2017-9-2 11:27 编辑
答案是: 892371480,对应的R(d)=0.16358819553891188<15499/94744(=0.1635881955585578)
=============
思路:
R(n)=弹性分数个数/真分数个数=弹性分数个数/(n-1)=小于n且与n互质的数的个数/(n-1)
网上找了一下,求小于给定的n且与互质的数的个数,可以通过对欧拉函数算法稍加修改实现
初步运行看了一下100以内的数的R(n),再加上题目中的12的提示,发现了一个规律:
0<n<5时,最小的R(n)为R(4)
0<n<10时,最小的R(n)为R(6)
0<n<15时,最小的R(n)为R(12)
0<n<20时,最小的R(n)为R(18)
0<n<25时,最小的R(n)为R(24)
0<n<40时,最小的R(n)为R(30)
0<n<80时,最小的R(n)为R(60)
0<n<100时,最小的R(n)为R(90)
而
4=2*2
6=2*3
12=2^2*3
18=2*3^2
24=2^3*3
30=2*3*5
60=2^2*3*5
90=2*3^2*5
可见,R(n)最小值都是出现在当n等于[2,3,5,7,11...]这些素数从小到大累积相乘时
为了快速锁定可能满足条件的区间,循环时,不考虑同一素数的幂,而直接采用2*3*5*7这样的方式递增,第一次发现素数的乘积n对应的R(n)小于15499/94744时,马上跳出循环。此时的n(n=p1*p2*p3..*pn)虽然满足R(n)<15499/94744,但不一定是最小值,因为n1=p1*p2*p3...*p(n-1)肯定是不符合,而n=p1*p2*p3...*p(n)肯定是符合条件的,而对于(n1,n2]这个区间中,可能会有符合条件的,也可能不会有符合条件的,为止,需要进一步确定:
(n1,n2]这个区间范围仍然很大,逐一计算耗时太长,根据前面观察到的规律可以分析出,(n1,n2]这个区间中如果有数n0满足R(n0)<15499/94744,这个数必定也是p1*p2*p3...(若干个素数的乘积,可能还会有幂的形式)因此,需要将前面求出的n值对应的素数前面的所有素数与n1滚动相乘,放到一个列表list1中,然后将其从小到大排序,只要找到第一个符合R(n0)<15499/94744的n0,马上跳出循环,此时的n0就是符合条件的最小n0(因为后面即使有ni满足R(ni)<15499/94744,ni也会比n0大)
代码如下:
=====================================
- #count表示小于n的,与n互质的数的个数(包含1),同时count也表示n的弹性分数的个数
- #R(n)=count/(n-1)
- def PrintPrime(n): #输出[2,n]范围内所有的质数
- list0=[]
- for i in range(2,n+1):
- for j in range(2,int(math.sqrt(i))+1):
- if(i%j==0):
- break
- else:
- list0.append(i)
- return list0
- def euler(n): #count表示[1,n)范围内,不包含N,包含1,与互质的数的个数,返回值为R(n)
- n0 = n
- sqrt_n = int(math.sqrt(n))
- count = n
- for i in range(2,sqrt_n+1):
- if(n%i==0):
- count = int(count/i*(i-1))
- while(n%i == 0):
- n/=i
- if(n>1):
- count = int(count/n*(n-1))
- return count/(n0-1)
- import math
- min0 = 15499/94744
- list0 = PrintPrime(30) #用于存放从2到30范围内的所有素数
- sum = 1
- for i in list0: #先找到满足条件的N的上界
- sum*=i
- if(euler(sum)<min0):
- n0 = sum
- min = euler(sum)
- break;
- list1=[int(sum/i),]#list1用于存放[sum/i,sum]范围内可能满足R(d)<15499/94744的数,list1[0]本来是不满足R(d)要求的,但为了计算方便,也放入list1
- for k in list0[0:list0.index(i)]:
- for each in list1:
- sum1 = k*each
- if(sum1>=n0):
- break
- else:
- list1.append(sum1)
- list1.sort()
- for n in list1[1:]: #跳过list1[0]
- if(euler(n)<min0):
- break
- print('符合条件的最小N为: %d' % n)
- print('%d对应的R(d)为:' % n,euler(n))
复制代码
运行结果:
符合条件的最小N为: 892371480
892371480对应的R(d)为: 0.16358819553891188
|
评分
-
参与人数 1 | 荣誉 +10 |
鱼币 +10 |
贡献 +10 |
收起
理由
|
冬雪雪冬
| + 10 |
+ 10 |
+ 10 |
分析的头头是道。 |
查看全部评分
|