It is currently Fri Apr 19, 2024 6:59 pm

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 54 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #21 Posted: Sun May 07, 2017 6:37 pm 
Gosei
User avatar

Posts: 1848
Location: Bellevue, WA
Liked others: 90
Was liked: 837
Rank: AGA 5d
KGS: Capsule 4d
Tygem: 치킨까스 5d
Kirby wrote:
I see a lot of people participating. Are they all from L19?
At least 10 in this round are from L19.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #22 Posted: Sun May 07, 2017 7:56 pm 
Lives with ko

Posts: 149
Liked others: 276
Was liked: 49
Rank: 3d
KGS: 3d
DGS: 3d
OGS: 3d
Similar to what peti said about Problem C: I've made so much incremental progress in formulating it as a DP problem, but still I'm running out of time at test case 34 ...

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #23 Posted: Sun May 07, 2017 11:00 pm 
Dies in gote
User avatar

Posts: 63
Liked others: 0
Was liked: 40
Thanks for setting up the contest.

I had (I think) working Python solutions for C and E, but hit the time limit exceeded problem (especially frustrating for problem E since on my laptop all test cases up to n = 10^18 and varying k - which I think should be the slowest ones within the problem specification - ran in below 1 second ...). Rewriting in a compiled language would have helped, I suppose, but did not seem to be a good way to spend my time. I did not use any math/combinatorics, though, maybe I should have thought more about that.

For the curious, I put my solutions/attempts on github: https://github.com/ugoertz/l19contest. Comments welcome!

Best regards, Ulrich

_________________
u-go.net


This post by ugoertz was liked by: Solomon
Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #24 Posted: Sun May 07, 2017 11:10 pm 
Gosei
User avatar

Posts: 1848
Location: Bellevue, WA
Liked others: 90
Was liked: 837
Rank: AGA 5d
KGS: Capsule 4d
Tygem: 치킨까스 5d
About to go to sleep, will post what I managed to solve in the morning and update the leaderboard. I'm thinking maybe for next round, to put up 2 easy, 2 medium, 2 hard instead of 1 easy, 1 medium, and 3 hard. What do you guys think? I'm also open to suggestions for next week's theme.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #25 Posted: Mon May 08, 2017 12:11 am 
Gosei

Posts: 1348
Location: Finland
Liked others: 49
Was liked: 129
Rank: FGA 7k GoR 1297
BTW, is it possible to submit solutions after the round has closed and to get feedback whether the solution would have been accepted? There are some problems I'd like to try, but I don't usually (read: ever) have time to do those within set timeframe. I might try during e.g. summer vacation, though.

_________________
Offending ad removed

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #26 Posted: Mon May 08, 2017 3:12 am 
Lives with ko

Posts: 125
Liked others: 13
Was liked: 12
Rank: KGS 5 kyu
So thank you Solomon for arranging this! It was fun even though I had little time to take part. (I'd ask for an earlier start next time in order for us living in GMT+ countries to be able to start Friday night)

Spoiler from here on...
Problem B: after my initial naive approach I decided to cut the string to n pieces (n going 2,3,4,5...) and see if the pieces are identical. If yes, take the piece, drop everything else and start again. At the end multiply the result according to the pieces dropped (i.e.: if I find that cutting to 3 works and then cutting that 1/3 to 2 pieces again works, the multiplier is 6).
What was the final realization for me is that I only needed to check for prime number n-s (as there is no way a string can have 4 repetition when there is no 2). This I found a bit absurd because there is knowingly no quick way to check for primes. Still my clumsy naive implementation of prime number checking yielded the key to solve this problem.

Problem C: at first I implemented a huge recursive multi level loop to evaluate every permutation (so that order matters) of selected k items (where k is 1 to count of all items). The "))((" test case item really freaked me out and I'm so glad that it was among the examples.
Then later I came up with a formula that allowed me to verify a set of selected k items without trying all the permutations but I still needed to try out all possible sets of k items (where k is 1 to count of all items).
I then added a few optimizations (e.g. going with k from count of all items down to 1 and exiting if for whatever k I found a working set). I also noticed that I can freely drop items that (evaluating from left to right) never have fewer '('-s than ')'-s and have equal number of '('-s and ')'-s as I can always append them without ruining the balance. So I dropped them and added their length to the solution.
But then I was still running out of time on test case 3. I added a few more early checks (return 0 if every item has more '('-s than ')'-s or the other way around), improved my naive "get k of n in every permutation" loop, but then I ran out of ideas. The .net fiddle page started freezing on me, and it was 2:30AM so I called it a day, but I'm very curious what I could have missed.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #27 Posted: Mon May 08, 2017 3:58 am 
Lives with ko

Posts: 259
Liked others: 46
Was liked: 116
Rank: 2d
ugoertz wrote:
For the curious, I put my solutions/attempts on github: https://github.com/ugoertz/l19contest. Comments welcome!


I was thinking of doing something like this after the first round, but decided against it - having the solutions googleable kind of breaks the concept of contest web sites. On the other hand, it is nice to be able to discuss each other's approaches and solutions. Hmm. (I clearly need to learn Python better, I can't even tell what you're doing in some of these.)

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #28 Posted: Mon May 08, 2017 4:04 am 
Lives with ko

Posts: 259
Liked others: 46
Was liked: 116
Rank: 2d
Solomon wrote:
About to go to sleep, will post what I managed to solve in the morning


I'll let you go first this time and post at my thoughts later if I have anything to add. Still thinking about putting up source.

Quote:
I'm thinking maybe for next round, to put up 2 easy, 2 medium, 2 hard instead of 1 easy, 1 medium, and 3 hard. What do you guys think? I'm also open to suggestions for next week's theme.

Sounds like a good plan, but to me it felt like this week we had trivial/easy/medium/hard/hard-ish. I'm not sure we need more than one instance of things like bishops or autori each week.

What themes are available?

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #29 Posted: Mon May 08, 2017 4:06 am 
Lives with ko

Posts: 259
Liked others: 46
Was liked: 116
Rank: 2d
peti29 wrote:
What was the final realization for me is that I only needed to check for prime number n-s (as there is no way a string can have 4 repetition when there is no 2). This I found a bit absurd because there is knowingly no quick way to check for primes.
There's a well-known algorithm to generate a list of primes in advance.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #30 Posted: Mon May 08, 2017 8:01 am 
Lives in sente

Posts: 902
Location: Fort Collins, CO
Liked others: 319
Was liked: 287
Rank: AGA 3k
Universal go server handle: jeromie
I thought the difficulty level was ok. Problem A was trivial. Problem B was in the sweet spot where a naive implementation would not work but optimization wasn't too difficult, so that was fun. I didn't solve problem C, but it didn't seem out of reach - just a bit hard. I've only got a few hours each evening where I can work on the problems (and I have to split that time with playing go ;-) ), so I think solving two problems is fairly reasonable.


On problem B:
My optimization was to factor the length of the input string and then only check substrings that were equal in length to one of the factors. I didn't check in advance, but the maximum number of factors of a number n can be given by the equation 2**(1.5379 * (log(n)/log(log(n)))), which comes out to a max of 4457 factors at the test case limit of 2 million. The average case will be smaller, but even in the worst case that's not too many cases to check in the allotted time.


On problem C:
Like peti29, I implemented a recursive backtracking solution that worked on small data sets but didn't handle the test input. That's actually not surprising.
A lot of problems in programming competitions like this seem like they can be solved with backtracking, but that is almost always the wrong approach. Backtracking is generally O(n!), which blows up the problem space very, very quickly unless you can find a way to severely prune the search tree. I could prune the tree significantly for the average case, but I'm sure the test cases included adversarial input designed to foil most common pruning strategies.

I suspect that there is a numeric solution that doesn't involve ordering the strings at all. I have some idea of the proper data representation (all you need to know about each string is the number of unmatched open parentheses, the number of unmatched closed parentheses, and the length of the string), and some important simplifications (the total number of open and closed parentheses must match, any substrings that consist of matched parentheses can add their length to the solution without further impacting the search space), but I never had the flash of insight that usually accompanies the discovery of the proper algorithm.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #31 Posted: Mon May 08, 2017 8:13 am 
Dies in gote
User avatar

Posts: 63
Liked others: 0
Was liked: 40
bernds wrote:
ugoertz wrote:
For the curious, I put my solutions/attempts on github: https://github.com/ugoertz/l19contest. Comments welcome!


I was thinking of doing something like this after the first round, but decided against it - having the solutions googleable kind of breaks the concept of contest web sites.


I was also wondering whether this is frowned upon, but I do not think that google will find these attempts too easily. Also, if one wants to cheat then there are other possibilities (e.g. I just googled one of the problems to check whether the solution is already available and found that the hidden test cases can be found (assuming that kattis uses the same ones as the original contest which seems very likely), and on the corresponding page there is even a notice that solutions will be posted at some later point).

Does this seem reasonable or do people disagree? I for one would surely like to have a look at your solutions.

Ulrich

_________________
u-go.net

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #32 Posted: Mon May 08, 2017 8:40 am 
Honinbo

Posts: 10905
Liked others: 3651
Was liked: 3374
Some comments on problem 2. :)

Hidden for courtesy.

How to limit the size of n?

The following assumes that the whole string has been read and that an array or arrays or a dictionary is used.

Let Length be the length of the string. Length mod n = 0.

Let Count(char) be the number of occurrences of char in the string. For each character, Count(char) mod n = 0.

That means that we may be able to use the Greatest Common Denominator (GCD) to limit the size of n before matching substrings. We have

n(max) = GCD(Count(“a”), Count(“b”), . . . , Count(“z”))

Since Length = ∑ Count, we can replace one of the Counts with Length. For instance, if Length is a prime, we know that n(max) is Length or 1, but if we only look at the Counts, we may not realize that for some time. For instance, with Length = 7, the Counts (leaving out 0s) might be (2,2,3).

It is a good idea, I think, to sort the Counts and start with the minimum non-zero Count to find the GCD.

Let’s apply all this to the example strings.

String = “abcd”
Length = 4
Count(”a”) = 1
n(max) = GCD(1,4) = 1
n = 1

String = “aaaa”
Length = 4
Count(“a”) = 4
n(max) = GCD(4,4) = 4

String = “ababab”
Length = 6
Count(“a”) = 3
n(max) = GCD(3,6) = 3 ; Note that we do not need to check Count(“b”). It is redundant.

In the next example, let’s just use the numbers.

Length = 48
Count(“a”) = 18
Count(“b”) = 30
n(max) = GCD(18,48) = 6 ; Again, we do not have to make use of Count(“b”).

Can we also make use the number of occurrences of digrams? With a possible Length of 2,000,000 that might help. The answer is yes, with a twist. Let’s look at the last example:

String = “ababab”

Count(“ba”) = 2
Count(“ab”) = 3
n(max) = GCD(2,3) = 1

This is plainly wrong. We cannot use the GCD of the number of occurrences of “ab” and “ba”. The reason is that “ba” does not belong to the repeating substring. The “b” belongs to one substring while the “a” belongs to the next substring. In fact, in this case Count(“ba”) = n-1. It could also equal the count of “ba” in the repeating substring plus n-1. In either case, if we add 1 to it, we can use it, as adding n to a count does no harm. Let’s do that.

GCD(inc(2),3) = 3

So far, so good. But how do we do know whether to add 1 to Count(“ab”) or to Count(“ba”)? Easy. “a” is the first letter in String, and “b” is the last letter. That tells us that “ba” marks the boundaries between repeating substrings.

Now, when we use digrams, we add 1 to the Count of the digram whose first character is the last character in String and whose second character is the first character in String. When we do that, the sum of the counts = Length, as it should.

In this case the digrams give us no reduction of n(max) from the result we get using single letters.

But let’s look at this example:

String = “abbaab”

Using single characters:

Count(“a”) = 3
Count(“b”) = 3
n(max) = GCD(3,3) = 3

Using digrams:

The sorted Counts:

Count(“aa”) = 1
Count(“bb”) = 1
Count(“ba”) = 1
Count(“ab”) = 2

n(max) = GCD(1,1,2,2)) = 1 ; We add 1 to Count(“ba”)
n = 1

OC, in this case we do not have to make the full computation. In fact, since Count(“bb”) = 1, we don’t need to calculate any GCD at all. ;)

Note that even if we get a lower limit for n with the digrams than we do with the single character counts, we may be able to use the single character count result to reduce the limit even further. It does not hurt to start with the single character counts.

String = “abaabababaabacbabaababababaacb”
Length = 30 ; Chosen because of its number of divisors ;)

Count(“c”) = 2
Count(“b”) = 12
Count(“a”) = 16
n(max) = GCD(2,12,16) = 2

Count(“ac”) = 2
Count(“cb”) = 2
Count(“aa”) = 4
Count(“ab”) = 10
Count(“ba”) = 11 ; Add 1 to this

n(max) = GCD(2,2,4,10,12) = 2

This example is meant to illustrate the virtue (I hope) of this approach. The string is perhaps deceptive in part because of so many repetitions of the initial and final parts of the string (the “a”s and “b”s). That means that if we are working down the candidate substrings, we will get early matches, whether we work from the front or the back. There are also a lot of potential “ba” boundaries between substrings. But that means that there are a lot of “a”s and “b”s, but relatively few “c”s. It is the paucity of “c”s that puts a cap on n. With only 2 “c”s n(max) = 2, while using the counts of only “a” and “b” gives us an n(max) of 4.

OC, as always, the proof is in the pudding. :)

_________________
The Adkins Principle:
At some point, doesn't thinking have to go on?
— Winona Adkins

Visualize whirled peas.

Everything with love. Stay safe.


Last edited by Bill Spight on Tue May 09, 2017 7:36 am, edited 1 time in total.
Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #33 Posted: Mon May 08, 2017 9:26 am 
Honinbo

Posts: 9545
Liked others: 1600
Was liked: 1711
KGS: Kirby
Tygem: 커비라고해
One thing I've learned from this competition is that the theme doesn't really matter much. Sometimes solving a "recursive" problem isn't really focused on the recursion part, or sometimes solving a "string" problem isn't really about strings. Solving these problems require general problem solving skills, because almost always, it's not so much about solving the problem "correctly", but rather about solving it fast and with a low amount of memory.

Anyway, while I haven't been able to spend as much time as I'd like on this competition, I still appreciate it - I end up programming more than I would otherwise over the weekend :-)

_________________
be immersed

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #34 Posted: Mon May 08, 2017 10:04 am 
Honinbo

Posts: 10905
Liked others: 3651
Was liked: 3374
Kirby wrote:
almost always, it's not so much about solving the problem "correctly", but rather about solving it fast and with a low amount of memory.


Sort of like playing online go. :mrgreen:

_________________
The Adkins Principle:
At some point, doesn't thinking have to go on?
— Winona Adkins

Visualize whirled peas.

Everything with love. Stay safe.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #35 Posted: Mon May 08, 2017 10:38 am 
Lives in sente
User avatar

Posts: 842
Liked others: 180
Was liked: 151
Rank: 3d
GD Posts: 422
KGS: komi
I found A trivial, B perfect, C-E too difficult. I realize to some extent the choice is guided by the Kattis ratings, which rated B a 6.4, C a 7.3 and D 5.8. I think the submission statistics can be some guide about the accuracy of the ratings - B and C had many submissions (100s) while D had very few (<10).

I'm not fussed about theme. Perhaps a theme around the solution mechanisms might be interesting (recursion, DP, etc), if available.

Thanks for setting this, it's very enjoyable.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #36 Posted: Mon May 08, 2017 10:41 am 
Lives in sente

Posts: 902
Location: Fort Collins, CO
Liked others: 319
Was liked: 287
Rank: AGA 3k
Universal go server handle: jeromie
Bill Spight wrote:
Kirby wrote:
almost always, it's not so much about solving the problem "correctly", but rather about solving it fast and with a low amount of memory.


Sort of like playing online go. :mrgreen:


These contests are remarkably like solving tsumego. In particular, the nature of the problem changes considerably when you know there is a solution before tackling the problem.

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #37 Posted: Mon May 08, 2017 1:26 pm 
Gosei
User avatar

Posts: 1848
Location: Bellevue, WA
Liked others: 90
Was liked: 837
Rank: AGA 5d
KGS: Capsule 4d
Tygem: 치킨까스 5d
Problem A
Code:
print("".join(word[0].upper() for word in input().split('-')))


Problem B
The way I approached this problem was to utilize the preprocessing function from the KMP algorithm (call it kmp_pre). Specifically, the function calculates for every index of a pattern P, the length of the longest border (substring that is both a prefix and a suffix) found up to that index. For example, kmp_pre('aabbaabb') = [0 1 0 0 1 2 3 4], and kmp_pre('ababab') = [0 0 1 2 3 4].

If however, instead of running kmp_pre on P, we run it on P + P, then the border length found at an index equal to the size of P tells us the length of the period len(period) := i - kmp_pre[i] + 1, and the value of n from the problem statement would just be len(P) / len(period). A way of visualizing this is to imagine P on two pieces of tape, and you're trying to align them such that the borders align, the length of the gap ('<>') on the left telling you the length of 'a' in the problem statement (s = a^n):
Code:
aabbaabbaabbaabb
||||||||
aabbaabb (aligns, but this is the trivial case)
aabbaabb
  aabbaabb
   aabbaabb
    aabbaabb (aligns)
<  >||||||||
aabbaabbaabbaabb

abababababab
||||||
ababab (aligns, trivial)
ababab
  ababab (aligns)
<>||||||
abababababab

abcdabcd
||||
abcd (aligns, trivial)
abcd
  abcd
   abcd
    abcd (aligns)
<  >||||
abcdabcd

Example 1: let P = aabbaabb => len(P) = 8. Then kmp_pre(P + P) = [0 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12]. At i = 11, the border length of P + P == 8, i.e, that aabbaabbaabb = P + aabb has a substring of length 8 that is both a prefix and a suffix (P), so len(a) = 11 - 8 + 1 = 4. Then n = len(P) / len(a) = 8 / 4 = 2.

Example 2: let P = ababab => len(P) = 6. Then kmp_pre(P + P) = [0 0 1 2 3 4 5 6 7 8 9 10]. At i = 7, the border length of P + P == 6, so len(a) = 7 - 6 + 1 = 2. Then n = len(P) / len(a) = 6 / 2 = 3.

Example 3: let P = abcd => len(P) = 4. Then kmp_pre(P + P) = [0 0 0 0 1 2 3 4]. At i = 7, the border length of P + P == 4, so len(a) = 7 - 4 + 1 = 4. Then n = len(P) / len(a) = 4 / 4 = 1.

Code:
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <cmath>

std::vector<int> kmp_preprocess(const std::string &pattern) {
    int pattern_sz = (int) pattern.size();
    std::vector<int> border_array(pattern_sz, 0);
   
    int prev = 0;
    int curr = 1;
    while (curr < pattern_sz) {
        if (pattern[curr] == pattern[prev]) {
            border_array[curr] = prev + 1;
            ++prev;
            ++curr;
        } else if (prev > 0) {
            prev = border_array[prev - 1];
        } else {
            ++curr;
        }
    }

    return border_array;
}

int main() {
    while (true) {
        std::string s;
        std::cin >> s;
        if (s == ".") break;

        std::vector<int> kmp_prefix = kmp_preprocess(s + s);
       
        int s_sz = (int) s.size();
        int res = 0;
        for (int i = 0; i < (int) kmp_prefix.size(); ++i) {
            if (kmp_prefix[i] == s_sz) {
                res = i - kmp_prefix[i] + 1;
            }
        }
        std::cout << s_sz / res << std::endl;
    }
}


Problem C
Intuitively I knew this was a DP problem, but problem was getting the state and the transition correct. For the state, several pieces of information is necessary. Start with size and balance...

  • size: just the length of the string
  • balance: counter to keep track of difference between number of ('s vs )'s. e.g., ()()()'s balance = 0, ((('s balance = 3, ()(())(('s balance = 2.

If we utilized just these two pieces of information and ran DP with it, that would be ideal, and it would handle a lot of cases like ['(((', ')))'] or ['(())((', ')))', '(()', '(((())']. However, what this doesn't handle is differentiating between something like (()) versus ))((, both of which would have a balance of 0 and same size, but clearly must be handled differently (the first case is "free", the second one not so much...). So a third piece of information (call it 'offset') is needed, which is always <= 0 and counts the number of )'s that come before a positively balanced chunk, or the number of ('s that come after a negatively balanced chunk. So (()) would have an offset of 0, but ))(( would have an offset of -2. It's worth noting that if we are only dealt chunks with negative offsets, then we can't merge any chunks together. In the case of ))((, we would need something (one of many examples) like (( (balance +2, offset 0) and )) (balance -2, offset 0) to merge with. Hence, when we sort these chunks, we need to sort by offset (descending) first to find the ones with 0 offset, before looking balance and size.

That's pretty much the hard part, the DP is simpler:
Code:
memo[i + chunk.balance] = max(memo[i + chunk.balance], memo[i] + chunk.size)

We keep track of two memo tables: one for positively balanced chunks, one for negatively balanced chunks. After that, we go through the memo tables and find the highest aligned value between them, and that's the answer.
Code:
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#define MAX_N 300
#define MAX_S 300
#define MAX_V (MAX_N * MAX_S) + 5

class ParenChunk {
public:
    int size;
    int balance; // 0 = balanced, count( '(' ) > count( ')' ) => balance > 0
    int offset;

    ParenChunk(std::string raw_paren_str) {
        size = raw_paren_str.size();
        balance = 0;
        offset = 0;

        for (const char &c : raw_paren_str) {
            if (c == '(')
                ++balance;
            else
                --balance;
            offset = std::min(offset, balance);
        }

        if (balance < 0) {
            // recount offset because it has to be done in reverse ( '))(' )
            int rebalance = 0;
            offset = 0;
            for (auto it = raw_paren_str.rbegin(); it != raw_paren_str.rend(); ++it) {
                if (*it == '(')
                    --rebalance;
                else
                    ++rebalance;
                offset = std::min(offset, rebalance);
            }
        }
    }

    bool operator< (const ParenChunk &p) const {
        if (offset != p.offset)
            return offset > p.offset;
        if (balance != p.balance)
            return std::abs(balance) > std::abs(p.balance);
        return size > p.size;
    }

    int get_balance_magnitude() const {
        return std::abs(balance);
    }
};

std::ostream &operator<<(std::ostream &strm, const ParenChunk &p) {
    return strm << '('
                << std::to_string(p.size)    << ", "
                << std::to_string(p.balance) << ", "
                << std::to_string(p.offset)
                << ')';
}

void run_dp(const std::vector<ParenChunk> &v, std::vector<int> &memo) {
    for (const auto &p : v) {
        int p_bal = p.get_balance_magnitude();
        for (int i = MAX_V - 1 - p_bal; i >= -p.offset; --i) {
            if (memo[i]) {
                memo[i + p_bal] = std::max(memo[i + p_bal], memo[i] + p.size);
            }
        }

        if (p.offset == 0)
            memo[p_bal] = std::max(memo[p_bal], p.size);
    }
}

void process_input(std::vector<ParenChunk> &pv, std::vector<ParenChunk> &nv) {
    int n;
    std::cin >> n;

    while (n--) {
        std::string raw_paren_str;
        std::cin >> raw_paren_str;
        ParenChunk paren_chunk{raw_paren_str};
        if (paren_chunk.balance >= 0) {
            pv.push_back(paren_chunk);
        } else {
            nv.push_back(paren_chunk);
        }
    }
}

int main() {
    std::vector<ParenChunk> positively_balanced;
    std::vector<ParenChunk> negatively_balanced;
    positively_balanced.reserve(MAX_N);
    negatively_balanced.reserve(MAX_N);

    process_input(positively_balanced, negatively_balanced);

    std::sort(positively_balanced.begin(), positively_balanced.end());
    std::sort(negatively_balanced.begin(), negatively_balanced.end());

    std::vector<int> positively_memo(MAX_V);
    std::vector<int> negatively_memo(MAX_V);
    run_dp(positively_balanced, positively_memo);
    run_dp(negatively_balanced, negatively_memo);

    int res = positively_memo[0] + negatively_memo[0];
    for (int i = 1; i < MAX_V; ++i) {
        if (positively_memo[i] && negatively_memo[i]) // match
            res = std::max(res, positively_memo[i] + negatively_memo[i]);
    }

    std::cout << res << std::endl;
}


This post by Solomon was liked by: peti29
Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #38 Posted: Mon May 08, 2017 1:34 pm 
Honinbo

Posts: 9545
Liked others: 1600
Was liked: 1711
KGS: Kirby
Tygem: 커비라고해
Cool, Solomon. Re: KMP, figures that Knuth has already solved the problem for us :-) Re: Problem C, I didn't spend much time on this problem since it looked difficult given the time I would spend on the problem, but I came up with the idea of using your idea of "balance" as a metric. However, once I saw that it didn't always work with a counter example, I gave up on that idea, and started looking at the next problem. It didn't occur to me to consider the "offset".

_________________
be immersed

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #39 Posted: Mon May 08, 2017 1:38 pm 
Gosei
User avatar

Posts: 1848
Location: Bellevue, WA
Liked others: 90
Was liked: 837
Rank: AGA 5d
KGS: Capsule 4d
Tygem: 치킨까스 5d
Leaderboard

  1. bernds - 11
  2. dfan - 9
  3. ugoertz - 8
  4. Solomon - 7
  5. quantumf - 3
  6. Kirby - 2
  7. jeromie - 2
  8. peti29 - 2
  9. gamesorry - 1

Some theme ideas for round 3:
  • Graphs
    • Graph Traversal
    • Single-Source Shortest Paths
    • Minimum Spanning Trees
    • Network Flow
  • Computational Geometry
    • Circles, points, triangles, and lines
    • Polygons
  • DP
    • Knapsack variations [0/1, 0/inf, etc.]
    • Coin change variations
    • Longest increasing subsequence (LIS) variations
    • TSP
  • Math
    • Probability theory
    • Number theory
      • Primes
      • Catalan number variations
      • Fibonacci number variations

If I don't get any suggestions, I'll just go with graphs on Friday. Also, for next round, I'll have it start in the morning on Friday in PST time so that it will be around 18:00 in Europe!

Top
 Profile  
 
Offline
 Post subject: Re: L19 Programming Problem Championship: Round 2
Post #40 Posted: Mon May 08, 2017 2:22 pm 
Lives with ko

Posts: 259
Liked others: 46
Was liked: 116
Rank: 2d
Solomon wrote:
Problem B
The way I approached this problem was to utilize the preprocessing function from the KMP algorithm (call it kmp_pre).
This is just equivalent to searching for S withing S+S (and ignoring the first match), right? I get the feeling this is how it was intended to be solved. I just went with the factorization. The interesting thing is that your solution looks like it should be more efficient, but runs slightly slower in practice in my tests. This is something I'll probably spend time on to try to understand - is C++ string handling that inefficient?


Quote:
Problem C
So a third piece of information (call it 'offset') is needed, which is always <= 0 and counts the number of )'s that come before a positively balanced chunk, or the number of ('s that come after a negatively balanced chunk.
Yes, that matches what I did. I found that if I sort this data correctly, I can just run the DP algorithm over all of it once and get the right answer at the end.


Here's what I did for Problem E:
It's relatively simple to write a recursive algorithm to generate an alphabetical sequence that matches the requirements. You have to keep track of what the previous character was, and how many characters have been used i times for 1 <= i <= k (and set limits as appropriate).
My first attempt at speeding it up was to recognize that the fact that we're duplicating a lot of patterns if we're going through the whole alphabet. If at any point we're choosing a new character that hasn't been seen before, we can remember how many substrings the recursive calls generated, and then any other choice of new characters will generate the same number. As long as that number is smaller than the remaining count, we can skip the recursive call and just subtract.
This turns out to work great for small k such as in the examples, where we always choose many different new characters, but for large k (approaching 26) it becomes less effective, and here we need speedups the most. So in the end I didn't end up using this. Instead, I recognize when the subproblem becomes suitably small (all character counts above 9 fully used up), and encode the pattern of remaining counts into an index into an array of shortcuts. The idea is the same: if we encounter a similar situation twice, we can skip recursion after the first time.
Graphs seems like a good choice, better go read up on a few things. I'd also like to thank you for running these. Kirby says he does more programming on weekends this way than he would otherwise; I'll go so far as to say it's more fun than most of the things I get to do during the week doing software professionally these days. It's good to encounter problems unlike the typical ones you see every day.


This post by bernds was liked by: Solomon
Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 54 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group