728x90
https://www.acmicpc.net/problem/17134
26/01/30
Golf Bot문제의 아이디어를 사용하면 쉽게 해결할 수 있다.
문제 접근 방식:
홀수 소수를 $p$, 짝수 세미소수를 $q$라고 한다면 $p+q = N$을 만족하는 경우의 수를 구하는 문제이다.
결국 Golf Bot문제와 동일한 아이디어로 풀리는데, $A[p] = 1$인 배열 $A$와 $B[q] = 1$인 배열 $B$를 만들어서, 두 배열 $A, B$를 FFT로 곱하면 된다.
배열 $A$는 에라토스테네스의 체를 통해 구할 수 있고, 그렇게 구한 $A$를 통해 $B$또한 만들 수 있다.
아래는 내가 위의 접근 방식과 같이 작성한 C++ 코드이다. 더보기를 누르면 확인할 수 있다.
더보기
// 17134번 르모앙의 추측
// FFT
#include <iostream>
#include <vector>
using namespace std;
#define fastio ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl '\n'
template<long long MOD, long long G>
struct NTT {
using ll = long long;
private :
// HELPER FUNCTION
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 iterative_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) butterflies by length = 2, 4, 8, ...
for (int len = 2; len <= n; len <<= 1){
// primitive len-th root of unity
int w_len = pow_mod(G, (MOD - 1) / len);
if (invert) w_len = mod_inv(w_len);
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, w_len);
}
}
}
// 3) Divide by n (multiply by inverse) for inverse transform
if (invert){
int inv_n = mod_inv(n);
for (int i = 0; i < n; ++i){
a[i] = mul_mod(a[i], inv_n);
}
}
}
// Input : Coefficient vector {a_0, a_1, ...}, {b_0, b_1, ...}
// Output : Convolution of two coefficient vector
vector<int> convolution(vector<int> a, vector<int> b) {
if (a.empty() || b.empty()) return {};
int S_a = (int)a.size(), S_b = (int)b.size();
// Make vector size easy to dnc(2^n).
int n = 1;
while (n < S_a + S_b - 1){
n <<= 1;
}
a.resize(n); b.resize(n);
// Normalize to [0, MOD)
for (int i = 0; i < n; ++i){
a[i] %= MOD; if (a[i] < 0) a[i] += MOD;
b[i] %= MOD; if (b[i] < 0) b[i] += MOD;
}
// NTT
iterative_NTT(a, 0); iterative_NTT(b, 0);
// Pointwise product
for (int i = 0; i < n; i++) {
a[i] = mul_mod(a[i], b[i]);
}
// INTT
iterative_NTT(a, 1);
a.resize(S_a + S_b - 1);
return a;
}
};
int main(void){
fastio
// Find odd primes and even semi-primes using sieve
vector<int> even_semi_primes(1'000'001, 0);
vector<int> sieve(1'000'001, 1);
sieve[0] = 0; sieve[1] = 0;
for (int i = 2; i <= 1000; ++i){
if (sieve[i]){
for (int j = i*i; j <= 1'000'000; j += i){
sieve[j] = 0;
}
}
}
for (int i = 0; i <= 500'000; ++i){
if (sieve[i]) even_semi_primes[2*i] = 1;
}
sieve[2] = 0;
// Product sieve using NTT
NTT<998'244'353, 3> ntt;
auto C = ntt.convolution(sieve, even_semi_primes);
int T; cin >> T;
int N;
for (int i = 0; i < T; ++i){
cin >> N;
cout << C[N] << endl;
}
return 0;
}
728x90
'알고리즘 > 백준 문제 풀이' 카테고리의 다른 글
| [C++] 17104번 골드바흐 파티션 2 (0) | 2026.02.18 |
|---|---|
| [C++] 20176번 Needle (0) | 2026.02.16 |
| [C++] 10531번 Golf Bot (0) | 2026.02.15 |
| [C++] 25456번 궁금한 시프트 (0) | 2026.02.14 |
| [C++] 1067번 이동 (0) | 2026.02.13 |