반응형
https://www.acmicpc.net/problem/13575
26/02/10
FFT를 사용하지 않고도 냅색만으로 해결할 수도 있지만, 나는 그렇게 해결하지 못했기 때문에 FFT를 사용한 풀이만을 소개하겠다.
문제 접근 방식:
결국 이것도 Golf Bot문제의 연장선인데, 우리는 보석을 $K$개 가져갈 수 있으므로 $\sum x^{a_{i}}$를 $K$번 거듭제곱하면 된다.
근데 무작정 $K$번 곱한다면 시간초과가 난다.
우리가 Convolution을 구현했을 때를 생각해보면, resize가 필수적이었다.
만약 두 다항식의 길이 차이가 크다면, 길이가 짧은 다항식의 resize 양 또한 커지게 되고, 결국 FFT변환할 때의 시간 또한 오래 걸릴 것이다.
결국 두 다항식의 길이 차이가 "적도록" 다항식을 서로 곱해야 한다.
우리는 분할 정복을 이용한 거듭제곱으로 다항식을 곱할 것이다. 그러면 Convolution함수를 $\log$번 호출하게 되며, 나이브하게 $K$번을 곱하는 것보다 빠르게 구할 수 있다.
아래는 내가 위의 접근 방식과 같이 작성한 C++ 코드이다. 더보기를 누르면 확인할 수 있다.
더보기
// 13575번 보석 가게
// FFT
/*
접근 방법:
길이 1'001짜리 다항식을 K번 곱한다면?
*/
#include <iostream>
#include <vector>
using namespace std;
#define fastio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl '\n'
typedef long long ll;
template<int MOD, int G>
struct NTT{
// HELPER FUNCTION
private:
inline int mul_mod(int a, int b) const {return (ll)a*b%MOD;}
inline int pow_mod(int a, int e) const {
int r = 1;
while(e > 0){
if (e&1) r=mul_mod(r,a);
a=mul_mod(a,a);
e>>=1;
}
return r;
}
inline int mod_inv(int a) const {return pow_mod(a, MOD-2);}
public:
void ntt(vector<int>& a, int invert){
int n = (int)a.size();
// 1) bit-reversal permutation
for (int i = 1, j = 0; i < n; ++i){
int bit = n >> 1;
while (j & bit){
j ^= bit;
bit >>= 1;
}
j ^= bit;
if (i < j) swap(a[i], a[j]);
}
// 2) butterfly
for (int len = 2; len <= n; len <<= 1){
int wlen = pow_mod(G, (MOD-1)/len);
if (invert) wlen = mod_inv(wlen);
for (int i = 0; i < n; i += len){
int w = 1;
for (int j = 0; j < len/2; ++j){
int u = a[i+j];
int v = mul_mod(w, a[i+j+len/2]);
int x = u+v; if (x >= MOD) x -= MOD;
int y = u-v; if (y < 0) y += MOD;
a[i+j] = x; a[i+j+len/2] = y;
w = mul_mod(w, wlen);
}
}
}
// 3) for invert
if (invert){
int inv = mod_inv(n);
for (int i = 0; i < n; ++i){
a[i] = mul_mod(a[i], inv);
}
}
}
vector<int> convolution(vector<int> a, vector<int> b){
int S_a = (int)a.size(), S_b = (int)b.size();
int n = 1;
while (n < S_a+S_b-1){
n <<= 1;
}
a.resize(n); b.resize(n);
ntt(a, 0); ntt(b, 0);
for (int i = 0; i < n; ++i) a[i] = mul_mod(a[i], b[i]);
ntt(a, 1);
a.resize(S_a+S_b-1);
return a;
}
};
vector<int> pow_poly(vector<int> a, int k){
NTT<998'244'353, 3> ntt;
vector<int> ret = {1};
while(k > 0){
if (k&1) ret=ntt.convolution(ret,a);
a=ntt.convolution(a, a);
k>>=1;
}
return ret;
}
int main(void){
fastio
int N, K; cin >> N >> K;
vector<int> a(1001, 0);
int j;
for (int i = 0; i < N; ++i){
cin >> j;
a[j] = 1;
}
vector<int> c = pow_poly(a, K);
for (int i = 0; i < c.size(); ++i){
if (c[i] != 0) cout << i << ' ';
}
return 0;
}
반응형
'알고리즘 > 백준 문제 풀이' 카테고리의 다른 글
| [C++] 14958번 Rock Paper Scissors (0) | 2026.02.26 |
|---|---|
| [C++] 11385번 씽크스몰 (0) | 2026.02.25 |
| [C++] 15576번 큰 수 곱셈 (2) (0) | 2026.02.24 |
| [Python] 25214번 크림 파스타 (0) | 2026.02.24 |
| [C++] 21624번 Fence (0) | 2026.02.23 |