백준 15829 - Hashing

황재진·2024년 7월 8일

백준

목록 보기
35/54

해시 함수를 구현하는 문제입니다. 문제에 주어진 수식을 그대로 코드로 구현하면 되는 문제입니다.

문제는 숫자가 너무 커질 경우 연산이 불가능해집니다. 이 때 모듈러 산술(Modular arithmetic) 특징 중 분배법칙을 활용해 해결할 수 있습니다.

(A+B)%C=(A%C+B%C)%C(AB)%C=(A%CB%C)%C(AB)%C=(A%CB%C)%C(A+B)\%C=(A\%C+B\%C)\%C \\ (A-B)\%C=(A\%C-B\%C)\%C \\ (A*B)\%C=(A\%C*B\%C)\%C

해당 문제의 해시 함수는 다음과 같이 생겼습니다.

H=i=0l1(airi)%MH=\sum_{i=0}^{l-1} ({a_i*r^i})\% M

이걸 풀어쓰면 다음과 같습니다.

(a0r0+a1r1+...+al1rl1)%M(a_0r^0+a_1r^1+...+a_{l-1}r^{l-1})\%M

먼저 모듈러 산술 덧셈 분배법칙이 활용됩니다.

((a0r0)%M+(a1r1)%M+...+(al1rl1)%M)%M((a_0r^0)\%M+(a_1r^1)\%M+...+(a_{l-1}r^{l-1})\%M)\%M

해당 식에서 0번 연산식만 떼어서 보겠습니다.

(a0r0)%M(a_0r^0)\%M

여기에서 모듈러 산술 곱셈 분배법칙이 활용됩니다.

(a0%M r0%M)%M(a_0\%M\ r^0\%M)\%M

위 연산이 l1l-1번 반복되는 형태라면 모듈려 연산으로 인해 표현 가능 숫자 범위를 넘어가지 않게 됩니다.

#include <iostream>
#include <cmath>

int main()
{
	const int r = 31;
	const int M = 1234567891;

	int l;
	std::string str;

	std::cin >> l >> str;

	long hash = 0;
	long curR = 1;

	for (int i = 0; i < l; i++)
	{
		int c = ((int)str[i] - 96); // M을 넘을 일이 없어서 M으로 나머지 연산 필요없음
		hash += c * curR % M;
		curR = (curR * r) % M;
	}

	std::cout << hash % M;

	return 0;
}
profile
프로그래밍, 쉐이더 등 이것저것 다해보는 게임 개발자입니다

0개의 댓글