본문 바로가기
Tech/Coding

토글 코드 트릭

by redcubes 2025. 4. 29.

솔브닥 스트릭을 연명하기 위해 문자열 브론즈 문제를 풀다가 고안한 토글 코드를 살펴보고 활용법을 이야기해 보겠다.

신용카드 판별

시간 제한 메모리 제한
1 초 128 MB

문제

신용카드는 총 16자리의 숫자로 구성되어 있다. 언뜻 보기에는 무작위로 된 숫자로 구성되어 있는 것 같이 보이지만 그 속에는 하나의 수학적 비밀이 숨겨져 있다. 그중 하나가 카드 번호가 유효 한지 유효하지 않은 지 검사하는 Luhn 공식이다. 그 공식은 다음과 같다.

1. 신용카드의 16자리 숫자에서 맨 우측 수부터 세어 홀수 번째 수는 그대로 두고, 짝수 번째 수를 2배로 만든다.
2. 2배로 만든 짝수 번째 수가 10 이상인 경우, 각 자리의 숫자를 더하고 그 수로 대체한다.
3. 이와 같이 얻은 모든 자리의 수를 더한다.
4. 그 합이 10으로 나뉘면 "정당한 번호"(유효)이고 그렇지 않으면 "부당한 번호"(유효하지 않음)로 판정된다.

다음 공식을 이용해 주어진 신용카드의 번호가 유효한지, 유효하지 않은 지 판단해라.

입력

첫째 줄에 테스트 케이스의 수 T(1 ≤ T ≤ 1000)이 주어진다.
그 다음 줄부터 테스트 케이스에 해당하는 신용카드 번호가 주어진다.

출력

신용카드의 번호가 유효하면 "T", 유효하지 않으면 "F"를 한 줄 씩 출력한다.

예제 입력/출력

예제 입력 1

3
2720992711828767
3444063910462763
6011733895106094

예제 출력 1

T
F
T

출처

University > 중앙대학교 > 중앙대학교 프로그래밍 경진대회 (CPC) > 2017 중앙대학교 프로그래밍 경진대회 (CPC) A번


우선 내가 이 아이디어를 떠올리기 전의 방법으로 그냥 짠다면 이렇게 짰을 것이다.

n,*s=open(0,'rb').read().split()
for c in map(bytearray,s):
    tot=0
    count=1
    while c:
        x=c.pop()-48
        tot+=sum(divmod(x*(2-(count&1)),10))
        count+=1
    print('F' if tot%10 else 'T')

2-(count&1)를 이용해서 현재 몇 번째 자리수인지 세면서 홀짝여부로 가중치를 조절한다.

좀 더 가독성 있는 코드를 제시하자면

# stdin에서 입력을 읽고 바이트 배열 리스트로 분할
n, *s = open(0, 'rb').read().split()

# 각 바이트 배열 처리
for c in map(bytearray, s):
    tot = 0
    count = 1
    
    # 바이트 배열의 각 숫자를 오른쪽에서 왼쪽으로 처리
    while c:
        # 바이트를 정수로 변환 ('0'의 ASCII 값 빼기)
        x = c.pop() - 48
        
        # Luhn 알고리즘 가중치 적용 (위치가 홀수면 2를 곱함)
        if count % 2 == 1:  # 홀수 위치
            weight = 2
        else:  # 짝수 위치
            weight = 1
            
        weighted_value = x * weight
        
        # 가중치가 적용된 값의 자릿수 합계 (10 이상일 경우 divmod 사용)
        digits_sum = sum(divmod(weighted_value, 10))
        tot += digits_sum
        
        count += 1
    
    # 합계가 10으로 나누어 떨어지면 'T', 아니면 'F' 출력
    print('F' if tot % 10 else 'T')

이 경우 별도의 카운트 변수를 사용해야 하고 홀 짝 판별을 하게 된다.

그런데 아래와 같은 수식을 쓰면 홀수번째와 짝수번째에 번갈아가면서 mul변수의 값을 1과 2로 만들 수 있다.

n,*s=open(0,'rb').read().split()
mul=2
for c in map(bytearray,s):
    tot=0
    while c:
        mul=3-mul
        x=c.pop()-48
        tot+=sum(divmod(x*mul,10))
    print('F' if tot%10 else 'T')

관찰

x의 값은 x초기값과 n의 차이 사이에서 토글된다. n이x보다 작아도 성립한다.

0,1 토글은 xor로도 할 수 있다.

 


활용

r = bytearray()
for i in range(10):
    if i % 2 == 0:
        r.append(ord('B'))  # 짝수 번째는 'B'
    else:
        r.append(ord('W'))  # 홀수 번째는 'W'
open(1,'wb').write(r)

위 코드를 아래와 같이 만들 수 있다.

r = bytearray()
c = 66
for i in range(10):
    c = 153 - c
    r.append(c)  # 짝수 번째는 'B'
open(1,'wb').write(r)

결과는 똑같다.

BWBWBWBWBW

상태 반전도 가능하다.

import os
r = list(map(bytearray,(b'WBBBBBBBBW' for _ in range(10))))
os.write(1,b'before\n\n')

for c in r:
    os.write(1,c+b'\n')
for i in range(10):
    for j in range(10):
        r[i][j] = 153 - r[i][j]
os.write(1,b'\nafter\n\n')
for c in r:
    os.write(1,c+b'\n')

 

before

WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW
WBBBBBBBBW

after

BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB
BWWWWWWWWB

https://giphy.com/explore/on-off-switch

https://www.acmicpc.net/problem/12813

def s():
    res=[bytearray() for _ in range(5)]
    for a,b in zip(*open(0,'rb').read().split()):
        res[0].append(a&b)
        res[1].append(a|b)
        res[2].append((a^b)+48)
        res[3].append(97-a)
        res[4].append(97-b)
    open(1,'wb').write(b'\n'.join(res))
s()

'Tech > Coding' 카테고리의 다른 글

29768-펠린드롬 이름  (0) 2025.05.03
출력 버퍼  (0) 2025.04.29
위상 정렬 (Topological Sort)  (0) 2025.04.19
파이썬 heapq.heapreplace 동작 원리  (0) 2025.04.12
파이썬 heapq : 힙큐 사용법 정리  (0) 2025.04.11