위치 의 숫자 부터 시작하여 숫자에서 숫자 Remove(n, startIndex, count)
를 제거 하는 기능 을 고려하십시오 . 예 :count
n
startIndex
Remove(1234, 1, 1) = 234
Remove(123456, 2, 3) = 156
Remove(1507, 1, 2) = 07 = 7
Remove(1234, 1, 4) = 0
우리는 가능한 모든 Remove
연산이 프라임이 아닌 경우 소수 X를 깨지기 쉬운 것으로 부릅니다 . 예를 들어, 80651은 다음과 같은 숫자가 모두 소수가 아니기 때문에 취약한 소수입니다.
651, 51, 1, 0, 8651, 851, 81, 8, 8051, 801, 80, 8061, 806, 8065
골
가장 깨지기 쉬운 소수를 찾는 프로그램을 작성하십시오. 편집 : 시간 제한을 우회하는 비교적 공정한 방법이 있었으므로 시간 제한을 제거했습니다.
점수는 프로그램에서 찾은 깨지기 쉬운 소수입니다. 동점 일 경우, 이전 제출물이 이깁니다.
규칙
- 모든 언어 및 타사 라이브러리를 사용할 수 있습니다.
- 자신의 하드웨어에서 프로그램을 실행합니다.
- 확률 우선 성 테스트를 사용할 수 있습니다.
- 모든 것은 기본 10에 있습니다.
주요 항목
- Qualtagh의 6629 자리 (자바)
- Emil이 작성한 5048 자리 (Python 2)
- Jakube의 2268 자리 숫자 (Python 2)
편집 : 나는 내 자신의 답변을 추가했습니다.
- Qualtagh의 알고리즘 (C #)을 기반으로 Suboptimus Prime의 28164 자리 숫자
답변
자바- 3144 3322 6629 자리
6 0{3314} 8969999
6 0{6623} 49099
이 솔루션은 FryAmTheEggman의 답변을 기반으로 합니다.
- 마지막 숫자는 1 또는 9입니다.
- 마지막 숫자가 1이면 이전 숫자는 0, 8 또는 9입니다.
- 마지막 숫자가 9이면 이전 숫자는 0, 4, 6 또는 9입니다.
- …
더 깊이 파면 어떨까요?
트리 구조가됩니다.
S
-----------------------
1 9
------------------ ----------------
0 8 9 0 4 6 9
--------- -----
0 8 9 ...
R과 모든 엔딩이 합성 인 경우 번호 R을 올바른 합성이라고합니다.
우리는 1, 9, 01, 81, 91, 09, 49, 69, 99, 001, 801, 901 등 모든 첫 번째 복합 번호를 반복 할 것입니다.
0으로 시작하는 숫자는 우선 순위를 검사하지 않지만 추가 숫자를 빌드하는 데 필요합니다.
X00 … 00R 형식의 대상 번호 N을 찾습니다. 여기서 X는 4, 6, 8 또는 9 중 하나이고 R은 올바른 합성입니다. X는 소수 일 수 없습니다. X는 0이 될 수 없습니다. R이 1 또는 9로 끝나면 N은 11 또는 19를 포함하므로 X는 1이 될 수 없습니다.
“제거”작업 후 XR에 소수가 포함되어 있으면 XYR에도 Y에 대한 소수가 포함됩니다. 따라서 R에서 시작하는 분기를 통과해서는 안됩니다.
X를 상수라고합시다 (6).
의사 코드 :
X = 6;
for ( String R : breadth-first-traverse-of-all-right-composites ) {
if ( R ends with 1 or 9 ) {
if ( remove( X + R, i, j ) is composite for all i and j ) {
for ( String zeros = ""; zeros.length() < LIMIT; zeros += "0" ) {
if ( X + zeros + R is prime ) {
// At this step these conditions hold:
// 1. X + 0...0 is composite.
// 2. 0...0 + R = R is composite.
// 3. X + 0...0 + R is composite if 0...0 is shorter than zeros.
suits = true;
for ( E : all R endings )
if ( X + zeros + E is prime )
suits = false;
if ( suits )
print R + " is fragile prime";
break; // try another R
// because ( X + zeros + 0...0 + R )
// would contain prime ( X + zeros + R ).
}
}
}
}
}
X + zeros + R 형식으로 소수를 찾는 데 너무 오래 걸릴 수 있기 때문에 zeros 수량을 제한해야합니다.
실제 코드는 매우 장황하며 여기 에서 찾을 수 있습니다 .
긴 int 범위의 숫자에 대한 우선 순위 테스트는 Miller 테스트의 결정적 변형에 의해 수행됩니다. BigInteger 번호의 경우 시험 분할이 먼저 수행 된 다음 BailliePSW 테스트가 수행됩니다. 확률 적이지만 확실합니다. 그리고 Miller-Rabin 테스트보다 빠릅니다 (밀러 라빈에서 그러한 큰 숫자를 충분히 반복하려면 많은 반복을 수행해야합니다).
편집 : 첫 번째 시도가 잘못되었습니다. X0 … 0R이 소수이면 R로 시작하는 분기도 무시해야합니다. 그러면 X0 … 0YR은 연약한 소수가 아닙니다. 그래서 추가 점검이 추가되었습니다. 이 솔루션은 올바른 것 같습니다.
편집 2 : 최적화가 추가되었습니다. (X + R)을 3으로 나눌 수 있으면 (X + zeros + R)도 3으로 나눌 수 있습니다. 따라서이 경우 (X + zeros + R)은 소수가 아니며 그러한 R은 건너 뛸 수 있습니다.
편집 3 : 소수 또는 마지막 위치가 아닌 경우 소수를 건너 뛸 필요가 없습니다. 따라서 21 또는 51과 같은 결말은 괜찮습니다. 그러나 별다른 변화는 없습니다.
결론 :
- 마지막 대답은 100 분 동안 깨지기 쉬운 지 확인하는 것이 었습니다. 답변을 검색하는 데 (앞의 모든 변형 확인) 약 15 분이 걸렸습니다. 예, 검색 시간을 제한하는 것은 의미가 없습니다 (대상 번호에서 검색을 시작할 수 있으므로 시간은 0이됩니다). 그러나이 질문 에서처럼 검사 시간을 제한하는 것이 의미가있을 수 있습니다 .
- 답 60 … 049099는 중간에 숫자 4가 있습니다. “제거”조작이 접촉하면 숫자를 3으로 나눌 수 있습니다. 따라서 왼쪽과 오른쪽에서 제거 조작을 확인해야합니다. 오른쪽이 너무 짧습니다. 왼쪽 길이는 거의 n = 길이 (N)입니다.
- BPSW 및 Miller-Rabin과 같은 우선 순위 테스트는 일정한 수량의 모듈 식 지수를 사용합니다. 이 페이지 에 따르면 복잡도는 O (M (n) * n) 이며, 여기서 M (n)은 곱셈 복잡도입니다. Java는 Toom-Cook 및 Karatsuba 알고리즘을 사용하지만 단순성을 위해 학술 알고리즘을 사용합니다. M (n)은 N = 2 . 따라서 원시성 테스트 복잡도는 O (n 3 )입니다.
- 우리는 길이 = 6에서 6629 사이의 모든 숫자를 확인해야합니다. 공통성을 위해 min = 1과 max = n을 취합시다. 전체 검사 복잡도는 O (1 3 + 2 3 + … + n 3 ) = O ((n * (n + 1) / 2) 2 ) = O (n 4 )입니다.
- 에밀의 대답 은 무증상 검사와 동일합니다. 그러나 상수는 낮습니다. 숫자 “7”은 숫자 중간에 서 있습니다. 왼쪽과 오른쪽은 거의 같습니다. 또한 (N / 2) 범 4 * 2 = N 4 배속 / 8 시간 단축. 9 … 9Y9 … 9 형식의 숫자는 동일한 점검 시간을 갖는 X0 … 0R 형식보다 1.7 배 더 길 수 있습니다.
답변
파이썬 2 – (126) 1221 1337 1719 2268 자리
999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
'9' * 1944 + '7' + '9' * 323
Remove (n, startIndex, count)의 결과는 약 len (n) ^ 2 개입니다. 나는 그 숫자를 최소화하려고 노력했다. 서로 옆에 많은 자릿수가 동일하면 여러 번 나타나기 때문에 이러한 많은 숫자가 무시 될 수 있습니다.
그래서 나는 9 초에 약간의 소수를 가져갔습니다. 나는 또한 1 백만 이하의 연약한 소수를 보았고, 그러한 연약한 소수가 있음을 보았다. 마지막에 2 9가있는 숫자를 검색하면 실제로 잘 작동하지만 이유는 확실하지 않습니다. 마지막에 1, 3 또는 4 9를 사용하면 연약한 소수가 작아집니다.
pyprimes 모듈을 사용합니다 . 그것이 좋은지 확실하지 않습니다. miller_rabin 테스트를 사용하므로 확률 적입니다.
이 프로그램은 약 1 분 안에이 126 자리의 깨지기 쉬운 프라임을 찾고 나머지 시간 동안 성공하지 않고 검색합니다.
biggest_found = 80651
n = lambda a,b,c: '9'*a + b + '9'*c
for j in range(1000):
for digit in '124578':
for i in range(2000):
number = int(n(i,digit,j))
if is_prime(number):
if (number > biggest_found):
if all(not is_prime(int(n(i,digit,k))) for k in range(j)):
biggest_found = number
print(i+j+1, biggest_found)
break
편집하다:
시간 제한을 제거한 것을 보았습니다. 나는 밤새 프로그램을 운영 할 것이다. 어쩌면 정말 큰 연약한 소수가 나타날 것이다.
편집 2 :
내 원래 프로그램을 더 빨리 만들었지 만 여전히 126 자리 이상의 솔루션은 없습니다. 그래서 나는 기차를 타고 x 9s + 1 digit + y 9s를 검색했습니다. 장점은 y를 고치면 O (n) 수에 대한 우선 순위를 확인해야한다는 것입니다. 1221은 다소 빨리 발견됩니다.
편집 3 :
2268 자리 숫자의 경우 동일한 프로그램을 사용하고 여러 코어의 작업 만 나눕니다.
답변
파이썬 2.7-429623069 99993799
지금까지 최적화가 없습니다. 깨지기 쉬운 프라임에 대한 사소한 관찰을 사용하십시오 (채팅에서 Rainbolt 덕분에).
- 깨지기 쉬운 소수는 1 또는 9로 끝나야합니다 (프라임은 고르지 않으며 마지막 숫자는 소수가 아니어야합니다)
- 1로 끝나는 연약한 소수는 8 또는 9로 시작해야합니다 (첫 번째 숫자는 소수 일 수 없으며 11, 41 및 61은 모두 소수입니다)
- 9로 끝나는 연약한 소수는 4, 6 또는 9로 시작해야합니다 (1에 대한 추론 참조, 89 만 소수입니다)
그냥 공 구르려고 노력 🙂
이것은 기술적으로 15 분에 걸쳐 약간 실행되지만 추가 시간에 단일 숫자 만 확인합니다.
is_prime
에서 가져온 여기 (isaacg 그것을 사용 여기 )와 확률이다.
def substrings(a):
l=len(a)
out=set()
for i in range(l):
for j in range(l-i):
out.add(a[:i]+a[len(a)-j:])
return out
import time
n=9
while time.clock()<15*60:
if is_prime(n):
if not any(map(lambda n: n!='' and is_prime(int(n)), substrings(`n`))):
print n
t=`n`
if n%10==9 and t[0]=='8':n+=2
elif n%10==1 and t[0]!='8':n+=8
elif t[0]=='1' or is_prime(int(t[0])):n+=10**~-len(t)
else:n+=10
참고로 시작 n=429623069
하면 최대에 도달합니다 482704669
. 여분의 숫자는 실제로이 전략을 죽이는 것 같습니다 …
답변
Python 2, 828 자리 5048 자리
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999799999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
155*'9'+'7'+4892*'9'
@Jakube가 지적했듯이 제출 한 첫 번째 소수는 실제로 내 코드의 버그로 인해 취약하지 않았습니다. 버그를 수정하는 것은 쉽지만 알고리즘을 상당히 느리게 만들었습니다.
나는 쉽게 깨지기 쉬운 소수의 하위 집합, 즉 숫자 9와 정확히 하나의 숫자 7로 구성된 하위 집합으로 나 자신을 제한했습니다.
def fragile_prime_generator(x, b_max):
bs, cs = set(), set()
prime = dict()
def test_prime(b,c):
if (b,c) not in prime:
prime[(b,c)] = is_prime(int('9'*b+`x`+'9'*c))
return prime[(b,c)]
def test_frag(b,c):
for b2 in xrange(b):
if test_prime(b2,c):
bs.add(b2)
return False
for c2 in xrange(c):
if test_prime(b,c2):
cs.add(c2)
return False
return True
a = 1
while len(bs)<b_max:
for b in xrange(min(a, b_max)):
c = a-b
if b not in bs and c not in cs and test_prime(b,c):
bs.add(b)
cs.add(c)
if test_frag(b,c): yield b,c
a += 1
print "no more fragile primes of this form"
for b,c in fragile_prime_generator(7, 222):
print ("%d digit fragile prime found: %d*'9'+'%d'+%d*'9'"
% (b+c+1, b, x, c))
나는 같은 사용 is_prime
(에서 기능을 여기 @FryAmTheEggman 등).
편집하다:
알고리즘을 더 빠르게 만들기 위해 두 가지 사항을 변경했습니다.
-
가능한 한 많은 수의 우선 순위 검사를 건너 뛰고 잠재적으로 깨지기 쉬운 프라임이 실제로 깨지기 쉬운 지 확인한 경우에만 되돌아갑니다. 중복 검사가 적으므로 프라임 검사 기능을 대략적으로 메모했습니다.
-
양식의 숫자에 대해서는
b*'9' + '7' + c*'9'
의 크기를 제한했습니다b
. 한계가 낮을수록 더 적은 숫자를 확인해야하지만 큰 연약한 소수를 전혀 찾지 못할 가능성이 높아집니다. 나는 일종의 222를 임의로 선택했습니다.
수천 자리에서 단일 소수 검사는 이미 내 프로그램을 몇 초가 걸릴 수 있습니다. 따라서이 접근법으로 더 잘 할 수는 없습니다.
제출 한 내용의 정확성을 확인하십시오. 확률 적 우선 순위 점검으로 인해 내 숫자는 이론적으로 소수가 될 수 없지만 그 숫자는 깨지기 쉬워야합니다. 또는 내가 잘못한 것입니다. 🙂
답변
C #, 10039 28164 자리
6 0{28157} 169669
편집 : 약간의 수정으로 Qualtagh의 알고리즘을 기반으로 다른 프로그램을 만들었습니다.
- L000 … 000R 형식의 숫자를 검색 중입니다. 여기서 L은 왼쪽 합성, R은 오른쪽 합성입니다. 왼쪽 복합 숫자 L이 여러 자릿수를 갖도록 허용했지만, 이는 주로 스타일 변경이며 알고리즘의 효율성에 영향을 미치지 않습니다.
- 검색 속도를 높이기 위해 멀티 스레딩을 추가했습니다.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading;
using System.Threading.Tasks;
using Mpir.NET;
class Program
{
const int PrimeNotFound = int.MaxValue;
private static BitArray _primeSieve;
private static HashSet<Tuple<int, int>> _templatesToSkip = new HashSet<Tuple<int, int>>();
static void Main(string[] args)
{
int bestDigitCount = 0;
foreach (Tuple<int, int> template in GetTemplates())
{
int left = template.Item1;
int right = template.Item2;
if (SkipTemplate(left, right))
continue;
int zeroCount = GetZeroCountOfPrime(left, right);
if (zeroCount != PrimeNotFound)
{
int digitCount = left.ToString().Length + right.ToString().Length + zeroCount;
if (digitCount >= bestDigitCount)
{
string primeStr = left + " 0{" + zeroCount + "} " + right;
Console.WriteLine("testing " + primeStr);
bool isFragile = IsFragile(left, right, zeroCount);
Console.WriteLine(primeStr + " is fragile: " + isFragile);
if (isFragile)
bestDigitCount = digitCount;
}
_templatesToSkip.Add(template);
}
}
}
private static int GetZeroCountOfPrime(int left, int right)
{
_zeroCount = 0;
int threadCount = Environment.ProcessorCount;
Task<int>[] tasks = new Task<int>[threadCount];
for (int i = 0; i < threadCount; i++)
tasks[i] = Task.Run(() => InternalGetZeroCountOfPrime(left, right));
Task.WaitAll(tasks);
return tasks.Min(task => task.Result);
}
private static int _zeroCount;
private static int InternalGetZeroCountOfPrime(int left, int right)
{
const int maxZeroCount = 40000;
int zeroCount = Interlocked.Increment(ref _zeroCount);
while (zeroCount <= maxZeroCount)
{
if (zeroCount % 1000 == 0)
Console.WriteLine("testing " + left + " 0{" + zeroCount + "} " + right);
if (IsPrime(left, right, zeroCount))
{
Interlocked.Add(ref _zeroCount, maxZeroCount);
return zeroCount;
}
else
zeroCount = Interlocked.Increment(ref _zeroCount);
}
return PrimeNotFound;
}
private static bool SkipTemplate(int left, int right)
{
for (int leftDiv = 1; leftDiv <= left; leftDiv *= 10)
for (int rightDiv = 1; rightDiv <= right; rightDiv *= 10)
if (_templatesToSkip.Contains(Tuple.Create(left / leftDiv, right % (rightDiv * 10))))
return true;
return false;
}
private static bool IsPrime(int left, int right, int zeroCount)
{
return IsPrime(left.ToString() + new string('0', zeroCount) + right.ToString());
}
private static bool IsPrime(string left, string right, int zeroCount)
{
return IsPrime(left + new string('0', zeroCount) + right);
}
private static bool IsPrime(string s)
{
using (mpz_t n = new mpz_t(s))
{
return n.IsProbablyPrimeRabinMiller(20);
}
}
private static bool IsFragile(int left, int right, int zeroCount)
{
string leftStr = left.ToString();
string rightStr = right.ToString();
for (int startIndex = 0; startIndex < leftStr.Length - 1; startIndex++)
for (int count = 1; count < leftStr.Length - startIndex; count++)
if (IsPrime(leftStr.Remove(startIndex, count), rightStr, zeroCount))
return false;
for (int startIndex = 1; startIndex < rightStr.Length; startIndex++)
for (int count = 1; count <= rightStr.Length - startIndex; count++)
if (IsPrime(leftStr, rightStr.Remove(startIndex, count), zeroCount))
return false;
return true;
}
private static IEnumerable<Tuple<int, int>> GetTemplates()
{
const int maxDigitCount = 8;
PreparePrimeSieve((int)BigInteger.Pow(10, maxDigitCount));
for (int digitCount = 2; digitCount <= maxDigitCount; digitCount++)
{
for (int leftCount = 1; leftCount < digitCount; leftCount++)
{
int rightCount = digitCount - leftCount;
int maxLeft = (int)BigInteger.Pow(10, leftCount);
int maxRight = (int)BigInteger.Pow(10, rightCount);
for (int left = maxLeft / 10; left < maxLeft; left++)
for (int right = maxRight / 10; right < maxRight; right++)
if (IsValidTemplate(left, right, leftCount, rightCount))
yield return Tuple.Create(left, right);
}
}
}
private static void PreparePrimeSieve(int limit)
{
_primeSieve = new BitArray(limit + 1, true);
_primeSieve[0] = false;
_primeSieve[1] = false;
for (int i = 2; i * i <= limit; i++)
if (_primeSieve[i])
for (int j = i * i; j <= limit; j += i)
_primeSieve[j] = false;
}
private static bool IsValidTemplate(int left, int right, int leftCount, int rightCount)
{
int rightDigit = right % 10;
if ((rightDigit != 1) && (rightDigit != 9))
return false;
if (left % 10 == 0)
return false;
if ((left + right) % 3 == 0)
return false;
if (!Coprime(left, right))
return false;
int leftDiv = 1;
for (int i = 0; i <= leftCount; i++)
{
int rightDiv = 1;
for (int j = 0; j <= rightCount; j++)
{
int combination = left / leftDiv * rightDiv + right % rightDiv;
if (_primeSieve[combination])
return false;
rightDiv *= 10;
}
leftDiv *= 10;
}
return true;
}
private static bool Coprime(int a, int b)
{
while (b != 0)
{
int t = b;
b = a % b;
a = t;
}
return a == 1;
}
}
이전 답변 :
8 0{5436} 4 0{4600} 1
깨지기 쉬운 프라임의 몇 가지 주목할만한 패턴은 다음과 같습니다.
600..00X00..009
900..00X00..009
800..00X00..001
999..99X99..999
여기서 X는 1, 2, 4, 5, 7 또는 8 일 수 있습니다.
이러한 숫자의 경우 가능한 길이 만 (길이-1) 만 고려하면 Remove
됩니다. 다른 Remove
연산은 중복 또는 명백하게 복합 숫자를 생성합니다. 800 자리까지의 모든 숫자를 검색하려고 시도했지만 나머지 패턴보다 8007001, 8004001, 9997999 및 6004009의 4 가지 패턴이 더 자주 나타납니다. Emil과 Jakube가 999X999 패턴을 사용하고 있기 때문에 8004001을 사용하기로 결정했습니다. 다양성을 추가하십시오.
알고리즘에 다음 최적화를 추가했습니다.
- 7000 자리 숫자로 검색을 시작한 다음 깨지기 쉬운 소수가 발견 될 때마다 길이를 1500 씩 증가시킵니다. 주어진 길이의 깨지기 쉬운 소수가 없으면 1 씩 증가시킵니다. 7000과 1500은 적절하게 보이는 임의의 숫자입니다.
- 멀티 스레딩을 사용하여 길이가 다른 숫자를 동시에 검색하고 있습니다.
- 각 프라임 검사의 결과는 중복 검사를 방지하기 위해 해시 테이블에 저장됩니다.
- Mpir.NET 에서 Miller-Rabin 구현을 사용하고 있습니다 .MPIR 은 GMP의 포크입니다.
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Mpir.NET;
class Program
{
const string _template = "8041";
private static ConcurrentDictionary<Tuple<int, int>, byte> _compositeNumbers = new ConcurrentDictionary<Tuple<int, int>, byte>();
private static ConcurrentDictionary<int, int> _leftPrimes = new ConcurrentDictionary<int, int>();
private static ConcurrentDictionary<int, int> _rightPrimes = new ConcurrentDictionary<int, int>();
static void Main(string[] args)
{
int threadCount = Environment.ProcessorCount;
Task[] tasks = new Task[threadCount];
for (int i = 0; i < threadCount; i++)
{
int index = i;
tasks[index] = Task.Run(() => SearchFragilePrimes());
}
Task.WaitAll(tasks);
}
private const int _lengthIncrement = 1500;
private static int _length = 7000;
private static object _lengthLock = new object();
private static object _consoleLock = new object();
private static void SearchFragilePrimes()
{
int length;
lock (_lengthLock)
{
_length++;
length = _length;
}
while (true)
{
lock (_consoleLock)
{
Console.WriteLine("{0:T}: length = {1}", DateTime.Now, length);
}
bool found = false;
for (int rightCount = 1; rightCount <= length - 2; rightCount++)
{
int leftCount = length - rightCount - 1;
if (IsFragilePrime(leftCount, rightCount))
{
lock (_consoleLock)
{
Console.WriteLine("{0:T}: {1} {2}{{{3}}} {4} {2}{{{5}}} {6}",
DateTime.Now, _template[0], _template[1], leftCount - 1,
_template[2], rightCount - 1, _template[3]);
}
found = true;
break;
}
}
lock (_lengthLock)
{
if (found && (_length < length + _lengthIncrement / 2))
_length += _lengthIncrement;
else
_length++;
length = _length;
}
}
}
private static bool IsFragilePrime(int leftCount, int rightCount)
{
int count;
if (_leftPrimes.TryGetValue(leftCount, out count))
if (count < rightCount)
return false;
if (_rightPrimes.TryGetValue(rightCount, out count))
if (count < leftCount)
return false;
if (!IsPrime(leftCount, rightCount))
return false;
for (int i = 0; i < leftCount; i++)
if (IsPrime(i, rightCount))
return false;
for (int i = 0; i < rightCount; i++)
if (IsPrime(leftCount, i))
return false;
return true;
}
private static bool IsPrime(int leftCount, int rightCount)
{
Tuple<int, int> tuple = Tuple.Create(leftCount, rightCount);
if (_compositeNumbers.ContainsKey(tuple))
return false;
using (mpz_t n = new mpz_t(BuildStr(leftCount, rightCount)))
{
bool result = n.IsProbablyPrimeRabinMiller(20);
if (result)
{
_leftPrimes.TryAdd(leftCount, rightCount);
_rightPrimes.TryAdd(rightCount, leftCount);
}
else
_compositeNumbers.TryAdd(tuple, 0);
return result;
}
}
private static string BuildStr(int leftCount, int rightCount)
{
char[] chars = new char[leftCount + rightCount + 1];
for (int i = 0; i < chars.Length; i++)
chars[i] = _template[1];
chars[0] = _template[0];
chars[leftCount + rightCount] = _template[3];
chars[leftCount] = _template[2];
return new string(chars);
}
}
답변
Haskell- 1220 자리 숫자 는 실제 실수 로 수정되었습니다.
99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999997999999999999999999999999999999999999999999999999999999999999999999999
9{1150} 7 9{69}
더 나은 하나-1277 자리
9{871} 8 9{405}
하스켈 코드
downADigit :: Integer -> [Integer]
downADigit n = f [] 1 where
f xs a | nma /= n = f (((n `div` a10)*a + nma):xs) a10
| otherwise = xs where
a10 = a * 10
nma = n `mod` a
isFragile = all (not . isPrime') . downADigit
findNextPrime :: Integer -> Integer
findNextPrime n | even n = f (n + 1)
| otherwise = f n where
f n | isPrime' n = n
| otherwise = f (n + 2)
primesFrom n = f (findNextPrime n) where
f n = n:f (findNextPrime $ n + 1)
primeLimit = 10000
isPrime' n | n < primeLimit = isPrime n
isPrime' n = all (millerRabinPrimality n) [2,3,5,7,11,13,17,19,984,7283,6628,8398,2983,9849,2739]
-- (eq. to) find2km (2^k * n) = (k,n)
find2km :: Integer -> (Integer,Integer)
find2km n = f 0 n
where
f k m
| r == 1 = (k,m)
| otherwise = f (k+1) q
where (q,r) = quotRem m 2
-- n is the number to test; a is the (presumably randomly chosen) witness
millerRabinPrimality :: Integer -> Integer -> Bool
millerRabinPrimality n a
| a <= 1 || a >= n-1 =
error $ "millerRabinPrimality: a out of range ("
++ show a ++ " for "++ show n ++ ")"
| n < 2 = False
| even n = False
| b0 == 1 || b0 == n' = True
| otherwise = iter (tail b)
where
n' = n-1
(k,m) = find2km n'
b0 = powMod n a m
b = take (fromIntegral k) $ iterate (squareMod n) b0
iter [] = False
iter (x:xs)
| x == 1 = False
| x == n' = True
| otherwise = iter xs
-- (eq. to) pow' (*) (^2) n k = n^k
pow' :: (Num a, Integral b) => (a->a->a) -> (a->a) -> a -> b -> a
pow' _ _ _ 0 = 1
pow' mul sq x' n' = f x' n' 1
where
f x n y
| n == 1 = x `mul` y
| r == 0 = f x2 q y
| otherwise = f x2 q (x `mul` y)
where
(q,r) = quotRem n 2
x2 = sq x
mulMod :: Integral a => a -> a -> a -> a
mulMod a b c = (b * c) `mod` a
squareMod :: Integral a => a -> a -> a
squareMod a b = (b * b) `rem` a
-- (eq. to) powMod m n k = n^k `mod` m
powMod :: Integral a => a -> a -> a -> a
powMod m = pow' (mulMod m) (squareMod m)
-- simple for small primes
primes :: [Integer]
primes = 2:3:primes' where
1:p:candidates = [6*k+r | k <- [0..], r <- [1,5]]
primes' = p : filter isPrime candidates
isPrime n = all (not . divides n)
$ takeWhile (\p -> p*p <= n) primes'
divides n p = n `mod` p == 0
isPrime :: Integer -> Bool
isPrime n | n < 2 = False
| otherwise = f primes where
f (p:ps) | p*p <= n = if n `rem` p == 0 then False else f ps
| otherwise = True
main = do
print . head $ filter isFragile (primesFrom $ 10^1000)