Trước tiên, ta nghĩ một thuật toán quy hoạch động đơn giản cho bài này. Nhận thấy m nhỏ
nên ta nghĩ ngay đến quy hoạch động bitmask: gọi f[i][mask1][mask2] là số cách điền
bảng i×m, với cột thứ i−1 và cột i lần lượt được xếp các quân mã theo cấu hình
mask1 và mask2. Cách chuyển trạng thái khá đơn giản:
f[i][mask1][mask2]=∑mask3f[i−1][mask2][mask3]
Thỏa mãn các cấu hình mask1,mask2,mask3 đôi một không mâu thuẫn (mâu thuẫn tức là có
hai con mã tấn công nhau).
Tới đây ta nhận thấy bản chất công thức truy hồi này vẫn là một công thức truy hồi tuyến
tính, từ đó có thể thử áp dụng ngay nhân ma trận để giải. Tuy nhiên, điều này đồng nghĩa
với việc ta cần một ma trận vuông kích thước 2×22m=512 khi m=4, nên việc nhân
ma trận một lần cũng đã đủ lâu, chưa kể việc ta nhân nó logn lần.
Để tối ưu thì ta nhận thấy khi tính f[i][mask1][mask2], ta không cần quan tâm tới các bộ
(mask1,mask2) bị mâu thuẫn, vì giá trị của nó chắc chắn bằng 0 rồi. Nếu thử code sinh
hết các bộ không mâu thuẫn thì khi m=4, chỉ có 81 bộ thỏa mãn! Khi này, ta chỉ cho vào
ma trận các bộ thỏa mãn để tính, nên bây giờ ma trận chỉ có kích thước 162×162, đủ
tốt để có thể nhân ma trận logn lần.
Code mẫu:
cpp#∈clude<bitsstdc++.h>usingll=longlong;#def∈eall(a)a.beg∈(),a.end()#def∈eSZ(a)(∫)(a).size()usingnamespacestd;const∫mod