39 바이트 얻기
이것은 Dennis와 JonathanFrech 가 별도로 찾은 39 바이트 솔루션을 얻는 방법에 대한 설명입니다 . 또는 오히려, 그것은 내 실제 경로보다 훨씬 더 좋은 방법으로 어떻게 뒷받침으로 대답에 도달 할 수 있는지 설명합니다.
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
약간 덜 골퍼하고 더 많은 양의 스패닝으로 작성하면 다음과 같습니다.
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
비트 패리티
우리는 내에서 아이디어로 시작하는 47 바이트 솔루션 출력 형태의 모든 숫자 까지 계산 하고 하나의도의 전체 수를 만드는 패리티 비트이다.n=2*k+b
k
0,1,...,399
b
의 작성하자 par(x)
에 대한 비트 패리티 의 x
배타적 논리합 (이다 ^
)의 모든 비트를 x
. 짝수의 1 비트가 있으면 0이고 (숫자는 사악함) 홀수의 1 비트가 있으면 1입니다. 들어 n=2*k+b
우리가 가진, par(n) = par(k)^b
그래서 악을 달성하기 위해 par(n)==0
우리가 필요로하는을 b=par(k)
의 마지막 비트 즉, n
앞의 비트의 비트 패리티가 될 수 있습니다.
골프에서 나의 첫번째 노력은 표현에 있었다 par(k)
, 처음으로 직접시 와 bin(k).count('1')%2
함께 다음과 비트 조작 .
패리티 업데이트
그럼에도 불구하고 짧은 표현은 없었습니다. 대신 작업 할 정보가 더 많다는 것을 인식하는 데 도움이되었습니다. 현재 숫자의 비트 패리티를 계산하는 대신
k ----> par(k)
우리가 증가로 우리는 비트 패리티를 업데이트 할 수 있습니다 k
에 k+1
.
k ----> par(k)
|
v
k+1 ----> par(k+1)
즉, 카운트 업 k=0,1,2,...
하기 때문에 매번 처음부터 계산하지 않고 현재 비트 패리티를 유지하면됩니다. 비트 패리티 업데이트 par(k+1)^par(k)
에서가 뒤집혀 비트 수이다 패리티 k
에 k+1
해당이다 par((k+1)^k)
.
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
형태 (k+1)^k
이제 계산해야합니다 par((k+1)^k)
. 계산 비트 패리티는 우리가 해결하려는 문제이기 때문에 우리가 아무데도없는 것처럼 보일 수 있습니다. 그러나 숫자 는 2의 거듭 제곱보다 1이 적은 (k+1)^k
것으로 표현되며 숫자는 비트 핵에서1,3,7,15,..
종종 사용됩니다 . 왜 그런지 보자.
우리가 증가 할 때 k
, 이진 캐리의 효과는 마지막 0
과 모든 1
것을 오른쪽 으로 뒤집는 것 0
입니다. 예를 들어k=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
캐리를 발생시키는 열은로 표시되어 *
있습니다. 이것은 a로 1
변경하고의 0
캐리 비트를 전달합니다.이 비트 1
는 0
in k
에 도달 할 때까지 왼쪽으로 전파 되고로 변경됩니다 1
. 더 왼쪽에있는 비트는 영향을받지 않습니다. 그래서, k^(k+1)
비트 위치를 확인 변경 k
에 k+1
, 그것은 가장 오른쪽의 위치를 발견 0
하고 1
그 오른쪽에의합니다. 즉, 변경된 비트는 접미사를 형성하므로 결과는 0 다음에 하나 이상의 1이옵니다. 선행 0이 없으면 1, 11, 111, 1111, ...
2의 거듭 제곱보다 작은 이진수가 있습니다 .
컴퓨팅 par((k+1)^k)
이제 (k+1)^k
로 제한됨을 이해 1,3,7,15,...
했으므로 이러한 숫자의 비트 패리티를 계산하는 방법을 찾으십시오. 여기에, 유용한 사실은 즉 1,2,4,8,16,...
다른 모듈 3
사이 1
와 2
, 이후 2==-1 mod 3
. 따라서 1,3,7,15,31,63...
모듈로를 3
사용하면 1,0,1,0,1,0...
비트 패리티가됩니다. 완전한!
따라서 업데이트를 다음 par(k+1) = par(k) ^ par((k+1)^k)
과 같이 수행 할 수 있습니다.
par(k+1) = par(k) ^ ((k+1)^k)%3
b
패리티를 저장하는 변수로 사용 하면 다음과 같습니다.
b^=((k+1)^k)%3
코드 작성
코드에서 이것을 함께 퍼팅, 우리는 시작 k
과 패리티 비트 b
에 모두 0
다음 반복적으로 인쇄, n=2*k+b
업데이트 b=b^((k+1)^k)%3
및 k=k+1
.
46 바이트
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
온라인으로 사용해보십시오!
우리는 주위에 괄호를 제거 k+1
에 ((k+1)^k)%3
있기 때문에 파이썬의 우선 순위는 첫째, 어쨌든 보이는 이상한로 추가한다.
코드 개선
단일 변수로 직접 작업하고 직접 n=2*k+b
업데이트를 수행하면 더 잘할 수 있습니다 . 에 k+=1
해당합니다 n+=2
. 그리고 업데이트는에 b^=(k+1^k)%3
해당합니다 n^=(k+1^k)%3
. 여기서 k=n/2
업데이트하기 전에 n
.
44 바이트
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
온라인으로 사용해보십시오!
우리는 다시 작성하여 단축 할 수 있습니다 n/2+1^n/2
(이것을 기억하십시오 (n/2+1)^n/2
)
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
/2
마지막 비트를 제거 하므로 xoring 전이나 후에 비트를 제거해도 문제가되지 않습니다. 그래서 우리는 있습니다 n^=(n+2^n)/2%3
. 우리는 모듈이 있음을 지적하여 다른 바이트를 저장할 수 있습니다 3
, /2
에 해당 *2
에 해당 -
즉 지적, n+2^n
분할은 바닥없이 실제 반감이도 그래서입니다. 이것은 준다n^=-(n+2^n)%3
41 바이트
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
온라인으로 사용해보십시오!
마지막으로, 우리는 작업을 결합 할 수 있습니다 n^=c;n+=2
로 n=(n+2)^c
, 여기서 c
조금이다. 이것은 ^c
마지막 비트에서만 작동 하고 마지막 비트 +2
는 신경 쓰지 않기 때문에 작동하므로 작업이 출퇴근합니다. 다시, 우선 순위는 parens를 생략하고 씁니다 n=n+2^c
.
39 바이트
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
온라인으로 사용해보십시오!