FPC Programming Questions
Last fall, I joined the FSU ACM Question Writers team for our semi-annual programming contest. I was chosen to write two questions for the COP4530 Data Structures II class at FSU.
The two problems I chose to write are a sliding window problem, and a DFS tree problem.
Scoring Drives
This problem was intended to be the easier of the two, so I stuck to basics and used a straightforward sliding window pattern, similar to one you might see on LeetCode.
Here is the writeup:
Problem:
On a bright, beautiful, sunny 12PM football game in Tallahassee, the Seminoles offense runs a long series of plays. You have collected the integer sequence that represents drive-by-drive net yardage adjustments. A positive number means the drive gained yards on net. A negative number means the drive lost yards on net due to sacks, penalities, or turnovers. Zero means the drive broke even.
A scoring window is defined as any contiguous block of drives. You are tasked with counting how many scoring windows give total net yardage exactly equal to a target value S.
In other words, given an array $d[1, …, n]$ of integers, count the number of pairs $(l, r)$ with $1 ≤ l ≤ r ≤ n$ such that $d[l] + d[l+1] + … + d[r] = S$.
Input:
One line with two integers: $n, S$
$n$ is the number of drives recorded
$S$ is the target net yardage
One line with n integers: $d1\space d2\space …\space dn$
$d$ is the net yardage adjustment for the ith drive
Output:
The count of contiguous drive windows whose total is exactly S.
Sample Run:
| Input |
|---|
| 7 5 2 3 -1 2 3 -2 -1 |
| Output |
|---|
| 3 |
Here is the intended solution for the problem (in Python):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import sys
def main():
data = list(map(int, sys.stdin.buffer.read().split()))
iterator = iter(data)
n = next(iterator)
S = next(iterator)
pref = 0
ans = 0
freq = {0: 1}
for _ in range(n):
x = next(iterator)
pref += x
needed = pref - S
ans += freq.get(needed, 0)
freq[pref] = freq.get(pref, 0) + 1
print(ans)
if __name__ == "__main__":
main()
The Great Family Tree Feast
This is a binary-tree path-sum counting problem: given node values and child links plus a root ID and target S, count all downward continuous paths (any start node to any descendant) whose values sum to S.
Here is the writeup:
Problem:
It’s Thanksgiving at the Binary Family reunion, and the family tree is quite literal this year. Each family member has brought a dish with a certain “deliciousness value” (which can be positive, negative, or zero).
The tradition states that any group of family member sitting along a continous path at a distinctly tree shaped table can share a feast together. However, there is a catch: the combined seliciousness of their dishes must equal exactly $S$ (or the satisfaction score) for the feast to be considered successful.
Your job is to count how many different successful feasts can happen at this year’s reunion
Input:
The first line $n$ is the number of family members in the tree
The next $n$ lines for each family member are as follows:
- $v[i]$: the deliciousness value
- $l[i]$: the ID of the family member seated to their left below them (-1 if no one)
- $r[i]$: the ID of the family member seated to their right below them (-1 if no one)
Next line - $r$: the ID of the patriarch/matriarch of the family
Last line - $S$: the target satisfaction score
Output:
A single integer: the number of valid feast paths with deliciousness sum equal to s.
Sample Run:
| Input | | :—————————————————————————————————————————-: | | 9
3 2 3
-2 4 5
4 -1 6
2 -1 -1
1 -1 -1
-1 7 8
3 -1 -1
1 -1 9
2 -1 -1
1
4 |
| Output |
|---|
| 2 |
Here is the intended solution for the problem (in Python):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import sys
def main():
data = sys.stdin.buffer.read().split()
it = iter(data)
n = int(next(it))
val = [0] * (n + 1)
left = [0] * (n + 1)
right = [0] * (n + 1)
for i in range(1 , n + 1):
val[i] = int(next(it))
left[i] = int(next(it))
right[i] = int(next(it))
r = int(next(it))
s = int(next(it))
freq = {0:1}
answer = 0
def dfs(u, cur):
nonlocal answer
if u == -1:
return
cur += val[u]
needed = cur - s
answer += freq.get(needed, 0)
freq[cur] = freq.get(cur, 0) + 1
if left[u] != -1:
dfs(left[u], cur)
if right[u] != -1:
dfs(right[u], cur)
cnt = freq[cur] - 1
if cnt == 0:
del freq[cur]
else:
freq[cur] = cnt
dfs(r, 0)
print(answer)
if __name__ == "__main__":
main()
Takeaways:
I had a really fun time writing these problems. I wanted them to be approachable but still unique, and I think I hit that goal. I will definitely continue to write problems for the contest in the future.