Cumulative checkpoint: programming and discrete reasoning
Use after C01–C05. Reserve roughly 45–75 minutes, adjusting for your other commitments. Work without AI, solution pages, or execution on the first pass. Record assumptions and predicted behavior before testing. Score each problem for setup, reasoning, execution, verification, and explanation; a familiar answer copied from memory is not evidence of transfer.
Trace total=0; for value in [3,-2,5]: total=2*total+value. Give the state after each iteration and write a recurrence for the state after values. Explain why it is not an ordinary running sum.
In Python, let a=[[1],[2]]; b=a.copy(); b[0].append(7); b.append([3]). Give the final contents of both names and explain precisely which objects were copied and which remain shared.
A C++ function returns a reference to a local std::vector<int>. Explain the defect. Compare returning the vector by value with returning a reference to caller-owned storage, including lifetime obligations.
Negate “for every request there exists a server that eventually replies.” Then explain why this statement does not assert that one fixed server replies to every request.
Prove by induction that divides for every integer . State the base case, induction hypothesis, and the exact algebraic use of that hypothesis.
A recurrence has and for powers of two. Solve it and explain why a recursive implementation’s termination needs a domain restriction or rounding/base-case policy for other positive integers.
Optional small hints
CP.02: copying an outer list does not recursively copy inner lists. CP.05: rewrite using . CP.06: count how many halvings reach one.
Complete solutions: CP#
Compare the first step where your work differs. A corrected answer is not yet an independent success.
CP.01Show solution
A weighted history, not a sum
The states are , , and . With inputs , let and . Earlier inputs are repeatedly doubled; for three inputs, , which gives . An ordinary prefix sum instead satisfies . This derivation explains the observed state rather than merely quoting the printed output.
Back to CP.01CP.02Show solution
The outer containers differ; one inner mutation is shared
Final a is [[1,7],[2]]; final b is [[1,7],[2],[3]]. The shallow copy created a new outer list containing references to the same two inner lists. Appending to the first inner list affects the shared object seen through both names. Appending a third inner list to b changes only that outer list. A memory diagram with two outer containers pointing to shared inner containers makes both effects predictable.
CP.03Show solution
A reference cannot extend the destroyed local object’s lifetime
The local vector is destroyed when the function returns, so a reference to it dangles. Using it is invalid even if the old memory appears intact. Returning by value transfers a valid result object under C++ value semantics, with move or copy-elision behavior as applicable; the caller owns the resulting lifetime. Returning a reference to caller-owned storage can be valid only while that storage remains alive and under a clear mutation/invalidation contract. The choice is about ownership and API semantics, not a blanket rule that references are always faster.
Back to CP.03CP.04Show solution
Negate quantifiers in order
The negation is: there exists a request such that every server fails to eventually reply to that request. In symbolic form, becomes . The original permits the chosen server to depend on the request. For example, one server may answer odd-numbered requests and another even-numbered requests; every request has a responder, but neither server answers all requests. This is not the same as .
Back to CP.04CP.05Show solution
Use the induction hypothesis as a divisible factor
For , , divisible by . Assume for an integer . Then , also divisible by . Therefore the claim holds for all nonnegative integers by induction. The proof does not assume the desired next case; it constructs its integer factor from the current case.
Back to CP.05CP.06Show solution
A cost recurrence and an implementation domain are different
For , after halvings the argument reaches one. Unrolling gives . A literal real-valued halving routine on input never reaches exactly one, while an integer routine must specify floor/ceiling and a base condition such as . The mathematical recurrence’s stated power-of-two domain made the base reachable. An implementation on a larger domain needs a new termination argument and possibly a different exact recurrence.
Back to CP.06Retention and readiness#
Repair C01–C03 for state or lifetime errors and C04–C05 for quantifier or induction errors. Advance to independent algorithm work when you can explain these solutions from a blank page and solve a fresh variant, not merely recognize the reference.