Project Euler 111

Project Euler 111

题目

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:

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.

$\mathbf{Digit, d}$ $\mathbf{M(4, d)}$ $\mathbf{N(4, d)}$ $\mathbf{S(4, d)}$
$0$ $2$ $13$ $67061$
$1$ $3$ $9$ $22275$
$2$ $3$ $1$ $2221$
$3$ $3$ $12$ $46214$
$4$ $3$ $2$ $8888$
$5$ $3$ $1$ $5557$
$6$ $3$ $1$ $6661$
$7$ $3$ $9$ $57863$
$8$ $3$ $1$ $8887$
$9$ $3$ $7$ $48073$

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

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

解决方案

本题主要通过位运算的手段来枚举。

这里用一个$N$比特数$mask$表示一个$N$位数的状态。对于某个数位$d(0\leq d\leq 9)$,如果任意一个$N$位数,第$i$位为$d$,那么状态$mask$的第$i$位为$1$,否则为$0$。

以题目中的数字为例,如$d=1,N=4$时,$1117$表示成状态$(1110)_2$,$2111$为状态$(0111)_2$。

将所有的$N$比特状态值枚举出来,将状态按其中比特为$1$的数量$b$进行分类。

按照比特为$1$的数量$b$,从大到小枚举每个分类,遍历分类中所有的状态,然后通过递归生成对应状态$mask$下的所有数。在这些拥有$b$个某数位$d$的数中,如果存在一个数是质数,那么就有$M(N,d)=b$,第一次找到的结果就是最优的。找完其它有$b$个$d$的质数后,那么循环就可以停下来,不用再往后判断$b-1$个$d$的那些数了。

另外,还需要注意最高位不能填$0$这种情况。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from tools import is_prime

N = 10

ls = [[] for i in range(N)]
for s in range(1, (1 << N) - 1):
ls[bin(s).count('1')].append(s)


def gen(msk: int, f: int, digit: int, num: int, a: list):
if f == -1:
if isprime(num):
a.append(num)
return
if msk >> f & 1:
if digit == 0 and f == N - 1:
return
else:
gen(msk, f - 1, digit, num * 10 + digit, a)
else:
# 如果是在最高位任意填,那么必须从1开始填,否则从0开始填。
for k in range(int(f == N - 1), 10):
if k != digit:
gen(msk, f - 1, digit, num * 10 + k, a)


ans = 0
for digit in range(10):
for bits in range(N - 1, 0, -1):
a = []
for v in ls[bits]:
gen(v, N - 1, digit, 0, a)
s = sum(a)
if s:
ans += s
break
print(ans)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
Ujimatsu Chiya 微信 微信
Ujimatsu Chiya 支付宝 支付宝