Sums
TL;DR
Compute n
range-sum queries fast using a prefix-sum array, send back exactly n
answers, one per line. Use buffered I/O to stay under the 10s server limit.
Flag: scriptCTF{1_w4n7_m0r3_5um5_c2b7a07c8079}
Challenge Overview
- Category: Programming
- Service:
nc play.scriptsorcerers.xyz 10426
- Goal: For each query
[l, r]
(0-indexed, inclusive), returnsum(nums[l:r+1])
.
- Gotchas:
n = 123456
(large).
- You must return exactly
n
lines of answers.
- Time limit: 10 seconds (server-side).
- The server independently computes the correct answers internally and checks your output line-by-line.
What the Server Does (Given Code Summary)
- Generates
n=123456
random integersnums[i]
in[0, 696969]
.
- Prints one giant line with all
n
numbers separated by spaces.
- Prints
n
lines of queriesl r
, inclusive, 0-indexed.
- Internally runs its own solver (
./solve
) to get the correct answers.
- Reads your
n
answers from stdin and compares with its own.
- If they match and total elapsed time ≤ 10s, prints the flag.
Implication: Our output must be correct and fast.
Strategy
Use a prefix-sum array pref
where:
pref[0] = 0
pref[i+1] = pref[i] + nums[i]
Then each query sum is:
sum(nums[l:r+1]) = pref[r+1] - pref[l]
This makes each query O(1) after an O(n) preprocessing pass.
Reproduction: Step-by-Step
✅ 1) Prerequisites
- Python 3.8+ (tested with CPython; PyPy works too)
- Network access to the challenge host
✅ 2) Save the client script
Create solve_remote.py
with the following:
#!/usr/bin/env python3
import socket
HOST = "play.scriptsorcerers.xyz"
PORT = 10426
def main():
with socket.create_connection((HOST, PORT)) as sock:
rf = sock.makefile("r", encoding="utf-8", newline="\n")
wf = sock.makefile("w", encoding="utf-8", newline="\n")
# 1) Read the big line of numbers
nums_line = rf.readline()
if not nums_line:
return
nums_strs = nums_line.strip().split()
n = len(nums_strs)
nums = list(map(int, nums_strs))
# 2) Build prefix sums
pref = [0] * (n + 1)
s = 0
for i, a in enumerate(nums, 1):
s += a
pref[i] = s
# 3) Answer exactly n queries
out = []
append = out.append
for _ in range(n):
line = rf.readline()
l_str, r_str = line.split()
l = int(l_str); r = int(r_str)
append(str(pref[r + 1] - pref[l]))
# 4) Send all answers in one go (fewer syscalls)
wf.write("\n".join(out) + "\n")
wf.flush()
# 5) Read remainder (flag or error)
# Using read() to EOF ensures we don't miss the flag line.
remainder = rf.read()
if remainder:
print(remainder, end="")
if __name__ == "__main__":
main()
✅ 3) Run it
python3 solve_remote.py
If successful, you’ll see the flag:
scriptCTF{1_w4n7_m0r3_5um5_c2b7a07c8079}
Notes on Performance & Robustness
- Why buffered I/O? Using
makefile()
and writing all answers at once reduces syscall overhead and comfortably fits within the 10s limit.
- Complexity:
- Prefix computation: O(n)
- Query answers: O(n)
- Total: O(n) time, O(n) memory
- Integer safety: Python ints are arbitrary precision; sums won’t overflow.
Common Pitfalls
- ❌ Printing answers one-by-one without buffering → slower I/O.
- ❌ Forgetting the trailing newline at the end of the output.
- ❌ Off-by-one on inclusive ranges; remember
pref[r+1] - pref[l]
.
- ❌ Assuming 1-indexed inputs; the problem is 0-indexed.
Lessons Learned
- For large-scale query tasks, precompute and answer in O(1) per query.
- For tight server timeouts, optimize I/O as much as the algorithm.
- Always confirm indexing conventions and inclusivity of ranges.