#include
#include
#include
using namespace std;
const unsigned int FIRST_SIGNAL = 1983;
int countK(unsigned int k, unsigned int n);
struct RNG {
unsigned int seed;
RNG() : seed(FIRST_SIGNAL) {}
unsigned int next() {
unsigned int ret = seed;
seed = ((seed * 214013u + 2531011u));
return ret % 10000 + 1;
}
};
int main()
{
int caseNum = 0;
cin >> caseNum;
unsigned int k = 0, n = 0;
for (int cIter = 0; cIter < caseNum; cIter++)
{
cin >> k >> n;
int count = countK(k, n);
cout << count << endl;
}
}
int countK(unsigned int k, unsigned int n)
{
RNG rng;
queue signals;
unsigned int rangeSum = 0, cnt = 0;
for (unsigned int tail = 0; tail < n; tail++)
{
int newSignal = rng.next();
rangeSum += newSignal;
signals.push(newSignal);
while (rangeSum > k)
{
rangeSum -= signals.front();
signals.pop();
}
if (rangeSum == k) { cnt++; }
}
return cnt;
}
이 문제는 Input 값을 직접 생성해가며 문제를 풀어야 했다. Input 데이터들을 모아둘 메모리가 제한 범위를 훨씬 넘어서기 때문이다. 이 문제에서는 RNG 구조체를 선언하여 다음 Input 값을 매번 생성하였다.
알고리즘을 고안할 때 처음엔 brute force 방식으로 구현하였다. 모든 부분 순열 구간을 돌면서 값들을 계산하는 방식이었고, 매우 비효율적이었다. 책에서는 head 값이 증가할 때마다 tail 값이 감소하지 않는다는 지점에서 통찰을 얻었다. 이를 활용하여 tail 이 0 번부터 N - 1 번 순회하는 동안 head 들이 tail을 알아서 따라오도록 코드를 작성하였다.
그 결과 O(NK) 였던 brute force 방식을 O(N) 으로 훨씬 Optimize 할 수 있었다.
이 문제를 풀면서 RNG 구조체가 난수를 생성할 때 연산 관련 이슈가 발생했었다.
자세한 건 아래 링크에 적어두었다.
반응형
'Algorithm > Data Structures' 카테고리의 다른 글
BRACKETS 2 (0) | 2019.10.03 |
---|---|
JOSEPHUS (0) | 2019.03.18 |