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<int, int>;
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
'백준 > 문자열' 카테고리의 다른 글
[ICPC] 백준 14959 - Slot Machines (0) | 2022.07.20 |
---|---|
[ICPC] 백준 10266 - 시계 사진들 (0) | 2022.07.15 |
[ICPC] 백준 9081 - 단어 맞추기 (0) | 2021.11.09 |