Link
https://www.acmicpc.net/problem/3908
Details
에라토스테네스 채를 진행하고 나서, 작은 소수부터 다음의 과정을 통해 Tabulation을 행해준다.
- 이미 존재하는 소수의 합에 i를 더한 경우를 table에 적용해준다. (O(N))
- 본인스스로 1개로 구성하는 경우의 수를 추가해준다.
vector<bool> is_prime;
vector<map<int, int>> sum_factors;
// sum_factors[i][j] = k : i수를 j개의 소수의 합으로 나타내는 방법의 수가 k개 존재한다.
n이 1120까지이므로 충분히 간단하게 으로 해결이 가능하다.
Code
#include<bits/stdc++.h>
using namespace std;
vector<bool> is_prime;
vector<map<int, int>> sum_factors;
// sum_factors[i][j] = k : i수를 j개의 소수의 합으로 나타내는 방법의 수가 k개 존재한다.
void build_table(int n, int k) {
is_prime.resize(n + 1, true);
sum_factors.resize(n + 1);
is_prime[0] = is_prime[1] = false;
for (int i = 2; i * i <= n; i++) {
if (is_prime[i]) {
for (int j = i * i; j <= n; j += i) {
is_prime[j] = false;
}
}
}
// dp 시작 O(N)
for (int i = 2; i <= n; i++) if(is_prime[i]) {
// 이전에 존재하는 모든 소수 순회, 이때 더하기가 중복되지 않도록 역순으로 해줌줌
for(int j = n; j >= 0; j--) {
int target = i + j;
if(target > n) continue;
// target의 경우의 수에 1를 더해줌, key값이 없다면 value를 1로 초기화
for(auto& p : sum_factors[j]) {
// key값이 존재하지 않는다면 자동으로 0을 반환하기 때문에 성립하는 식
sum_factors[target][p.first + 1] += p.second;
}
}
// 자기자신으로 구성이 가능하기 때문에 1추가
sum_factors[i][1] = 1;
}
}
int main() {
int n, k;
int t_case; cin >> t_case;
// 최대 정수개수 1120에 대한 모든 테이블 그냥 미리 작성
build_table(1120, 14);
while(t_case--) {
cin >> n >> k;
cout << sum_factors[n][k] << '\n';
}
}