ABC 324 - D번 복기, 순열 다루는 테크닉 - 두 문자열이 서로의 순열일려면? -
1. 문제
D - Square Permutation (atcoder.jp)
D - Square Permutation
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
2. 풀이
주어진 정수 문자열의 순열이 어떤 정수의 제곱수가 될때, 그러한 순열의 개수를 구하는 문제.
길이 제한이 13이라고 해도 모든 순열을 찾고, 각 순열이 어떤 수의 제곱수인지 검사하면 매우 느리다
1) 만약 길이 N인 s의 순열이 X의 제곱수가 될려면, X는 아무리 커봐야 $\sqrt{10^{N}}$이다.
그러므로 0부터 $\sqrt{10^{N}}$까지 모든 정수 i에 대해 i의 제곱이 길이 N인 s의 순열이 될 수 있는지 체크해본다.
여기서 s의 순열을 모두 구하고 체크하는게 아니라, 어떤 두 문자열 s와 t가 서로의 순열이 될 수 있는지를 생각해본다.
2) 만약 s의 순열이 t가 된다는 뜻은, s와 t가 동일한 문자로 구성되어 있다는 뜻이다.
그러므로, 애초에 s를 정렬해두고 i의 제곱을 list로 바꾼 다음 정렬해서 두 리스트의 구성이 동일한지 체크하면 된다.
여기서 주의할 점은 주어진 정수 문자열 s에는 0이 들어가 있을 수 있는데, "0부터 $\sqrt{10^{N}}$까지 모든 정수 i"에는
0이 없으니까, s와 i의 제곱이 동일한 길이가 되도록 i의 제곱 리스트에 0을 넣어준다
n = int(input())
s = sorted(input())
count = 0
max_value = pow(10,n)
i = 0
while i*i < max_value:
t = list(str(i**2))
while len(s) != len(t):
t.append('0')
t.sort()
find = False
for j in range(len(s)):
if s[j] != t[j]:
find = True
break
if find == False:
count += 1
i += 1
print(count)
여기서 중요한 디테일이 있는데... for문으로 바꾸면 시간이 4초가 넘어서 시간초과가 난다
n = int(input())
s = sorted(input())
count = 0
for i in range(int((10**n)**(1/2))+1):
t = list(str(i**2))
while len(s) != len(t):
t.append('0')
t.sort()
find = False
for j in range(len(s)):
if s[j] != t[j]:
find = True
break
if find == False:
count += 1
print(count)
for문 range()가 배열 만들어서 while보다 느리겠다 생각했는데..
알고보니 len(t)가 시작부터 len(s)보다 큰 경우가 있어서.. 여기서 무한루프 일어나더라...
while len(s) != len(t):
t.append('0')
뒤에 int((10**n)**(1/2))로 고치면 시간은 비슷하더라...
근데 이러면 오답임... 확실히 int((10**n)**(1/2))+1까지는 해야돼.. 이게 루트 구하면서 오차가 있으니까
n = int(input())
s = sorted(input())
count = 0
for i in range(int((10**n)**(1/2))):
t = list(str(i**2))
while len(s) != len(t):
t.append('0')
t.sort()
find = False
for j in range(len(s)):
if s[j] != t[j]:
find = True
break
if find == False:
count += 1
print(count)
그래서 애초에 len(t)가 len(s)보다 크면 continue로 스킵
n = int(input())
s = sorted(input())
count = 0
for i in range(int((10**n)**(1/2))+1):
t = list(str(i**2))
if len(t) > len(s):
continue
while len(s) != len(t):
t.append('0')
t.sort()
find = False
for j in range(len(s)):
if s[j] != t[j]:
find = True
break
if find == False:
count += 1
print(count)
핵심은 두 문자열이 서로의 순열이라는 것은?
두 문자열의 구성이 서로 동일하다.
따라서 두 문자열을 정렬하면 동일한 문자열이 되어야한다.
'경쟁 프로그래밍 > Atcoder' 카테고리의 다른 글
ABC 328 C번 복기 - 문자열에서 누적합을 떠올려야 할 때 (0) | 2023.11.12 |
---|---|
ABC 328 E번 복기 cost를 modulo로 나눈 최소 스패닝 트리 구하는법 (0) | 2023.11.12 |
ABC 304 복기 - E good graph - union find 활용 (0) | 2023.06.04 |
ABC 301 복기.. C - AtCoder Cards (문자열 그리디 알고리즘) (0) | 2023.05.14 |
그래프 연결요소 - union find로 찾아야하는 연결요소 문제 1 - (0) | 2023.03.14 |