鱼C论坛

 找回密码
 立即注册
查看: 2662|回复: 4

题目111:寻找含有最多重复位的10位的素数

[复制链接]
发表于 2016-8-21 00:55:39 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Primes with runs

Considering 4-digit primes containing repeated digits it is clear that they cannot all be the same: 1111 is divisible by 11, 2222 is divisible by 22, and so on. But there are nine 4-digit primes containing three ones:

1117, 1151, 1171, 1181, 1511, 1811, 2111, 4111, 8111


We shall say that M(n, d) represents the maximum number of repeated digits for an n-digit prime where d is the repeated digit, N(n, d) represents the number of such primes, and S(n, d) represents the sum of these primes.

So M(4, 1) = 3 is the maximum number of repeated digits for a 4-digit prime where one is the repeated digit, there are N(4, 1) = 9 such primes, and the sum of these primes is S(4, 1) = 22275. It turns out that for d = 0, it is only possible to have M(4, 0) = 2 repeated digits, but there are N(4, 0) = 13 such cases.

In the same way we obtain the following results for 4-digit primes.

QQ20160821-1@2x.png


For d = 0 to 9, the sum of all S(4, d) is 273700.

Find the sum of all S(10, d).


题目:

考虑含有重复位的四位数素数。显然这四位数不能全部相同:1111 可以被 11 整除,2222 可以被 22 整除,等等。但是有 9 个四位的素数包含三个 1:

1117, 1151, 1171, 1181, 1511, 1811, 2111, 4111, 8111


我们用 M(n, d) 来表示一个 n 位素数中重复位的最大值,其中 d 代表重复的数字。用 N(n, d) 代表这样的素数的数量,S(n, d) 来代表这些素数之和。

所以 M(4,1) = 3,是四位的素数中重复位的最大值,其中 1 是重复的那一位数。共有 N(4,1)=9 个这样的素数,他们的和 S(4,1)=22275。事实证明对于  d=0,只能有 M(4,0)=2 个重复位,但是却有 N(4,0)=13 个这样的数。

用同样的方法我们可以得到对于四位数素数的如下结果:

QQ20160821-1@2x.png


对于 d=0 到 9,S(4,d) 之和为 273700。

求所有 S(10,d) 之和。

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2016-10-28 16:56:47 | 显示全部楼层
当n=4时,程序已经验证成功了,而且速度也挺快 0.5秒不到
但是放到n=10的时候,感觉要等好久,看来还要优化算法。
273700
Time used: 0.34
  1. # -*- coding: utf-8 -*-
  2. import itertools as it
  3. import math
  4. import time
  5. start = time.time()
  6. def getPrime(n):
  7.         primes = [True]*n
  8.         primes[0], primes[1] = False, False
  9.         for (i,prime) in enumerate(primes):
  10.                 if prime:
  11.                         for j in range(i*i,n,i):
  12.                                 primes[j] = False
  13.         plist = []
  14.         for (k,trueprime) in enumerate(primes):
  15.                 if trueprime:
  16.                         plist.append(k)
  17.         return plist
  18. primes = getPrime(100000)
  19. def isPrime(n):
  20.         if n > 100000:
  21.                 for i in primes:
  22.                         if n%i==0:
  23.                                 return False
  24.                         if i*i > n:
  25.                                 break
  26.                 return True
  27.         else:
  28.                 if n in primes:
  29.                         return True
  30.                 else:
  31.                         return False

  32. def pr(n,d):
  33.         pl = list(range(d))+list(range(d+1,10))
  34.         for i in range(n-1,1,-1):
  35.                 cl = []
  36.                 com = it.combinations(pl,(n-i))
  37.                 for each in com:
  38.                         tl = list(each)
  39.                         for j in range(i):
  40.                                 tl.append(d)
  41.                         cl.append(tl)
  42.                 plst = set()
  43.                 for ecom in cl:
  44.                         al = it.permutations(ecom,n)
  45.                         for a in al:
  46.                                 s = 0
  47.                                 for j in range(n):
  48.                                         s = s*10+a[j]
  49.                                 if isPrime(s) and int(math.log10(s)) == n-1:
  50.                                         plst.add(s)
  51.                 if len(plst) > 0:
  52.                         break
  53.         return plst

  54. print (sum(sum(pr(4,k)) for k in range(10)))
  55. print ('Time used: %.2f' % (time.time()-start))
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-10-28 23:39:11 | 显示全部楼层
对算法进行了优化
  1. # -*- coding: utf-8 -*-
  2. from itertools import combinations

  3. import time
  4. start = time.time()
  5. def getPrime(n):
  6.         primes = [True]*n
  7.         primes[0], primes[1] = False, False
  8.         for (i,prime) in enumerate(primes):
  9.                 if prime:
  10.                         for j in range(i*i,n,i):
  11.                                 primes[j] = False
  12.         plist = []
  13.         for (k,trueprime) in enumerate(primes):
  14.                 if trueprime:
  15.                         plist.append(k)
  16.         return plist
  17. primes = getPrime(100000)
  18. def isPrime(n):
  19.         if n > 100000:
  20.                 for i in primes:
  21.                         if n%i==0:
  22.                                 return False
  23.                         if i*i > n:
  24.                                 break
  25.                 return True
  26.         else:
  27.                 if n in primes:
  28.                         return True
  29.                 else:
  30.                         return False

  31. def generateDigitLists(n,without, withZero=False):
  32.     if n == 0:
  33.         yield []
  34.     else:
  35.         start = 0 if withZero else 1
  36.         for lst in generateDigitLists(n-1,without, True):
  37.             for i in range(start,10):
  38.                 if i != without:
  39.                     yield [i] + lst

  40. def F(n,d):
  41.     for k in range(n-1,0,-1):
  42.         resultSet = set()
  43.         start = 0 if d != 0 else 1
  44.         for dInds in combinations(range(start,n), k):
  45.             for dList in generateDigitLists(n-k,d, d != 0 and 0 in dInds):
  46.                 j=0
  47.                 lst = [d]*n
  48.                 for i in range(n):
  49.                     if i not in dInds:
  50.                         lst[i] = dList[j]
  51.                         j += 1
  52.                 number = int(''.join(str(dig) for dig in lst))
  53.                 if isPrime(number) :
  54.                     resultSet.add(number)
  55.         if len(resultSet) > 0:
  56.             return k,resultSet


  57. def MNS(n,d):
  58.     k,rs = F(n,d)
  59.     return k,len(rs),sum(rs)

  60. def e111(n):
  61.     r = 0
  62.     for d in range(10):
  63.         m,ln,s = MNS(n,d)
  64.         r += s
  65.     return r

  66. print (e111(10))

  67. print ("Time used: %.2f sec" % (time.time()-start))
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-4-26 10:16:58 | 显示全部楼层
M(10,0) = 8     N(10,0) = 8     S(10,0) = 38000000042
M(10,1) = 9     N(10,1) = 11    S(10,1) = 12882626601
M(10,2) = 8     N(10,2) = 39    S(10,2) = 97447914665
M(10,3) = 9     N(10,3) = 7     S(10,3) = 23234122821
M(10,4) = 9     N(10,4) = 1     S(10,4) = 4444444447
M(10,5) = 9     N(10,5) = 1     S(10,5) = 5555555557
M(10,6) = 9     N(10,6) = 1     S(10,6) = 6666666661
M(10,7) = 9     N(10,7) = 9     S(10,7) = 59950904793
M(10,8) = 8     N(10,8) = 32    S(10,8) = 285769942206
M(10,9) = 9     N(10,9) = 8     S(10,9) = 78455389922
Sum = 612407567715
耗时:0.0164531秒
主要检验的数不能用循环来产生。而要根据规律用“填数”方法来产生。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2022-2-9 20:22:10 | 显示全部楼层
本帖最后由 guosl 于 2022-2-10 08:32 编辑
  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <omp.h>
  6. using namespace std;

  7. const int nLen = 10;//讨论的素数位数

  8. char cPrimes[100104];//cPrimes[i]=1表示i是一个素数
  9. int nPrimes[9600];//具体记录素数
  10. int nps = 0;//记录在0到100100之间素数的个数
  11. int nCount[10];//nCount[i]记录N(nLen,i)的值
  12. long long lTSum[10];//lTSum[i]记录S(nLen,i)的值
  13. int nMaxCount[10];//nMaxCount[i]记录M(Len,i)的值

  14. void dfs(int nCt, //当前未变动的数字的个数,也是取指定数字的个数
  15.   int nPos, //填充的位置
  16.   const char* str, //逐渐被填充的字符串(最后形成欲求的素数)
  17.   int nChkInt)//指定的数字
  18. {
  19.   if (nCt == nMaxCount[nChkInt])//所有可变动的指标已经用完
  20.   {
  21.     //检查最后生成的数字是否是一个素数
  22.     long long x = 0;
  23.     for (int i = 0; i < nLen; ++i)
  24.     {
  25.       x *= 10;
  26.       x += str[i];
  27.     }
  28.     int nD = sqrt((double)x);
  29.     bool bIsPrime = true;
  30.     for (int i = 0; nPrimes[i] <= nD; ++i)
  31.     {
  32.       long long p = (long long)nPrimes[i];
  33.       if (x%p == 0)
  34.       {
  35.         bIsPrime = false;
  36.         break;
  37.       }
  38.     }
  39.     if (!bIsPrime)
  40.       return;//不是素数
  41.     ++nCount[nChkInt];//保存结果
  42.     lTSum[nChkInt] += x;
  43.     return;
  44.   }
  45.   if (nPos >= nLen)//超出可填充的位置
  46.     return;
  47.   for (int i = 0; i < 10; ++i)//继续枚举在第nPos位置上的数字
  48.   {
  49.     char str1[16];
  50.     memcpy(str1, str, sizeof(str1));
  51.     str1[nPos] = i;
  52.     if (i == nChkInt)
  53.       dfs(nCt, nPos + 1, str1, nChkInt);//如果是指定值则未占用变动指标
  54.     else
  55.       dfs(nCt - 1, nPos + 1, str1, nChkInt);//如果不是指定值则占用变动指标
  56.   }
  57. }

  58. int main(void)
  59. {
  60.   double t = omp_get_wtime();
  61.   //筛法求批量素数
  62.   memset(cPrimes + 2, 1, sizeof(cPrimes) - 2);
  63.   for (int i = 2; i <= (int)sqrt(100100.0); ++i)
  64.   {
  65.     if (cPrimes[i] == 0)
  66.       continue;
  67.     for (int j = i*i; j < 100100; j += i)
  68.       cPrimes[j] = 0;
  69.   }
  70.   //保存具体的素数
  71.   nPrimes[nps++] = 2;
  72.   for (int i = 3; i < 100100; i += 2)
  73.   {
  74.     if (cPrimes[i] == 1)
  75.       nPrimes[nps++] = i;
  76.   }
  77.   long long lSum = 0;
  78. #pragma omp parallel for reduction(+:lSum)
  79.   for (int nChkInt = 0; nChkInt < 10; ++nChkInt)//求M(Len,nChkInt),N(Len,nChkInt),S(Len,nChkInt)
  80.   {
  81.     nMaxCount[nChkInt] = nLen;
  82.     while (nCount[nChkInt] == 0)
  83.     {
  84.       --nMaxCount[nChkInt];
  85.       char str[16];//记录最后满足条件的素数
  86.       memset(str, 0, sizeof(str));
  87.       for (int i = 1; i <= 9; ++i)//枚举要生成的素数的第0位上的数字
  88.       {
  89.         int k = nLen;
  90.         memset(str, nChkInt, nLen * sizeof(char));//把该数所有位置上的值都填成nChkInt
  91.         str[0] = i;
  92.         if (i != nChkInt)
  93.           --k;//未取指定的值,可变动数字的个数减一
  94.         dfs(k, 1, str, nChkInt);//逐步填充后面的位置上的数字
  95.       }
  96.     }
  97.     lSum += lTSum[nChkInt];
  98.   }
  99.   //输出结果
  100.   for (int i = 0; i < 10; ++i)
  101.     cout << "M(" << nLen << "," << i << ") = " << nMaxCount[i] << "\tN(" << nLen << "," << i << ") = " << nCount[i] << "\tS(" << nLen << "," << i << ") = " << lTSum[i] << endl;
  102.   cout << "Sum = " << lSum << endl;
  103.   t = omp_get_wtime() - t;
  104.   cout << "耗时:" << t << "秒" << endl;
  105.   return 0;
  106. }
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-23 21:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表