On November 23, the 2018 Sogang University Programming Contest was held for 3 hours. It's an individual ACM-ICPC style algorithm contest held every year for Sogang University undergrads. This is its 14th year. (2016 was the 12th, so this year is probably the 14th..? Not totally sure, but it should be)
There's the Master division, open only to freshmen and sophomores, and the Champion division, open to all years. I'm a freshman without much offline contest experience, so I entered the Master division. Since I'll be the president of the algorithm club starting next year, this might be my first and last time taking part in the school contest as a contestant 😄
There were 6 problems per division, 12 in total. You can try the open contest on Baekjoon Online Judge. The Master division got problems A, C, D, E, G, and I from the open contest, and the Champion division got B, F, H, J, K, and L.

Over the summer I worked as balloon staff at the 2018 Union of Collegiate Programming Clubs Contest (UCPC 2018), tying balloons to contestants' desks, and this time I was on the receiving(?) end of the balloons. When I was tying them, I was a bit worried it might distract the contestants, but once I was the one solving problems, it turned out to be less distracting than I thought!
When lots of balloons go up, the contest hall looks pretty. I love this culture!
It was a bit of a shame that I couldn't use Kotlin at the contest. Kotlin is my main language, and over 90% of the problems I've solved on BOJ were in Kotlin. But I'd gotten fairly used to C++ from studying with the club, so it wasn't really a problem. As for Kotlin, I'd like to settle for using it at the ICPC World Finals if I ever get there and hogging all of JetBrains' attention. Though, well, I'd have to actually make it to the World Finals first..
Anyway, enough rambling from a freshman at his first contest like this, let's talk about the problems!
The problems
Warning: solutions below.
The solutions are in the order I solved the problems.
C. 어려운 소인수분해 (Hard Prime Factorization) / BOJ #16563
Surprisingly, the solution for A didn't come to me right away, so I started with C. I was confident with the Sieve of Eratosthenes.
Since the input is a natural number between 2 and 5 million, I first precompute the primes up to with the Sieve of Eratosthenes. During the contest, instead of taking the exact square root of 5 million, I just went with roughly 3000. Since , you get a bit under 350 primes.
Read some number n. Now for each prime p, divide n by p until it's no longer divisible by p, printing p each time. Increase p starting from 2, and once n becomes smaller than , conclude it can't be divided by p anymore and break out of the loop. If n still isn't 1 after trying every prime up to 2236, the remaining n is itself prime, so print n as well. This way, even with a million numbers to factorize, the number of primes p you try dividing by is small, so there's nothing to worry about. First solve 9 minutes into the contest.
A. 3의 배수 (Multiples of 3) / BOJ #16561
Surprisingly, I spent a lot of time on this one because I misunderstood the problem at first. You're supposed to split into 3 natural numbers, but I missed that and read it as just the number of ways to partition a natural number. Anyway.
If you read the problem, you'll notice n being a multiple of 3 doesn't really mean much, right? It's really the same as splitting into 3 natural numbers. But it says the order matters. How should we split it?
First, there's only one way to split 3 into 3 parts: 1 + 1 + 1. Splitting 4 into 3 parts gives 3 ways by rearranging 2 + 1 + 1, splitting 5 into 3 parts gives 6 ways by rearranging 3 + 1 + 1 and 2 + 2 + 1… So we could think of this as finding the number of ways to distribute balls into 3 distinct boxes with at least 1 in each! This equals the combination with repetition
. Working it out, it's simply
, and solving it this way gets you AC!
Of course, I forgot my high school probability and statistics ages ago, so I split 3, 4, 5, and 6, saw I got 1, 3, 6, and 10, thought 'this must be some nCr!', coded it right away, and it was accepted. Accepted 14 minutes into the contest.
B. 친구비 (Friend Fee) / BOJ #16562
It was a simple graph problem. Find the connected components and add up just the minimum value of each. It doesn't really matter whether you find the components with BFS or DFS, and since you visit every node only once, it's solved in in no time. Just print “Oh no” only when this sum exceeds K. Accepted 21 minutes into the contest.
D. 히오스 프로그래머 (HotS Programmer) / BOJ #16564
I solved it by binary searching the team's target level T between 0 and . Actually, during the contest I didn't bother with the theoretical maximum of T and searched between 0 and . For some reason I just couldn't get a feel for how far the range should go..
At each step of the search, I compared K with the total levels you'd need to raise for a target level of T. N is at most a million and K is at most a billion, so using int would overflow, right? Of course I used long long.
Computing the total levels to raise is , and searching for the target level T is . So this problem is also solved in linear time. Got one WA from setting the binary search range wrong, then first solve 32 minutes into the contest.
E. N포커 (N-Poker) / BOJ #16565
A probability and statistics problem. I think I ended up scribbling a lot of numbers on the problem sheet.
Let's take picking 7 cards as an example. In the figure from the problem, pick one of the 13 vertical columns, then pick 3 of the remaining 48 cards. In this case, the number of ways is
in total.
But what if you pick 11? If you pick one column from the figure and then pick 7 of the remaining 48 cards, those 7 cards might form another column. In that case, subtract the cases where you pick two columns and then 3 of the remaining 44 cards. The number of ways comes out to
!
What about picking 15? If you think like above, subtracting the duplicates also removes the cases with 3 columns. So if you add back the cases with 3 columns, you get
ways.
You get the idea by now, right? Looks like we can generalize. Looking at the pattern above, for any n the number of ways we want seems to be
, and it actually is!
Computing the binomial coefficients is another issue: you can't get them by computing factorials and dividing. long long only goes up to , and already blows way past that range, so computing the from above is out of the question. long double has a bigger range than long long, but once it gets really big its precision is worse than long long's. Instead, using the recurrence
, you can precompute binomial coefficients for n ≤ 52, k ≤ 52, k ≤ n with dynamic programming. The numbers might get too big, but since we only need to print the result modulo 10,007 anyway, by the properties of modular arithmetic you can just store every binomial coefficient modulo 10,007 when precomputing.
With these precomputed binomial coefficients, whatever n comes in, you only add up at most 13 terms, so it's solved in . Got 3 WAs from writing the formula wrong before getting it right, then first solve 1 hour 1 minute into the contest.
F. 카드 게임 (Card Game) / BOJ #16566
I found out later that this problem was originally planned as problem F of the Champion division. But apparently they thought this one was easier, so they swapped Champion's F and Master's F. (No wonder there were two card problems in a row)
Anyway, at first I thought 'oh, is this a binary search tree..?' and spent about 10 minutes trying to implement one, but I'd practiced trees way too little (plus, as I mentioned above, I rarely had to write structs in C++ because I was doing Kotlin), so I gave up, thought 'well, my original goal was just to place in the top 5 anyway,' and kind of threw a solution at it. And it was accepted!! I think the test data was a bit weak.
First, sort the cards Minsu took. Then make a flag array that stores whether each of the M cards has been used. Now, letting x be the value of the card Cheolsu plays, find x + 1 among Minsu's cards with lower_bound. If it hasn't been used yet, print it right away. If it has, keep incrementing the index by one until you hit an unused card, and print it when found.
Actually, this approach is in the worst case, a complexity where getting TLE wouldn't be surprising. I think I just got lucky! It's hard to say I properly solved the problem, but anyway, first solve 1 hour 47 minutes into the contest.
Apparently the intended solution uses index sort. It seems possible because M ≤ N ≤ 4,000,000; I should solve it again the intended way.
I solved all 6 problems and won the Master division. Since it's probably my first and last school contest as a contestant, winning it means a lot to me personally. Great job to all the contestants and problem setters. Thanks to the organizers for putting together a great contest!
I had a hard time when backspace stopped working in the middle of coding (turns out some international students had changed the keyboard language settings to their own languages), but my first offline contest in a while was so much fun. I'll probably be a problem setter starting next year, and I'll work hard to make a contest everyone can enjoy 😊
Great job, everyone! 🎈













































