티스토리 뷰
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define P 37
#define M 1000000007
#define m 100003
#define L long long
L calHash(char * s) {
L a=0,b=1,c;
while(*s) {
c=(*s-'a'+1);
a=(a+c*b)%M;
b=(b*P)%M;
++s;
} return a;
}
L fast(L base, L exp, L mod) {
L a=1;
while(exp>0) {
if(exp&1) a = (a*base)%mod;
base = (base*base)%mod;
exp/=2;
} return a;
}
int main(void) {
L v, invP;
int i,j,r,c,h=0,cnt=0;
scanf("%d %d",&r,&c);
char str[c][r+1];
int hash[c];
invP = fast(P,M-2,M);
for(i=0;i<r;i++) for(j=0;j<c;j++) scanf(" %c",&str[j][i]);
for(i=0;i<c;i++) str[i][r]='\0';
for(i=0;i<c;i++) hash[i] = calHash(str[i]);
while(++h < r) {
int table[m]={};
for(i=0;i<c;i++) {
hash[i] = (((hash[i]-(str[i][h-1]-'a'+1))*invP)%M);
v=hash[i]%m;
while(table[v]) {
if(!strcmp(str[i]+h,str[table[v]-1]+h)) {
printf("%d",h-1);
return 0;
} else {
++v;
if(v==m) v=0;
}
} table[v]=i+1;
}
}
printf("%d",h-1);
}
풀이 : 해쉬 테이블
<사용한 것>
calHash : 해쉬값을 구합니다.
처음 문자열에 대한 해쉬값을 구한다음, 시간을 줄이기 위해서, 한 줄 삭제한 다음 다시 해쉬값을 구하는 것이 아니라 기존의 해쉬값에서 약간의 연산만 추가했습니다.
(a0P0...anPn) 여기서 a0P0을 제거한 해쉬값은 ( (a0P0...anPn) - a0P0 / P ) mod M 이며 c언어에서 곱셈에 비해 나눗셈은 너무 느리기 때문에 1/P = P^-1 이며 이는 즉 모듈러 역원으로 얻어낼수 있습니다.
모듈러 역원 a^-1 = a^(N-2) mod N (단 N은 소수)
fast : 모듈러 역원을 구하기 위한 제곱을 구하는 함수에 mod M 이 추가되었습니다. (밑^지수 에서 지수를 이진수로 바라본 다음, 빨리 a^n 을 구할 수 있는 방법입니다)
<해쉬값과 해쉬테이블>
해쉬값은 mod M (overflow 방지) 만을 한것을 의미하며, 이러한 해쉬값들을 해쉬테이블에 사용할때는 , 해쉬테이블에 맞게 mod m 을 해주었습니다. 주의 할 점은 해쉬값은 구할때 mod m 을 하지 않습니다. mod m을 한 것은 테이블에 범위에 맞춘 변형된 해쉬값 이라고 보는게 맞습니다.
<해쉬테이블 충돌관리>
먼저 특정 변형된 해쉬값을 가지고 이미 어떤 것이 먼저있는지를 확인하고 만약 있다면 strcmp으로 문자열을 비교해 봅니다. 만약 다르다면 (+1) 옆 구역을 확인하며, 같다면 종료합니다.
<문자열 입력받기>
문자열을 90도 돌려서 저장하는게 더 편할 것 같아서 %s가 아니라 %c로 각각 문자하나씩 담아서, 90도로 돌려주었습니다.
dobarz
adatak
이걸
da\0
od\0
ba\0
at\0
ra\0
zk\0
로 저장했다고 보시면 됩니다 \0은 따로 붙여주었습니다. (for(i=0;i<c;i++) str[i][r]='\0';)
https://www.acmicpc.net/problem/2866
'c언어 > BAEKJOON' 카테고리의 다른 글
c언어 4779번 칸토어 집합 (백준) (0) | 2025.03.14 |
---|---|
c언어 28446번 볼링공 찾아주기 (백준) (0) | 2025.03.08 |
c언어 27964번 콰트로치즈피자 (백준) (0) | 2025.03.01 |
c언어 20291번 파일정리 (백준) (0) | 2025.02.28 |
c언어 31908번 커플링 매치 (백준) (0) | 2025.02.25 |
- Total
- Today
- Yesterday
- 1835
- C언어
- 세그먼트 트리
- 플로이드
- union
- 그리디
- 오프라인 쿼리
- 덱
- 스택
- 브루트포스
- XOR
- DP
- C++
- 최소 스패닝 트리
- 백준
- java
- 누적합
- Segment Tree
- BFS
- 기하학
- 그래프
- 1835번
- PASCAL
- 최대공약수
- 정렬
- find
- DFS
- Lazy Propagation
- 누적 합
- Krustal
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |