CF 104790D - Democratic Naming
Every city in the new county has a name of the same length. The county's final name is chosen one character at a time. For each position, every city votes for the letter that appears at that position in its own name.
CF 104790D - Democratic Naming
Rating: -
Tags: -
Solve time: 1m 15s
Verified: yes
Solution
Problem Understanding
Every city in the new county has a name of the same length. The county's final name is chosen one character at a time. For each position, every city votes for the letter that appears at that position in its own name. The letter with the highest number of votes becomes the corresponding letter of the county name. If several letters receive the same highest number of votes, the alphabetically smallest one is selected.
The input consists of the number of cities, the common length of every city name, and then the names themselves. The required output is the single name produced by applying the voting rule independently at every character position.
The constraints are fairly small. There are at most 1000 city names, each containing at most 1000 characters. This means there are at most one million input characters in total. Any algorithm that processes each character once or a constant number of times easily fits within typical contest limits. Algorithms that repeatedly rescan all strings for every possible answer would still be acceptable here, but there is no reason to do extra work when a direct counting solution exists.
The first non-obvious edge case is a tie between multiple letters. Consider the input
2 1
b
a
Both letters receive one vote, so the correct output is
a
A careless implementation that simply keeps the first maximum encountered would incorrectly output b.
Another case is when every city has the same name. For example,
3 4
code
code
code
The answer must be
code
Since every position has unanimous agreement, no tie-breaking logic should interfere.
A final case is when every position has a different winner. For example,
3 3
abc
bbc
cac
The output is
abc
Each column must be processed independently. Combining information from different positions would produce the wrong result.
Approaches
The most direct solution is to process each position separately. For one column, count how many times each letter appears among all city names, then choose the letter with the highest frequency. If several letters have the same frequency, choose the alphabetically smallest one. Repeating this for all positions produces the required answer.
This approach already performs only one pass over every input character. Since there are at most one million characters, the total work is about one million counting operations plus checking the 26 lowercase letters for every position. That is easily fast enough.
The key observation is that every character position is completely independent from every other position. The decision for the first letter never affects the decision for the second letter. Because the alphabet contains only 26 lowercase letters, maintaining a frequency array of size 26 for each column is both simple and efficient.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n × m × 26) | O(26) | Accepted |
| Optimal | O(n × m + 26 × m) | O(26) | Accepted |
Although both rows have essentially the same asymptotic complexity because the alphabet size is constant, the frequency-counting formulation is the natural and intended solution.
Algorithm Walkthrough
-
Read the values of
nandm, then store all city names. -
Create an empty list that will hold the characters of the final county name.
-
For every character position from
0tom - 1, create a frequency array of length 26 initialized to zero. -
Visit every city name and increment the counter corresponding to the letter appearing at the current position.
Each city contributes exactly one vote to the current column, so after this pass the frequency array contains the complete election result for that position.
-
Scan the 26 counters in alphabetical order and keep track of the letter with the largest frequency.
Because the scan is performed from
'a'to'z', updating the answer only when a strictly larger frequency is found automatically keeps the alphabetically smallest letter whenever frequencies are tied. -
Append the selected letter to the answer.
-
After all positions have been processed, join the collected letters into a string and print it.
Why it works
For every position, the algorithm counts exactly how many votes every possible letter receives. These counts exactly match the definition of the election. Choosing the letter with the largest count satisfies the majority rule, and scanning letters in alphabetical order guarantees that ties are resolved in favor of the smallest letter. Since every position is processed independently, every character of the constructed name is correct, making the entire output correct.
Python Solution
import sys
input = sys.stdin.readline
n, m = map(int, input().split())
names = [input().strip() for _ in range(n)]
answer = []
for col in range(m):
freq = [0] * 26
for name in names:
freq[ord(name[col]) - ord('a')] += 1
best = 0
for i in range(1, 26):
if freq[i] > freq[best]:
best = i
answer.append(chr(best + ord('a')))
print("".join(answer))
The program begins by reading all city names so every column can be accessed efficiently.
For each column, it creates a fresh frequency array with one entry for every lowercase letter. Every city contributes one vote by incrementing the appropriate counter.
The variable best stores the index of the current winning letter. The scan begins with 'a' as the initial candidate. The comparison uses > instead of >=. This detail is what implements the tie-breaking rule. When two letters have equal frequency, the earlier one in the alphabet remains selected because it was encountered first.
Finally, the chosen letters are converted back into characters, collected in a list, and joined into the final county name.
Worked Examples
Sample 1
Input
3 5
apple
maple
alpha
| Position | Letters | Winning letter | Answer so far |
|---|---|---|---|
| 0 | a, m, a | a | a |
| 1 | p, a, l | a | aa |
| 2 | p, p, p | p | aap |
| 3 | l, l, h | l | aapl |
| 4 | e, e, a | e | aaple |
The final answer is aaple. The second column demonstrates the tie-breaking rule. The letters a, l, and p each appear once, so the smallest letter, a, is chosen.
Sample 2
Input
3 4
icpc
back
laps
| Position | Letters | Winning letter | Answer so far |
|---|---|---|---|
| 0 | i, b, l | b | b |
| 1 | c, a, a | a | ba |
| 2 | p, c, p | p | bap |
| 3 | c, k, s | c | bapc |
The final answer is bapc. Every column is processed independently, confirming that earlier decisions never affect later ones.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n × m + 26 × m) | Every input character is counted once, then 26 counters are checked for each column. |
| Space | O(26) | Only one frequency array of fixed size is needed besides the input. |
The total number of processed characters is at most one million, and each character is handled exactly once. The extra scan over 26 letters per column is negligible. The algorithm comfortably fits within the problem constraints.
Test Cases
import sys
import io
def solve():
input = sys.stdin.readline
n, m = map(int, input().split())
names = [input().strip() for _ in range(n)]
ans = []
for col in range(m):
freq = [0] * 26
for name in names:
freq[ord(name[col]) - ord('a')] += 1
best = 0
for i in range(1, 26):
if freq[i] > freq[best]:
best = i
ans.append(chr(best + ord('a')))
print("".join(ans))
def run(inp: str) -> str:
backup_stdin = sys.stdin
backup_stdout = sys.stdout
sys.stdin = io.StringIO(inp)
sys.stdout = io.StringIO()
solve()
out = sys.stdout.getvalue()
sys.stdin = backup_stdin
sys.stdout = backup_stdout
return out
# provided samples
assert run("3 5\napple\nmaple\nalpha\n") == "aaple\n", "sample 1"
assert run("3 4\nicpc\nback\nlaps\n") == "bapc\n", "sample 2"
# minimum size
assert run("1 1\nz\n") == "z\n", "single city"
# tie breaking
assert run("2 1\nb\na\n") == "a\n", "alphabetical tie"
# all equal
assert run("3 3\ncat\ncat\ncat\n") == "cat\n", "identical names"
# different winners per column
assert run("3 3\nabc\nbbc\ncac\n") == "abc\n", "independent columns"
| Test input | Expected output | What it validates |
|---|---|---|
| One city with one letter | z |
Minimum input size |
Two names b and a |
a |
Alphabetical tie-breaking |
| Three identical names | Same name | Unanimous voting |
abc, bbc, cac |
abc |
Each column handled independently |
Edge Cases
Consider the tie-breaking example.
2 1
b
a
The frequency array for the only column becomes [1, 1, 0, ..., 0]. The scan starts with 'a' as the current winner. When 'b' is examined, its frequency is equal rather than larger, so the winner is not changed. The output is correctly a.
Now consider unanimous voting.
3 4
code
code
code
Every column contains only one distinct letter. The frequency arrays each have a single maximum, so the selected letters are c, o, d, and e. The algorithm outputs code exactly as expected.
Finally, consider different winners in different columns.
3 3
abc
bbc
cac
The first column has frequencies {a:1, b:1, c:1}, so a wins by alphabetical order. The second column has b appearing twice, making it the winner. The third column has c in every name, making it unanimous. The algorithm never mixes information between columns, producing the correct answer abc.