Disclaimer: I have no idea if this are indeed the correct answers. I just solved the exercises like this. I think that they are right though.
I have added my own code to this gist. It is ugly as hell, just like you can expect from code created in a contest like this.
Difficulty: easy
It is simple to see that a greedy solution is good enough.
My algorithm for this:
- Count the number of times every char appears and initialize the answer to 0, and set x to 26
- Find the char that occurs the most, multiply by x, add to the answer.
- Set the number of occurences of that char to 0 (so we will not see it as the most occuring char again).
- Decrease x by 1
- Repeat until x is 0
Difficulty: Moderate
This problem is a lot harder than Beatiful Strings. But with some insight, you should see that both emoticons (frowny face and smiley face) give you a choise when you encounter them. For the frowny face this is to either see it as a frowny face or as a '(' And for the smiley face this is to either see it as a smiley face or as a ')'. The truth is that it is impossible to know which to choose if you scan the string from the front to the back.
Thus, we need to scan the search space for this problem for a possible solution. To explain the concept, we will construct a 'decision tree' for the following example:
:( unhappy? or happy! :))
In the decision tree, every left child of a node, means we take it as its original form. And every right child means that we take it as a paren.
(take as emoticon) :( (take as parenthesis)
/ \
:) :)
/ \ / \
n n y n
The string is only valid when we take the frowny face as a paren, and the smiley face as a smiley face.
While parsing the string, we ignore every char exept for ':' (which indicates a smiley), '(' and ')'. We keep a 'depth' parameter that keeps the depth of the nesting of parenthesis. And whenever we find a smiley, we recursively call the parse method twice. One time we do not adjust the depth (we take the emoticon as emoticon), and the second time we do adjust the depth (we take the emoticon as parenthesis).
Simplified version of my algorithm for this problem, implemented in C++:
// line : input
// p : pointer to current position in line
bool parse(int p, int depth)
{
for (; p < len; p++) {
switch(line[p]) {
case '(':
depth++;
break;
case ')':
if (depth <= 0) {
return false;
}
depth--;
break;
case SMILEY: // :)
if (depth <= 0) {
// just use as smiley
break;
} else {
// two options:
// - use as smiley
// - use as ')'
return parse(p + 1, depth) || parse(p + 1, depth - 1);
}
break;
case FROWNY: // :(
// two options:
// - use as frowny
// - use as '('
return parse(p + 1, depth) || parse(p + 1, depth + 1);
break;
}
}
if (depth != 0) {
return false;
}
return true;
}
Difficulty: Moderate / Hard
In this problem it is very important that you read carefully. I've heard some people that looked over the fact that for m[i], you only need to look at the previous k values of m. Not all previous values.
First we have to calculate the sequence using the given PRNG. There is no smart way around this, it is just a means of delivering large input without producing an input file that is very large (which might give problems on slow connections).
When we have generated the first k values, it is time to tackle the problem itself. It is not very hard to generate value m[i] using the previous k values. What I did, is put all the previous values in a Binary-Search-Tree, and calculate the next value. Then I would pop the first value from the queue, and remove it from the Binary-Search-Tree.
Continously generating the next value is really easy, and will work perfectly for low values of n. However, when n gets larger, this will get painfully slow (and easily make your program run longer than 6 minutes). But, with some insight, we can see that the values of m[i] (with i > k), will repeat themselves every k+1 values. Thus now it is a matter of generating the first 2k+1 values. And then we give the value at position k + (n-2) % (k - 1) as the answer.