반응형
문제 요약
홀수 N이 주어졌을 때, N을 홀수 소수 하나와 짝수 세미소수의 합으로 나타내는 경우의 수를 구하시오. 여기서 세미소수란 두 소수를 곱한 수를 말한다.
N은 최대 100만이며 테스트 케이스의 수는 최대 10만이다.
풀이
N이 주어지면 N보다 작은 모든 홀수 소수 p에 대해서 N-p가 짝수 세미소수인 p의 개수를 찾으면 됩니다.
세미소수는 임의의 소수에 2를 곱한 수입니다.
에라토스테네스의 체를 이용해서 짝수 세미소수와 홀수 소수들을 전처리하면 어떤 수 x가 주어졌을 때 x가 홀수 소수인지 그리고 N-x가 짝수 세미소수인지 판단하는 것은 쉽습니다. 그러나 이를 이용하면 테스트 케이스가 많아서 시간초과를 받습니다.
이를 해결하기 위해서 생성함수를 이용합니다.
다항식 $f(x)$와 $g(x)$를 만들 것인데 $f(x)$는 홀수 소수 차수의 항들의 계수가 1이고 나머지 항들의 계수는 0인 다항식입니다. $g(x)$는 짝수 세미소수 차수의 항들의 계수가 1이고 나머지는 0인 다항식입니다.
이제 $N$이 들어왔을 때 우리가 원하는 답은 $f(x), g(x)$를 곱한 다항식 $h(x)=f(x)g(x)$의 N차항의 계수가 됩니다.
$f$와 $g$의 차수는 100만으로 나이브하게 다항식의 곱을 구하면 시간초과가 납니다. FFT를 이용하면 이를 빠르게 구할 수 있고 문제를 해결할 수 있습니다.
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000000
typedef complex<double> cdbl;
bool chk[MAXN+5];
vector<int> primes;
void sieve() {
for(int i=2;i<=MAXN;++i) {
if(!chk[i]) {
for(int j=i+i;j<=MAXN;j+=i) chk[j] = true;
}
}
for(int i=2;i<=MAXN;++i) {
if(!chk[i]) primes.push_back(i);
}
}
void fft(vector<cdbl> &a, bool inv) {
int n = a.size();
// bit reversal
for(int i=1,j=0;i<n;++i) {
int bit = n>>1;
while(!((j^=bit) & bit)) bit >>=1;
if(i<j) swap(a[i],a[j]);
}
for(int i=1;i<n;i<<=1) {
double x = inv? M_PI / i : -M_PI / i;
cdbl w = cdbl(cos(x),sin(x));
for(int j=0;j<n;j += i<<1) {
cdbl p = cdbl(1,0);
for(int k=0;k<i;++k) {
cdbl tmp = a[i+j+k] * p;
a[i+j+k] = a[j+k] - tmp;
a[j+k] += tmp;
p *= w;
}
}
}
if(inv) {
for(int i=0;i<n;++i) a[i] /= n;
}
}
// h = fg
void multiply(vector<cdbl> &f, vector<cdbl> &g, vector<cdbl> &h) {
fft(f,false); fft(g,false);
for(int i=0;i<f.size();++i) h[i] = f[i] * g[i];
fft(h,true);
}
int main() {
cin.tie(nullptr); ios::sync_with_stdio(false);
int T; cin >> T;
sieve();
vector<cdbl> f(1<<21), g(1<<21), ans(1<<21);
for(auto p:primes) {
f[p] = cdbl(1,0);
if(p*2<=MAXN) g[2*p] = cdbl(1,0);
}
multiply(f,g,ans);
while(T--) {
int n;
cin >> n;
cout << round(ans[n].real()) << '\n';
}
return 0;
}
반응형
'Problem Solving > 문제풀이' 카테고리의 다른 글
백준 4008번 특공대 (0) | 2021.02.15 |
---|---|
백준 20176번 Needle (0) | 2021.02.15 |
백준 14756번 Telescope (0) | 2021.02.15 |
백준 10793번 Tile Cutting (2) | 2021.02.15 |
백준 10531번 Golf Bot (0) | 2021.02.04 |