본문 바로가기

백준/문자열

백준 1498 - 주기문

728x90
728x90

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

사전 지식

이 문제를 KMP로 풀고 와야 한다.

 

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

 

4354번: 문자열 제곱

알파벳 소문자로 이루어진 두 문자열 a와 b가 주어졌을 때, a*b는 두 문자열을 이어붙이는 것을 뜻한다. 예를 들어, a="abc", b="def"일 때, a*b="abcdef"이다. 이러한 이어 붙이는 것을 곱셈으로 생각한다

www.acmicpc.net

풀이

문자열 제곱을 제대로 이해하고 왔다면 KMP 실패 함수에 다음 성질이 있음을 알 것이다.

 

길이 x의 문자열이 주기성을 만족하려면 n - x개의 접미사와 n - x개의 접두사가 같아야 한다. 또한 x|n을 만족해야 한다.(|은 정수론에서 배수관계를 나타내는 기호)

 

일단 실패 테이블을 구하자.

 

그러면 테이블에 n - x개의 서로 같은 문자열의 길이를 구할 수 있다. 문제에서는 substring에 대해 주기를 구할 수 있냐고 묻고 있으므로 각 인덱스마다 (i + 1) - pi[i] (0-indexed)의 값으로 x를 구하고 나눠 떨어지는 것마다 출력하면 된다.

 

전체 코드

더보기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,avx,avx2,fma")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
 
#include "bits/stdc++.h"
#include "ext/rope"
 
using namespace std;
using namespace __gnu_cxx;
 
using ll = long long;
using pii = pair<intint>;
 
string s;
 
vector<int> bake_pi(string &pat)
{
  vector<int> ret(pat.size());
  int j = 0;
  for (int i = 1; i < pat.size(); i++)
  {
    while (j and pat[j] != pat[i]) j = ret[j - 1];
    ret[i] = pat[j] == pat[i] ? ++j : 0;
  }
  return ret;
}
 
void solve()
{
  cin >> s;
 
  auto pi = bake_pi(s);
  for (int i = 1; i < pi.size(); i++)
  {
    int candidate = (i + 1- pi[i];
    if ((i + 1) % candidate == 0 and (i + 1!= candidate)
    {
      cout << i + 1 << ' ' << (i + 1/ candidate << '\n';
    }
  }
}
 
int main()
{
#ifdef LOCAL
  freopen("input.txt""r", stdin);
//  freopen("output.txt", "w", stdout);
#endif
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
 
  solve();
}
cs

제출 기록

728x90
728x90

'백준 > 문자열' 카테고리의 다른 글

[ICPC] 백준 14959 - Slot Machines  (0) 2022.07.20
[ICPC] 백준 10266 - 시계 사진들  (0) 2022.07.15
[ICPC] 백준 9081 - 단어 맞추기  (0) 2021.11.09