python https://www.algospot.com/judge/problem/read/DECUAL

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python https://www.algospot.com/judge/problem/read/DECUAL相关的知识,希望对你有一定的参考价值。

# -*- coding: utf-8 -*-

# 정수 문자열 찾아줌
# => (처음 non-digit가 나타난 index, 구한 정수값)
def find_digits(s):
    for i in xrange(len(s)):
        if s[i] < '0' or s[i] > '9':
            return (i, int(s[:i]))
    return (i+1, int(s))

# parser generator
# 파싱된 토큰을 순차적으로 반환하는 iterator 함수 반환
def generate_parser(s):
    # 문자열 내 현재 위치
    i = 0
    l = len(s)
    # 토큰 시작 위치, 토큰 끝 위치
    p1 = p2 = 0
    # 토큰 문자열
    tok = ""
    while(i<l):
        # '(' 를 찾을 때까지 건너뜀
        if s[i] != '(':
            i += 1
            continue
        # '(' 이전의 문자열을 tok에 붙여줌
        if p1 != i: tok += s[p1:i]
        # '(mmm)^n' 패턴을 찾아서 토큰으로 만들어줌
        p1 = i+1
        p2 = s[p1:].index(')')
        idx, cnt = find_digits(s[p1+p2+2:])
        # 이 때 반복수가 1 이거나 확장된 길이가 100 이하이면 기존 토큰에 이어 붙임
        if (cnt == 1) or (p2*cnt <= 100):
        #if cnt <= 3:
            tok += s[p1:p1+p2]*cnt
        # 이제 토큰을 반환할 때가 되었다!
        else:
            # 우선 기존에 모으고 있던 토큰을 먼저 반환하고
            if len(tok): yield (tok, 1)
            tok = ""
            # 반복수가 1보다 큰 다음 토큰도 이어서 반환함
            yield (s[p1:p1+p2], cnt)
        # 토큰 시작 위치 재조정
        p1 = i = p1+p2+idx+2
    # 문자열 파싱은 끝났지만 아직 반환 안 한 토큰이 남아 있다면 마지막으로 반환해줌
    if p1 < i: tok += s[p1:i]
    if len(tok): yield (tok, 1)

# 주어진 문자열을 파싱하여 (token, count) 원소를 가지는 배열과 최종 문자열 길이 반환
# 예제: ABC(ABC)^99999997(ABC)^1ABCAA
#    => ([('ABC', 1), ('ABC', 99999997), ('ABCABCAA', 1)], 300000002)
def parse_str(s):
    Q = []
    tlen = 0
    for g in generate_parser(s):
        Q.append(g)
        tlen += len(g[0])*g[1]
    return (Q, tlen)

# 큐의 첫 번째 토큰이 l보다 짧은 경우 사용
# 주어진 길이의 토큰을 만들기 위해 반복수를 줄이고 그래도 안 되면 다음 토큰을 확장하게 됨
# 반환값: 길이 l의 토큰, 만약 큐에 남은 토큰이 더 이상 없으면 현재까지 구한 토큰 반환
def borrow_next_token(l, Q):
    if len(Q) == 0: return ""
    s, c = Q.pop(0)
    sl = len(s)
    # 결과 토큰, 채워야 할 길이, 빌려 쓰는 토큰의 남은 반복수
    ts, tl, tc = s, l-sl, c-1
    # 채워야 할 길이가 남아 있거나 빌려 쓰는 토큰의 반복수가 남아 있는 동안
    while tl > 0 and tc > 0:
        ts, tl, tc = ts+s, tl-sl, tc-1
    # 길이 l인 토큰이 만들어졌다면
    if tl == 0:
        # 토큰의 반복수가 남아 있다면 큐에 다시 넣어줌
        if tc > 0: Q.insert(0, (s, tc))
        return ts
    # 여전히 l보다 짧다면
    if tl > 0:
        # 다음 토큰에서 더 빌려오자! 빚쟁이가 되고 있다!
        return ts + borrow_next_token(tl, Q)
    # 결과 토큰이 l보다 길어졌다면
    else:
        # 결과 토큰의 남은 부분을 빌려 쓰는 토큰 앞에 결합하고 반복수를 재조정
        # A(RUN)^50 에 l=2를 적용하면 => AR, (UNR)^49UN
        ts1, ts2 = ts[:tl], ts[tl:]
        if len(ts2): Q.insert(0, (ts2, 1))
        if tc > 0: Q.insert(0, (ts2+s[:tl], tc))
        return ts1

# 큐의 첫 번째 토큰의 길이가 l이 되도록 재조정
def resize_token(l, Q):
    # 첫 번째 토큰 길이가 이미 l이면 더 볼 것 없음
    if len(Q[0][0]) == l: return
    s, c = Q.pop(0)
    sl = len(s)
    # 토큰의 길이가 l보다 크면
    if sl > l and c == 1:
        # 두 개의 토큰으로 쪼개어 큐에 다시 넣음
        Q.insert(0, (s[l:], 1))
        Q.insert(0, (s[:l], 1))
        return
    d, m = divmod(l, sl)
    if m: d += 1
    # 토큰의 반복수를 다 쓰고도 길이가 l보다 짧으면
    if d > c:
        s1 = s*c
        # 다음 토큰에서 모자란 길이를 보충
        s2 = borrow_next_token(l-len(s1), Q)
        if len(s2) == 0: return
        s1 += s2
        Q.insert(0, (s1, 1))
    # 토큰의 반복수를 적용해서 길이가 l보다 길어지면
    else:
       #  남은 반복수만큼 큐에 넣고
        if c-d > 0: Q.insert(0, (s, c-d))
        # 길이가 l 이상이 된 토큰을 큐에 넣음
        Q.insert(0, (s*d, 1))
    # 아직 첫 번째 토큰의 길이가 l이 되지 않았으므로 이 과정을 반복함
    resize_token(l, Q)

def check_multiple(Q1, Q2):
    # Q1에 들어 있는 첫 번째 토큰이 긴 것이 되도록 위치 교환
    if len(Q1[0][0]) < len(Q2[0][0]):
        Q1, Q2 = Q2, Q1
    s1, c1 = Q1[0]
    s2, c2 = Q2[0]
    l1, l2 = len(s1), len(s2)
    # 긴 토큰의 길이가 짧은 토큰 길이의 배수인지 확인
    d, m = divmod(l1, l2)
    if m: return False
    # 짧은 토큰을 반복하여 긴 토큰과 같다면
    if s1 == (s2*d):
        # 긴 토큰을 큐에서 빼내고 짧은 토큰의 반복수를 d배 하여 큐 앞 쪽에 다시 넣음
        Q1.pop(0)
        Q1.insert(0, (s2, c1*d))
        return True
    return False

def compare_sub(Q1, Q2):
    # 큐가 둘 다 비었으면 True, 하나만 비었으면 False
    if len(Q1) == 0:
        if len(Q2) == 0: return True
        else: return False
    s1, c1 = Q1[0]
    s2, c2 = Q2[0]
    l1, l2 = len(s1), len(s2)
    # 각 큐의 첫 번째 토큰의 길이가 같으면
    if l1 == l2:
        # 두 토큰이 같다면, 토큰 반복 개수를 감하고, 남은 쪽은 다시 큐에 넣어줌
        if s1 == s2:
            Q1.pop(0)
            Q2.pop(0)
            if c1 > c2: Q1.insert(0, (s1, c1-c2))
            elif c1 < c2: Q2.insert(0, (s2, (c2-c1)))
            # 이번 토큰은 무사 통과
            return True
        # 토큰 길이가 같은데 문자열이 다르다면 더 볼 것 없음
        else: return False
    # 두 토큰의 길이가 다르면
    else:
        # 긴 토큰이 짧은 토큰의 반복 패턴인지 체크
        if not check_multiple(Q1, Q2):
            # 반복 패턴이 아니라면 짧은 토큰의 길이를 늘여줌
            if l1 > l2: resize_token(l1, Q2)
            else: resize_token(l2, Q1)
        # 그리고 다시 비교
        return compare_sub(Q1, Q2)

def compare(S1, S2):
    # 문자열 그 자체를 비교
    if S1 == S2: return True
    # 문자열 파싱한 결과와 최종 길이 구함
    # ABC(ABC)^99999997(ABC)^1ABCAA
    # => 길이        : 300000002
    # => 파싱 결과 큐: [('ABC', 1), ('ABC', 99999997), ('ABCABCAA', 1)]
    Q1, L1 = parse_str(S1.strip())
    Q2, L2 = parse_str(S2.strip())
    # 길이가 다르면 더 볼 것 없음
    if L1 != L2: return False
    # 큐에 토큰이 남아 있는 동안 계속 비교
    while(len(Q1) and len(Q2)):
        if not compare_sub(Q1, Q2):
            return False
    # 두 큐 중 하나라도 토큰이 남아 있으면 두 문자열은 다른 거임
    if len(Q1) or len(Q2):
        return False
    return True


if __name__=="__main__":
    ANS = {True:"YES", False:"NO"}
    T = input()
    for _ in xrange(T):
        print ANS[compare(raw_input(), raw_input())]

以上是关于python https://www.algospot.com/judge/problem/read/DECUAL的主要内容,如果未能解决你的问题,请参考以下文章

Python代写,Python作业代写,代写Python,代做Python

Python开发

Python,python,python

Python 介绍

Python学习之认识python

python初识