Jump to content

DSA/CSES 2Knights

From scratchpad
Revision as of 10:34, 31 August 2026 by Admin (talk | contribs) (Created page with "== Non-Attacking Knights on a k×k Board == '''Problem.''' For every board size <math>k = 1, 2, \dots, n</math>, count the number of ways to place ''two'' knights on a <math>k \times k</math> 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 <math>k...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Non-Attacking Knights on a k×k Board

Problem. For every board size k=1,2,,n, count the number of ways to place two knights on a k×k 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 k×k board has k2 squares. Placing two (identical, unlabeled) knights on two different squares is just "choose 2 squares out of k2":

(k22)=k2(k21)2

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 (x,y) 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 |dx| and |dy| 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 (x,y) and (x+dx,y+dy) to both lie on the board, x has k|dx| valid choices, and y has k|dy| valid choices. So the count is:

(k|dx|)(k|dy|)

Since {|dx|,|dy|}={1,2} for all 8 vectors, this is always:

(k1)(k2)

(No need to clamp negative values to zero — if k=1, the factor (k1)=0 already kills the product; if k=2, the factor (k2)=0 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"):

8(k1)(k2)

But an unordered pair of squares gets counted twice this way (once in each direction), so the number of unordered attacking pairs is:

E(k)=8(k1)(k2)2=4(k1)(k2)


Step 3: Subtract to get non-attacking pairs

Answer(k)=(k22)E(k)=k2(k21)24(k1)(k2)


Step 4: Simplify into one closed-form polynomial

Expand each piece separately.

First term: k2(k21)2=k4k22

Second term: 4(k1)(k2)=4(k23k+2)=4k212k+8

Put both over a common denominator of 2:

Answer(k)=k4k228k224k+162=k4k28k2+24k162

Combine like terms (k28k2=9k2):

Answer(k)=k49k2+24k162


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, (42)=6 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 O(1) to compute, so the whole solution is O(n) — trivially fast for n10000.

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 k49k2+24k16 is always even — this follows directly from the derivation, since it came from summing two integer-valued combinatorial counts ((k22) and E(k)) that are each themselves always integers, and their difference stays an integer after the ×2 common denominator was cleared.