DSA/CSES 2Knights
Non-Attacking Knights on a k×k Board
Problem. For every board size , count the number of ways to place two knights on a chessboard so that they do not attack each other.
The core is instead of calculating the possible combinations of placements which is confusing we can do total_possibilities - attacking_squares
Step 1: Total ways to place two knights, ignoring attacks
A board has squares. Placing two (identical, unlabeled) knights on two different squares is just "choose 2 squares out of ":
This is the total number of placements before removing the ones where the knights attack each other.
Step 2: Counting the attacking pairs
A knight standing at square attacks any square that is offset by one of these 8 vectors:
| Offset (dx, dy) | |||
|---|---|---|---|
| (1, 2) | (1, −2) | (−1, 2) | (−1, −2) |
| (2, 1) | (2, −1) | (−2, 1) | (−2, −1) |
Notice: in every one of these 8 vectors, the two numbers and are just 1 and 2 in some order, with some sign.
How many placements exist for one fixed offset (dx, dy)?
For the pair of squares and to both lie on the board, has valid choices, and has valid choices. So the count is:
Since for all 8 vectors, this is always:
(No need to clamp negative values to zero — if , the factor already kills the product; if , the factor does the same. The algebra takes care of small boards automatically.)
Summing over all 8 offsets gives the total number of ordered attacking pairs (i.e., "knight A attacks square B" counted separately from "knight B attacks square A"):
But an unordered pair of squares gets counted twice this way (once in each direction), so the number of unordered attacking pairs is:
Step 3: Subtract to get non-attacking pairs
Step 4: Simplify into one closed-form polynomial
Expand each piece separately.
First term:
Second term:
Put both over a common denominator of 2:
Combine like terms ():
Step 5: Sanity check against the example
| k | Answer(k) |
|---|---|
| 1 | 0 |
| 2 | 6 |
| 3 | 28 |
| 4 | 96 |
| 5 | 252 |
| 6 | 550 |
| 7 | 1056 |
| 8 | 1848 |
Matches the sample output exactly.
Intuition for k=1 and k=2: On a 1×1 board there's only one square, so you can't even place two knights (0 ways). On a 2×2 board, pairs exist, and a knight move needs at least a 3-wide gap in one direction, so none of them attack — all 6 count.
Step 6: Implementation
Since the formula is closed-form, each answer is to compute, so the whole solution is — trivially fast for .
def f(k):
return (pow(k, 4) - 9 * pow(k, 2) + 24 * k - 16) // 2
n = int(input())
for i in range(1, n + 1):
print(f(i))
Note: the division by 2 is safe as integer division (//) because is always even — this follows directly from the derivation, since it came from summing two integer-valued combinatorial counts ( and ) that are each themselves always integers, and their difference stays an integer after the common denominator was cleared.