소수가 담긴 배열을 생성하기 위해 에라토스테네체의 체를 적용한다.
이후 Two pointer를 이용해 연속된 소수의 합이 과 같아지는 횟수를 출력한다.
- 에라토스테네체의 체?
- 이하의 소수를 구하고자 한다면, 인 모든 정수 에 대하여, 자기 자신을 제외한 의 배수를 제거한다.
20
미만의 소수를 구한다고 가정하자.
은 약4.47
이므로, 인 에 대해 윗 과정을 진행한다.
2 , 3,4, 5 ,6, 7 ,8, 9 ,10, 11 ,12, 13 ,14, 15 ,16, 17 ,18, 19 ,20
2 , 3,4, 5 ,6, 7 ,8,9,10, 11 ,12, 13 ,14,15,16, 17 ,18, 19 ,20
2 , 3,4, 5 ,6, 7 ,8,9,10, 11 ,12, 13 ,14,15,16, 17 ,18, 19 ,20
최종적으로 남은2 3 5 7 11 13 17 19
가 범위 내의 모든 소수가 된다.
- 윗 과정을 통해 구한 소수 배열에 Two pointer를 적용해 과 비교한다.
- 연속된 소수의 합이 보다 작다면, 오른쪽 포인터를 옮긴다.
- 연속된 소수의 합이 과 같다면,
ans++
를 해준 후 오른쪽 포인터를 옮긴다.- 연속된 소수의 합이 보다 크다면, 왼쪽 포인터를 옮긴다.
- 입력받은 이 인 경우 예외처리 해주어야함에 유의한다.
void Eratos(int num)
{
// 에테체
for(int i = 2; i*i <= num; i++)
if(!visited[i])
for(int j = 2; i*j <= num; j++)
{//자신을 제외한 i의 배수를 제거한다.
visited[i*j] = true;
}
}
<에라토스테네체의 체>
위에서 설명한 알고리즘에 따라 소수를 판정한다.
int TP()
{
int ans = 0;
int start = 0,end = 0, sum = pN[0];
while(end < pN.size())
{
if(sum <= n)
{
if(sum == n) ans++;//합이 N과 같다면
sum += pN[++end];//합이 N 이하라면 오른쪽 포인터 옮김
}
else
{//합이 N보다 크면
if(start == end)
{//두 포인터의 위치가 같다면 둘 다 옮긴다.
start++; end++;
sum = pN[start];
}
//두 포인터의 위치가 다르면 왼쪽 포인터를 옮긴다
else sum -= pN[start++];
}
}
return ans;
}
<Two Pointer 함수>
void SOLVE()
{
if(n == 1) cout << 0, exit(0);
Eratos(n);
for(int i = 2; i <= n; i++)
if(!visited[i])
pN.push_back(i);
cout << TP();
}
<전체 알고리즘>
입력된 이 인 경우 예외처리 해준다.
이외의 경우, 에라토스테네체의 체를 적용해 소수를 판별한 수, 소수의 배열을 만들어 Two pointer를 적용해 답을 구한다.
#include <iostream>
#include <vector>
using namespace std;
int n;
bool visited[4000001];
vector<int> pN;
void INPUT()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin >> n;
}
void Eratos(int num)
{
// 에테체
for(int i = 2; i*i <= num; i++)
{
if(!visited[i])
{
for(int j = 2; i*j <= num; j++)
{
visited[i*j] = true;
}
}
}
}
int TP()
{
int ans = 0;
int start = 0,end = 0, sum = pN[0];
while(end < pN.size())
{
if(sum <= n)
{
if(sum == n) ans++;//합이 N과 같다면
sum += pN[++end];//합이 N 이하라면 오른쪽 포인터 옮김
}
else
{//합이 N보다 크면
if(start == end)
{//두 포인터의 위치가 같다면 둘 다 옮긴다.
start++; end++;
sum = pN[start];
}
//두 포인터의 위치가 다르면 왼쪽 포인터를 옮긴다
else sum -= pN[start++];
}
}
return ans;
}
void SOLVE()
{
if(n == 1) cout << 0, exit(0);
Eratos(n);
for(int i = 2; i <= n; i++)
if(!visited[i])
pN.push_back(i);
cout << TP();
}
int main()
{
INPUT();
SOLVE();
}
에라토스테네체의 체 , Two pointer 모두 쉬운 알고리즘에 속한다.
그러나 모르면 이 문제를 못 풀기에 Gold3이라는 높은 티어를 갖게된 것같은데..
여전히 다른 Gold3에 비하면 쉽다는 생각이 든다.