1. 문제
25025번: 다항식 계산
첫 번째 줄에 두 정수 N, P (0≤N≤106, 1≤P≤103, P는 소수)가 공백 하나로 구분되어 주어진다. 두 번째 줄에는 N+1개의 정수 aN, ⋯, a1, a0 (0≤ai≤109)가 공백 하나로
www.acmicpc.net
2. 풀이
결국에 구해야하는 값은 aikimodP이고 k와 P가 서로소이므로 페르마의 소정리를 이용할 수 있다.
그런데 1초안에 P개의 값을 계산해야하니 이거 쉽지 않다
계수는 최악의 경우 106개이고.. 매 함숫값마다 이들을 모두 순회해야하니.. O(109)는 돌아야겠는데
이거 1초안에 당연히 안될거고..
근데 조금 생각해보면...
페르마의 소정리에 의해 kp−1≡1(modp)
하지만 N이 p보다 클수 있는데 그런 경우에 kNmodp는 어떻게 구해야하는가?
합동식은 정수 q번 거듭제곱해도 성립하므로...
p-1에서 q번 거듭제곱한다면.. (kp−1)q≡1(modp)
여기에 kr을 양변에 곱해도 합동식이 성립하므로... k(p−1)q+r≡kr(modp)
만약에, N=(p−1)q+r이 성립한다고 한다면... 이 식이 무엇을 뜻하는가?
N을 p-1로 나눈 몫이 q이고 나머지가 r이다.
즉, kNmodp는 페르마의 소정리를 이용한다면.. N을 p-1로 나눈 나머지 r에 대하여 krmodp로 압축할수 있다
그래서 먼저 O(N)에 1부터 N까지 순회하여 p-1로 나눈 나머지를 모두 구해준다.
그러면 1부터 N까지가 0 ~ p-2중 하나로 압축될 것이며, 그러면서 동일한 거듭제곱 항은 서로 묶어서 계산할 수 있다
그래서 동일한 거듭제곱 항끼리 계수를 서로 묶어서 미리 계산해준다.
이렇게 한다면, 모든 i = 0,1,2,...,p-1에 대하여 f(i)를 계산할때, 계산해야할 거듭제곱 항은 0 ~ p-2까지로 압축되며,
O(N+p2)에 문제를 해결할 수 있다
약 2∗106이라 1초안에 돌수 있을듯
from sys import stdin
n,p = map(int,stdin.readline().split())
A = list(map(int,stdin.readline().split()))
A_dict = {}
f1 = 0
#페르마의 소정리에 의해, k^n mod p = k^(n%p) mod p
#차수가 같은 항끼리 묶어서 계수를 미리 계산해 N+1 > p-1개의 항으로 압축
for i in range(n+1):
A[i] %= p
f1 += A[i]
r = (n-i) % (p-1)
A_dict[r] = A_dict.get(r,0) + A[i]
A_dict[r] %= p
print(A[-1]) #f(0) mod p
print(f1 % p) #f(1) mod p
#i = 2,3,...,p-1에 대해 f(i) mod p를 계산
#A_dict에 차수가 k=0,1,2,..p-1인 항의 계수 v가 계산되어있다
#k 차수 항은 v*i^k mod p로 계산 가능
#분할정복을 이용한 거듭제곱으로 빠르게
for i in range(2,p):
answer = 0
for k,v in A_dict.items():
answer += pow(i,k,p)*v
answer %= p
print(answer)
'정수론' 카테고리의 다른 글
디오판토스 분수방정식의 정수 해법 배우기(+팩토리얼 인수분해, 제곱수의 약수의 개수) (0) | 2023.07.14 |
---|---|
포함 배제의 원리를 이용해 매우 큰 범위에서 조건에 맞는 수들만 빠르게 찾는 법 배우기 (+ 부분집합 구하기 재활) (0) | 2023.07.09 |
오일러 phi 함수 재활 -xφ(x) = n을 만족하는 x의 최솟값 구하기- (0) | 2023.07.06 |
이항계수를 소수로 나눈 나머지 구하는 방법 - Lucas' Theorem 배우고 적용하기 (0) | 2023.07.04 |
조합의 곱의 합을 구하는 Vandermonde's identity (0) | 2023.07.03 |