CF 75B - Facetook Priority Wall
We are given the name of a user on a social network and a sequence of activity messages between users. Every activity contributes a certain number of points between the two people involved.
CF 75B - Facetook Priority Wall
Rating: 1500
Tags: expression parsing, implementation, strings
Solve time: 2m 14s
Verified: no
Solution
Problem Understanding
We are given the name of a user on a social network and a sequence of activity messages between users. Every activity contributes a certain number of points between the two people involved.
The three possible activities are:
- posting on someone's wall, worth 15 points
- commenting on someone's post, worth 10 points
- liking someone's post, worth 5 points
The relationship score is symmetric. If alice comments on bob's post, both alice and bob gain 10 points toward each other.
Our task is not to compute scores between every pair of users. We only care about scores relative to the given user. After processing all actions, we must print every distinct person who appeared in the log, excluding the main user, sorted by descending score with that user. If multiple people have the same score, we break ties lexicographically.
The input format looks simple at first, but the strings are slightly tricky. The second username appears with "'s" attached, such as fatma's. A careless parser that directly stores this token will treat "fatma" and "fatma's" as different names.
The constraints are very small. There are at most 100 actions, and each username is at most length 10. Even an inefficient implementation would pass comfortably. This means the problem is primarily about careful string parsing and bookkeeping, not optimization.
A common mistake is forgetting to include users whose score with the main user is zero.
Consider this input:
ahmed
2
mona likes sara's post
sara commented on mona's post
Neither interaction involves ahmed, so both mona and sara have score 0 with him. The correct output is:
mona
sara
Another easy bug comes from parsing the second username incorrectly.
ahmed
1
ahmed posted on fatma's wall
The correct username is fatma, not fatma's. If we forget to remove the suffix, sorting and score accumulation become wrong because "fatma" and "fatma's" are treated as separate users.
Tie-breaking also matters.
ahmed
2
ahmed likes sara's post
ahmed likes mona's post
Both users receive 5 points, so the output must be:
mona
sara
A solution that sorts only by descending score would produce nondeterministic ordering.
Approaches
The most direct approach is to simulate every action exactly as written. For each line, we extract the two usernames and determine which activity occurred. If the main user participates in the interaction, we add the corresponding value to the other person's score. Meanwhile, we maintain a set of every distinct username that appears.
This brute-force strategy is already fully acceptable because the input size is tiny. With at most 100 lines, even repeatedly scanning strings and sorting names costs almost nothing. The total work is dominated by sorting at most a few hundred names.
The real challenge is not performance but representation. The activity lines have three different sentence structures:
X posted on Y's wall
X commented on Y's post
X likes Y's post
The useful observation is that all formats become easy once we split the line into words. The first token is always X, the second token identifies the action type, and the fourth token contains Y's. Removing the final two characters gives the actual username.
After extracting the usernames and action type, the problem reduces to score accumulation in a dictionary.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n log n) | O(n) | Accepted |
| Optimal | O(n log n) | O(n) | Accepted |
The "optimal" solution is essentially the same because the constraints are already tiny. The important part is organizing the parsing cleanly and sorting correctly.
Algorithm Walkthrough
- Read the main username and the number of actions.
- Create a dictionary that maps each action word to its score.
We use:
"posted"→ 15"commented"→ 10"likes"→ 5
- Maintain a set containing every distinct username except the main user.
This guarantees that even users with zero score appear in the final output. 4. Maintain another dictionary storing scores relative to the main user.
Missing entries are treated as zero. 5. For each action line:
- Split the line into words.
- Extract:
x = words[0]action = words[1]y = words[3][:-2]
The last operation removes the trailing "'s".
- Add both usernames to the set if they are not the main user.
- Look up the score value for the action.
- If
xis the main user, add the score toy. - If
yis the main user, add the score tox.
Because the relationship is symmetric, either direction contributes equally. 6. Convert the set of usernames into a list and sort it using:
- descending score
- lexicographical order as a tiebreaker
- Print the sorted names.
Why it works
The algorithm processes every interaction exactly once. For each action, the only score that matters is the one involving the main user. If neither participant is the main user, the interaction cannot affect the final ranking, so we ignore its score contribution while still recording the usernames.
The score dictionary always stores the total accumulated interaction value between the main user and every other user processed so far. Since every action contributes independently and exactly once, the final dictionary contains the correct totals. The final sorting rule directly matches the statement: higher score first, alphabetical order for ties.
Python Solution
import sys
from collections import defaultdict
input = sys.stdin.readline
def solve():
me = input().strip()
n = int(input())
points = {
"posted": 15,
"commented": 10,
"likes": 5
}
score = defaultdict(int)
people = set()
for _ in range(n):
words = input().split()
x = words[0]
action = words[1]
y = words[3][:-2]
if x != me:
people.add(x)
if y != me:
people.add(y)
value = points[action]
if x == me:
score[y] += value
if y == me:
score[x] += value
result = sorted(people, key=lambda name: (-score[name], name))
print("\n".join(result))
solve()
The points dictionary converts action words into numeric values. This avoids repeated conditional statements and makes the code easier to extend.
The parser relies on the fixed sentence structure. After splitting by spaces, the second username always appears in position 3 with an attached "'s". Slicing with [:-2] removes exactly those two characters.
The people set is separate from the score dictionary because some users may never interact directly with the main user. If we relied only on keys in score, users with zero score would disappear from the output.
Using defaultdict(int) removes the need to initialize missing scores manually.
The sorting key is subtle. We sort by (-score[name], name) instead of sorting twice. Negating the score gives descending numeric order, while the second component automatically handles lexicographical ties.
Worked Examples
Example 1
Input:
ahmed
3
ahmed posted on fatma's wall
fatma commented on ahmed's post
mona likes ahmed's post
Processing trace:
| Step | Action | Extracted Users | Score Changes | Current Scores |
|---|---|---|---|---|
| 1 | ahmed posted on fatma's wall | ahmed, fatma | fatma +15 | fatma: 15 |
| 2 | fatma commented on ahmed's post | fatma, ahmed | fatma +10 | fatma: 25 |
| 3 | mona likes ahmed's post | mona, ahmed | mona +5 | fatma: 25, mona: 5 |
Final sorting:
| Name | Score |
|---|---|
| fatma | 25 |
| mona | 5 |
Output:
fatma
mona
This example shows that interactions contribute regardless of direction. Both actions involving fatma increased the same relationship score.
Example 2
Input:
alex
4
bob likes clara's post
alex likes diana's post
eric commented on frank's post
george posted on alex's wall
Processing trace:
| Step | Action | Extracted Users | Score Changes | Current Scores |
|---|---|---|---|---|
| 1 | bob likes clara's post | bob, clara | none | empty |
| 2 | alex likes diana's post | alex, diana | diana +5 | diana: 5 |
| 3 | eric commented on frank's post | eric, frank | none | diana: 5 |
| 4 | george posted on alex's wall | george, alex | george +15 | diana: 5, george: 15 |
All discovered users:
| User | Score |
|---|---|
| bob | 0 |
| clara | 0 |
| diana | 5 |
| eric | 0 |
| frank | 0 |
| george | 15 |
Sorted output:
george
diana
bob
clara
eric
frank
This trace demonstrates why we must store every seen username separately from the score dictionary.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n log n) | Processing actions is O(n), sorting usernames dominates |
| Space | O(n) | Dictionaries and sets store at most all distinct users |
With at most 100 actions, this solution easily fits within the limits. Even the sorting step is tiny because the number of distinct usernames is small.
Test Cases
# helper: run solution on input string, return output string
import sys
import io
from collections import defaultdict
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
input = sys.stdin.readline
def solve():
me = input().strip()
n = int(input())
points = {
"posted": 15,
"commented": 10,
"likes": 5
}
score = defaultdict(int)
people = set()
for _ in range(n):
words = input().split()
x = words[0]
action = words[1]
y = words[3][:-2]
if x != me:
people.add(x)
if y != me:
people.add(y)
value = points[action]
if x == me:
score[y] += value
if y == me:
score[x] += value
result = sorted(people, key=lambda name: (-score[name], name))
return "\n".join(result)
return solve()
# provided sample
assert run(
"""ahmed
3
ahmed posted on fatma's wall
fatma commented on ahmed's post
mona likes ahmed's post
"""
) == "fatma\nmona", "sample 1"
# minimum input
assert run(
"""alex
1
bob likes clara's post
"""
) == "bob\nclara", "minimum size with zero scores"
# tie breaking
assert run(
"""alex
2
alex likes sara's post
alex likes mona's post
"""
) == "mona\nsara", "lexicographical tie breaking"
# repeated interactions
assert run(
"""alex
3
alex posted on bob's wall
bob commented on alex's post
alex likes bob's post
"""
) == "bob", "score accumulation"
# users unrelated to main user
assert run(
"""alex
4
bob likes clara's post
diana likes eric's post
frank commented on george's post
harry posted on alex's wall
"""
) == "harry\nbob\nclara\ndiana\neric\nfrank\ngeorge", "include zero-score users"
| Test input | Expected output | What it validates |
|---|---|---|
| Single unrelated interaction | bob clara order |
Users with zero score must still appear |
| Equal scores | Lexicographical ordering | Correct tie-breaking |
| Multiple interactions with same user | Single accumulated total | Score aggregation |
| Mixed related and unrelated users | Positive scores first | Proper sorting and inclusion |
Edge Cases
Users with zero interaction score
Input:
ahmed
2
mona likes sara's post
sara commented on mona's post
Neither action involves ahmed, so no score updates occur.
The algorithm still inserts both mona and sara into the people set. Their scores remain the default value 0.
Sorting gives:
mona
sara
A solution that only stored users inside the score dictionary would incorrectly print nothing.
Parsing names ending with "'s"
Input:
ahmed
1
ahmed posted on fatma's wall
After splitting:
| Index | Value |
|---|---|
| 0 | ahmed |
| 1 | posted |
| 2 | on |
| 3 | fatma's |
| 4 | wall |
The algorithm uses words[3][:-2], producing fatma.
Score state:
| User | Score |
|---|---|
| fatma | 15 |
Output:
fatma
Without removing the suffix, the stored name would incorrectly become fatma's.
Tie-breaking by lexicographical order
Input:
alex
2
alex likes sara's post
alex likes mona's post
Both users receive exactly 5 points.
Sorting key values:
| User | Key |
|---|---|
| mona | (-5, "mona") |
| sara | (-5, "sara") |
Since the numeric parts are equal, normal string comparison determines the order.
Correct output:
mona
sara
A solution sorting only by score could produce the wrong ordering depending on insertion order.