Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
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
Archives
Today
Total
관리 메뉴

dh-winternagi 님의 블로그

(21162) 뒤집기 K 본문

백준 (C++)/Solve

(21162) 뒤집기 K

dh-winternagi 2026. 4. 25. 00:23

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

단계별로 풀어보기

46단계(문자열 알고리즘 1) 8번째

 

 

 

길이가 같은 두 문자열의 사전 순 비교를 나이브하게 하는 법은 첫 글자부터 비교하여 O(N)이 걸린다. 하지만 해싱을 이용하면 O(log N)으로 사전 순 비교를 할 수 있다.

해싱을 이용하면 두 문자열이 같은지 확인하는 연산을 O(1)에 할 수 있다. 파라메트릭 서치를 이용해 비교 함수는 부분문자열 A[:mid]와 B[:mid]가 같은 값인가?로 설정하면 이 연산은 O(1)이므로, 두 문자열을 비교했을 때 처음으로 값이 달라지는 위치를 O(log N)으로 찾을 수 있다. 이 인덱스의 문자를 비교하는 건 O(1)이므로 결과적으로 한 번의 사전 순 비교를 O(log N)에 할 수 있다.

따라서 문자열의 집합의 정렬을 O(N log N)*O(log N)= O(N log^2 N)에 할 수 있다.

 

 

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define p 524287
#define mod 998244353

int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  
  int n, k;
  
  cin >> n >> k;
  
  vector<int> v(n), str(n-1);
  vector<long> hash(2*n-1), base(2*n-1);
  
  for(int i=0;i<n;i++)  cin >> v[i];
  for(int i=0;i<n-1;i++)  str[i]= i+1;
  
  reverse(v.begin(), v.end());
  v.insert(v.end(), v.begin(), v.end());
  
  base[0]= 1;
  for(int i=1;i<2*n-1;i++){
    hash[i]= (hash[i-1] * p + v[i]) % mod;
    base[i]= (base[i-1] * p) % mod;
  }
  
  auto gethash= [&](int l, int r) -> long {
    return (hash[r]-(hash[l-1]*base[r-l+1]%mod)+mod)%mod;
  };
  
  sort(str.begin(), str.end(), [&](int A, int B){
    int l= 0, r= n;
    
    while(l<r){
      int mid= (l+r)/2;
      
      long a= gethash(A, A+mid), b= gethash(B, B+mid);
      
      if(a==b)  l= mid+1;
      else  r= mid;
    }

    if(l==n)  return false;
    return v[A+l] < v[B+l];
  });
  
  for(int i=str[k-1],j=0;j<n;j++){
    cout << v[i+j] << " ";
  }
  
  return 0;
}

'백준 (C++) > Solve' 카테고리의 다른 글

(17435) 합성함수와 쿼리  (0) 2026.04.25
(3584) 가장 가까운 공통 조상  (0) 2026.04.25
(28122) 아이템  (0) 2026.04.24
(13505) 두 수 XOR  (0) 2026.04.24
(5670) 휴대폰 자판  (0) 2026.04.24