문제 출처

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

 

문제

어떤 자연수 N이 있을 때, 그 자연수 N의 분해합은 N과 N을 이루는 각 자리수의 합을 의미한다. 어떤 자연수 M의 분해합이 N인 경우, M을 N의 생성자라 한다. 예를 들어, 245의 분해합은 256(=245+2+4+5)이 된다. 따라서 245는 256의 생성자가 된다. 물론, 어떤 자연수의 경우에는 생성자가 없을 수도 있다. 반대로, 생성자가 여러 개인 자연수도 있을 수 있다.

자연수 N이 주어졌을 때, N의 가장 작은 생성자를 구해내는 프로그램을 작성하시오.

 

1차 풀이

N = int(input())

len_n = len(f"{N}")
start = N-9*len_n

if start <= 0:
    start = 1

for i in range(start, N):
    if i == N-1:
        print(0)
    else:
        digit_sum = sum(int(digit) for digit in f"{i}")
        if i + digit_sum == N:
            print(i)
            break

 

N의 생성자의 하한을 어느정도 잡아준다.

해당 하한부터 Brutal하게 모든 경우를 check하며 올라간다.

근데 98%에서 틀렸다.

 

 

수정 풀이

예외처리 및 for-loop의 범위를 조정하였다.

N = int(input())

len_n = len(f"{N}")
start = N-9*len_n

if start <= 0:
    start = 1

for i in range(start, N+1):
    if N == 1:
        print(0)
        break
    if i == N:
        print(0)
    else:
        digit_sum = sum(int(digit) for digit in f"{i}")
        if i + digit_sum == N:
            print(i)
            break

 

'알고리즘 & PS > 백준' 카테고리의 다른 글

[백준] 1260번 DFS와 BFS  (0) 2024.10.04
[백준] 12865번 평범한 배낭 (DP)  (1) 2024.10.04
[백준] 5430번 AC  (0) 2023.12.09

문제 출처

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

 

5430번: AC

각 테스트 케이스에 대해서, 입력으로 주어진 정수 배열에 함수를 수행한 결과를 출력한다. 만약, 에러가 발생한 경우에는 error를 출력한다.

www.acmicpc.net

 

문제

선영이는 주말에 할 일이 없어서 새로운 언어 AC를 만들었다. AC는 정수 배열에 연산을 하기 위해 만든 언어이다. 이 언어에는 두 가지 함수 R(뒤집기)과 D(버리기)가 있다.

함수 R은 배열에 있는 수의 순서를 뒤집는 함수이고, D는 첫 번째 수를 버리는 함수이다. 배열이 비어있는데 D를 사용한 경우에는 에러가 발생한다.

함수는 조합해서 한 번에 사용할 수 있다. 예를 들어, "AB"는 A를 수행한 다음에 바로 이어서 B를 수행하는 함수이다. 예를 들어, "RDD"는 배열을 뒤집은 다음 처음 두 수를 버리는 함수이다.

배열의 초기값과 수행할 함수가 주어졌을 때, 최종 결과를 구하는 프로그램을 작성하시오.

 

1차 풀이

테스트용 및 1차 작성 답안

import sys
input = sys.stdin.readline

T = int(input()) # # of Test Case 받아주고

for _ in range(T):
    function_list = list(input())  #input은 str로 받아지니 list만 씌워도 각 element로 분해, 혹시 모르니 input -> str로 확실히 변환
    list_len = int(input())  # 사실 쓸모없긴한데 주니 일단 받자
    number_list = eval(input())

    for i in function_list:
        print(number_list)
        print(i)
        if i == 'R':
            number_list = list(reversed(number_list))
            print('Im R')
        elif i == 'D':
            print('Im D')
            if len(number_list) == 0:  #list의 empty 판정으로 인한 에러를 bool을 이용하거나 try구문을 이용해도 될 듯
                print("error")
                break
            else:
                number_list.pop(0)
    print(number_list)

 

python에서는 input()을 받았을 때, string type으로 받아지므로 해당 값을 list, 혹은 integer로 명시적 변환

 

eval 함수

python의 built-in 함수이며 정말 편리하지만, 위험한 함수.

대부분의 구분을 분석하여 자동적으로 처리해주는 유연한 함수이지만 그만큼 python 자체적인 해석에 의존함으로

strip과 같은 방식으로 처리하여주는 것이 더 안전하긴 함.

 

 

위 코드는 "시간 초과" 발생

 

시간 초과의 발생 가능성이 있는 항목은

  • input
  • list를 reverse 하는 과정

등 이 있지만

해당 코드에서는 input 대신 sys.stdin.readline을 사용하였기에 input에서의 시간 초과라고 보기 힘듦.

'list를 reverse 하는 과정'에서 시간 초과가 발생했다면 해당 과정을 최소화 하는 방향으로 다시 짜보자.

 

 

보완 방향

1. RR이 짝수개 나온 경우 원래의 순서 그대로임으로 해당 작업 미 실행

2. function_list의 구문을 해석하여 원래의 number_list에서 양쪽 끝에서 각 x, y개 제거 및 reverse 작업 0회 or 1회 실행

 

순서대로 해보자.

 

1의 방법을 구현하던 도중 iteration을 도는 과정에서 RR의 짝수개를 처리하는 것이 아닌, function_list 자체에 대해 먼저 정리를 해두고 refine된 function_list를 돌리는 것이 더 효율적이라 판단.

 

 

보완코드

def refine_func(fun_list):
    for i in range(len(fun_list)-1):
        if fun_list[i] == 'P':
            continue
        if fun_list[i] != 'R':
            continue
        elif fun_list[i] == 'R':
            if fun_list[i+1] == 'R':
                fun_list[i]='P'
                fun_list[i+1]='P'
                continue
        else:
            print("?")
            

#뒤쪽의 main for-loop내의 코드 변환
for i in function_list:
        if i == 'P':
            continue
        if i == 'R':
            number_list = list(reversed(number_list))
        elif i == 'D':
            if len(number_list) == 0:  #list의 empty 판정으로 인한 에러를 bool을 이용하거나 try구문을 이용해도 될 듯 ?
                print("error")
                break
            else:
                number_list.pop(0)

 

해당 함수는 function_list를 받았을 때, 짝수개의 연속된 R에 대해서는 P로 변환한다.

R자체를 제거하면 좋긴하지만, iteration에서 list의 index를 참조하기에 삭제하는 방향으로는 힘들 것 같았다.

 

다만, 위 보완코드를 사용한 답안 또한 시간 초과

 

 

2번 방법

Reverse를 0번 혹은 1번만 실행하며 list의 좌, 우측에서 각각 몇번 pop 해야하는지 구한 후 실행

 

 

2차 수정 풀이

#최종 5430

import sys
input = sys.stdin.readline

def refine_func(fun_list):
    for i in range(len(fun_list)-1):
        if fun_list[i] == 'P':
            continue
        if fun_list[i] != 'R':
            continue
        elif fun_list[i] == 'R':
            if fun_list[i+1] == 'R':
                fun_list[i]='P'
                fun_list[i+1]='P'
                continue

T = int(input()) # # of Test Case 받아주고

for _ in range(T):
    function_list = list(input())  #input은 str로 받아지니 list만 씌워도 각 element로 분해, 혹시 모르니 input -> str로 확실히 변환
    list_len = int(input())  # 사실 쓸모없긴한데 주니 일단 받자
    number_list = eval(input())

    refine_func(function_list)

    check_li = [0,0]
    reverse_cnt = 0
    del_cnt = 0
    
    for command in function_list:
        if command == 'P':
            continue
        elif command == 'R':
            check_li.reverse()
            reverse_cnt += 1
        elif command == 'D':
            check_li[0] += 1
            del_cnt += 1

    if del_cnt > list_len:
        print("error")
        continue

    if reverse_cnt%2 ==0:
        pass
    elif reverse_cnt%2 ==1:
        check_li.reverse()
        left_del, right_del = check_li[0], check_li[1]
        for _ in range(right_del):
            del number_list[-1]
        for _ in range(left_del):
            del number_list[0]

    print(number_list)

 

이번엔 출력 초과 발생. 또한 16%에서 걸리는 거 보니 해당 test case에 뭐가 있는 듯.

 

 

 

 

 

 

 

 

'알고리즘 & PS > 백준' 카테고리의 다른 글

[백준] 1260번 DFS와 BFS  (0) 2024.10.04
[백준] 12865번 평범한 배낭 (DP)  (1) 2024.10.04
[백준] 2231번 분해합  (0) 2023.12.10

 

from mpl_toolkits.mplot3d.axes3d import get_test_data

X, Y, Z = get_test_data(0.5)

print(f"X.shape={X.shape}")
print(f"Y.shape={Y.shape}")
print(f"Z.shape={Z.shape}")

 

출력 결과

X.shape=(12, 12)
Y.shape=(12, 12)
Z.shape=(12, 12)

 

 

import matplotlib.pyplot as plt

fig, axs = plt.subplots(ncols=3, figsize=(10, 4), subplot_kw={"projection":"3d"}, constrained_layout=True)

for ax, d in zip(axs, [1, 0.5, 0.1]):
    X, Y, Z = get_test_data(d)
    dim = X.shape[0]
    ax.plot_wireframe(X, Y, Z)
    ax.set_title(f"get_test_data({d}): {dim}x{dim}", fontsize="x-large", color="gray", fontweight="bold")

 

 

 

 

 

 

 

 

 

 

 

 

 

참고

 

https://matplotlib.org/stable/plot_types/3D/wire3d_simple.html#sphx-glr-plot-types-3d-wire3d-simple-py

 

plot_wireframe(X, Y, Z) — Matplotlib 3.8.2 documentation

plot_wireframe(X, Y, Z) See plot_wireframe. import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import axes3d plt.style.use('_mpl-gallery') # Make data X, Y, Z = axes3d.get_test_data(0.05) # Plot fig, ax = plt.subplots(subplot_kw={"projection": "3d"}

matplotlib.org

 

https://jehyunlee.github.io/2021/07/09/Python-DS-79-mpl3d/

 

Matplotlib 3D Plots (1)

Matplotlib으로 3D Plot을 할 수 있습니다. 많은 분들이 알고 있는 사실이지만 적극적으로 쓰이지 않습니다. 막상 쓰려면 너무 낯설기도 하고 잘 모르기도 하기 때문입니다. Reference matplotlib tutorial: The

jehyunlee.github.io

 

'Data > Visualization' 카테고리의 다른 글

[Matplotlib] plot  (0) 2023.12.17

0. 참고 공식 문서

https://cloud.google.com/bigquery/docs/reference/standard-sql/geography_functions

 

Geography functions  |  BigQuery  |  Google Cloud

GoogleSQL for BigQuery supports geography functions. Geography functions operate on or generate GoogleSQL GEOGRAPHY values. The signature of most geography functions starts with ST_. GoogleSQL for BigQuery supports the following functions that can be used

cloud.google.com

GoogleSQL for BigQuery supports geography functions. Geography functions operate on or generate GoogleSQL GEOGRAPHY values. The signature of most geography functions starts with ST_. GoogleSQL for BigQuery supports the following functions that can be used to analyze geographical data, determine spatial relationships between geographical features, and construct or manipulate GEOGRAPHYs.

 

 

1. ST_GEOPOINT 함수

ST_GEOPOINT 함수는 위도(latitude)와 경도(longitude) 값을 입력받아 지리적 좌표(Geography point)를 반환하는 함수.

이 함수는 위도와 경도를 사용하여 특정 지리적 지점을 정의할 때 유용합니다.

 

ST_GEOPOINT(longitude, latitude)

 

  • longitude: 경도 값. (-180 ~ 180 사이의 값), latitude: 위도 값. (-90 ~ 90 사이의 값)

이 함수는 경도(longitude)가 첫 번째 인자로, 위도(latitude)가 두 번째 인자로 들어간다는 점에 유의해야 합니다. 반환값은 Geography 타입입니다.

 

예시

SELECT ST_GEOPOINT(-122.4194, 37.7749) AS geopoint;

 

결과

POINT(-122.4194 37.7749)

 

 

2. ST_DISTANCE 함수

ST_DISTANCE 함수는 두 지리적 좌표(Geography objects) 사이의 거리를 계산해 줌.

이 함수는 미터 단위로 두 점 사이의 최단 거리를 반환하며, 구면 지구 모델을 사용하여 거리를 계산합니다. 이는 지리적 분석에서 두 위치 간의 물리적 거리를 구할 때 유용합니다.

ST_DISTANCE(geography1, geography2)

 

 

  • geography1: 첫 번째 지리적 좌표 (Geography 타입), geography2: 두 번째 지리적 좌표 (Geography 타입).

 

예시: 샌프란시스코와 뉴욕 사이의 거리를 계산

SELECT ST_DISTANCE(
  ST_GEOPOINT(-122.4194, 37.7749),  -- San Francisco
  ST_GEOPOINT(-74.0060, 40.7128)    -- New York
) AS distance;

 

결과: 

4130107.673 meters (약 4,130km)

 

3. ST_DISTANCE와 ST_GEOPOINT를 함께 사용하는 경우

WITH cities AS (
  SELECT 'San Francisco' AS city, ST_GEOPOINT(-122.4194, 37.7749) AS location UNION ALL
  SELECT 'New York' AS city, ST_GEOPOINT(-74.0060, 40.7128) AS location UNION ALL
  SELECT 'Los Angeles' AS city, ST_GEOPOINT(-118.2437, 34.0522) AS location
)
SELECT city, ST_DISTANCE(ST_GEOPOINT(-123.1207, 49.2827), location) AS distance
FROM cities
ORDER BY distance ASC
LIMIT 1;

위 쿼리는 캐나다 벤쿠버(경도 -123.1207, 위도 49.2827)와 가장 가까운 도시를 찾음.

 

결과:

Los Angeles (약 1734km)

 

 

4. 기타 같이 사용하면 좋을 것

1. Geolite mmdb

https://github.com/P3TERX/GeoLite.mmdb

 

GitHub - P3TERX/GeoLite.mmdb: MaxMind's GeoIP2 GeoLite2 Country, City, and ASN databases

MaxMind's GeoIP2 GeoLite2 Country, City, and ASN databases - P3TERX/GeoLite.mmdb

github.com

이전에 python 라이브러리들을 통해서 몇가지 처리를 하려하였지만 open api들에 대해선 request limit이 걸려 다음과 같은 mmdb를 사용.

 

 

2. GeoPandas

import geopandas as gpd
from shapely.geometry import Point

data = {'City': ['San Francisco', 'New York'],
        'Latitude': [37.7749, 40.7128],
        'Longitude': [-122.4194, -74.0060]}
gdf = gpd.GeoDataFrame(data, geometry=gpd.points_from_xy(data['Longitude'], data['Latitude']))


print(gdf)

결과:

 

 

3. Geopy

from geopy.distance import geodesic

san_francisco = (37.7749, -122.4194)
new_york = (40.7128, -74.0060)

distance = geodesic(san_francisco, new_york).meters
print(f"Distance between San Francisco and New York: {distance} meters")

결과:

 

 

4. Folium (시각화)

import folium

m = folium.Map(location=[37.7749, -122.4194], zoom_start=12)

folium.Marker([37.7749, -122.4194], popup="San Francisco").add_to(m)
folium.Marker([40.7128, -74.0060], popup="New York").add_to(m)

m.save("map.html")  # 지도 저장

 

(로컬에 저장된 html 파일을 크롬으로 드래그 앤 드롭 하면 열린다.)

 

'Data > SQL' 카테고리의 다른 글

[BigQuery] DECLARE, SET  (0) 2023.11.29

AES(Advanced Encryption Standard)는 대칭 키 암호화 알고리즘으로, 데이터의 기밀성을 보장하기 위해 널리 사용됨.

이 중 AES-256은 256비트 키를 사용하여 가장 높은 수준의 보안을 제공합니다.

이번 글에서는 AES-256 CTR(카운터) 모드에 대해 설명하고, 이를 Python 코드로 구현.

AES-256 CTR 모드란?

CTR 모드는 AES의 여러 운영 모드 중 하나로, 암호화 및 복호화 과정에서 카운터 값을 사용합니다. 이 모드의 주요 장점은 병렬 처리가 가능하다는 것입니다. 이를 통해 성능을 크게 향상시킬 수 있습니다.

CTR 모드의 작동 방식은 다음과 같습니다:

  1. 초기화 벡터(IV)와 카운터를 결합하여 입력 블록을 생성합니다.
  2. 이 입력 블록을 AES 암호화 하여 암호화된 카운터 블록을 얻습니다.
  3. 이 블록을 평문 블록과 XOR 연산하여 암호문 블록을 생성합니다.
  4. 복호화 과정에서는 동일한 절차를 통해 암호문을 평문으로 변환합니다.

CTR 모드는 동일한 키와 IV를 사용하면 동일한 카운터 블록을 생성하기 때문에, 항상 서로 다른 IV를 사용하는 것이 중요합니다.

Python 코드 예제

다음은 Python을 사용하여 AES-256 CTR 모드 암호화를 구현하는 예제입니다. cryptography 라이브러리를 사용하여 쉽게 구현할 수 있습니다.

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
import os

# 암호화 함수
def encrypt_aes_256_ctr(key, plaintext):
    iv = os.urandom(16)  # IV는 16바이트 길이로 무작위 생성
    cipher = Cipher(algorithms.AES(key), modes.CTR(iv), backend=default_backend())
    encryptor = cipher.encryptor()
    
    # 패딩 추가 (옵션)
    padder = padding.PKCS7(algorithms.AES.block_size).padder()
    padded_data = padder.update(plaintext) + padder.finalize()
    
    ciphertext = encryptor.update(padded_data) + encryptor.finalize()
    return iv + ciphertext

# 복호화 함수
def decrypt_aes_256_ctr(key, ciphertext):
    iv = ciphertext[:16]  # IV는 암호문의 처음 16바이트
    actual_ciphertext = ciphertext[16:]
    cipher = Cipher(algorithms.AES(key), modes.CTR(iv), backend=default_backend())
    decryptor = cipher.decryptor()
    
    padded_plaintext = decryptor.update(actual_ciphertext) + decryptor.finalize()
    
    # 패딩 제거 (옵션)
    unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
    plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
    
    return plaintext

# 예제 사용
key = os.urandom(32)  # 256비트 키 생성
plaintext = b"This is a secret message."

# 암호화
ciphertext = encrypt_aes_256_ctr(key, plaintext)
print("Ciphertext:", ciphertext)

# 복호화
decrypted_text = decrypt_aes_256_ctr(key, ciphertext)
print("Decrypted text:", decrypted_text)
(ChatGPT,, Thank you)

코드 설명

  1. 키 생성: os.urandom(32)을 사용하여 256비트(32바이트) 키를 생성
  2. 암호화:
    • IV를 생성하고(os.urandom(16)), AES-256 CTR 모드로 암호화기를 초기화
    • 평문에 패딩을 추가하여 블록 크기를 맞춘 후 암호화
    • 최종 암호문은 IV와 암호문을 결합한 것
  3. 복호화:
    • 암호문에서 IV를 추출하고, AES-256 CTR 모드로 복호화기를 초기화
    • 복호화된 텍스트에서 패딩을 제거하여 원래의 평문을 얻
 
GCP BigQuery 공식 Documentation 링크
 
 
 
 

DECLARE


Description

지정된 유형의 변수를 선언.
DEFAULT 절이 지정된 경우 변수는 expression의 값으로 초기화되며, DEFAULT 절이 없으면 변수는 NULL 값으로 초기화됩니다.
 
 
 
Syntax
DECLARE variable_name[, ...] [variable_type] [DEFAULT expression];
 
 
Examples
DECLARE fromdate DATE DEFAULT '2014-01-01';  -- dates for after 2013
DECLARE todate DATE DEFAULT '2015-01-01';

SELECT FORMAT('From %t to %t', fromdate, todate);
 
이게 되는지 처음 알았다.
 
 

SET

 

Syntax

SET variable_name = expression;
SET (variable_name[, ...]) = (expression[, ...]);

 

 

 

Description

변수에 제공된 표현식의 값을 설정하거나 여러 변수를 여러 표현식의 결과를 기반으로 동시에 설정합니다.

SET 문은 다중 문장 쿼리 내에서 어디에서든 나타날 수 있습니다.

 

 

Examples

SET x = 5;
SET (a, b, c) = (1 + 3, 'foo', false);

'Data > SQL' 카테고리의 다른 글

[BigQuery] functions ST_DISTANCE, ST_GEOPOINT  (0) 2023.12.05

+ Recent posts