-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy patheuler-0114.cpp
102 lines (88 loc) · 2.94 KB
/
euler-0114.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// ////////////////////////////////////////////////////////
// # Title
// Counting block combinations I
//
// # URL
// https://projecteuler.net/problem=114
// http://euler.stephan-brumme.com/114/
//
// # Problem
// A row measuring seven units in length has red blocks with a minimum length of three units placed on it,
// such that any two red blocks (which are allowed to be different lengths) are separated by at least one black square.
// There are exactly seventeen ways of doing this.
//
// 
//
// How many ways can a row measuring fifty units in length be filled?
//
// NOTE: Although the example above does not lend itself to the possibility, in general it is permitted to mix block sizes.
// For example, on a row measuring eight units in length you could use red (3), black (1), and red (4).
//
// # Solved by
// Stephan Brumme
// May 2017
//
// # Algorithm
// This is a nice Dynamic Programming problem:
// - if there are less than three cells available then all must be black (1 solution)
// - else: the next cell can be black (return ''count[space - 1]'')
// - or: the next cells can be red, try all possible lengths and add ''count[space - block]''
//
// The algorithm examines most row lengths multiple times but memoizing the results in ''solutions'' keeps the running time well below 0.01 seconds.
//
// # Hackerrank
// My approach needs a bit of memory. Hackerrank has inputs up to `10^18` which clearly exceeds the RAM size of a desktop PC.
// [TODO] find closed formula
#include <iostream>
#include <vector>
#define ORIGINAL
// memoized solutions
const long long Unknown = -1;
std::vector<long long> solutions;
// print result modulo some number
#ifndef ORIGINAL
const unsigned long long Modulo = 1000000007;
#endif
// find result for row with a certain length
unsigned long long count(unsigned long long space, unsigned int minBlockLength)
{
// finished ?
if (space == 0)
return 1;
// already know the answer ?
if (solutions[space] != Unknown)
return solutions[space];
// one option is to leave the next cell black
auto result = count(space - 1, minBlockLength);
// insert red blocks at the current position with all possible spaces
for (auto block = minBlockLength; block <= space; block++)
{
// how much is left after inserting ?
auto next = space - block;
// must be followed by a black cell
if (next > 0)
next--;
// count all combinations
result += count(next, minBlockLength);
}
// Hackerrank only
#ifndef ORIGINAL
result %= Modulo;
#endif
// memoize result
solutions[space] = result;
return result;
}
int main()
{
// minimum length of each red block
unsigned int minBlockLength = 3;
// size of the whole row
unsigned long long totalLength = 50;
std::cin >> totalLength >> minBlockLength;
// cached results
solutions.resize(totalLength + 1, Unknown);
// let's go !
std::cout << count(totalLength, minBlockLength) << std::endl;
return 0;
}