题目大意:
在N行M列的棋盘上,放若干个炮可以是0个,使得没有任何一个炮可以攻击另一个炮。求有多少种放置方法?由于值比较大,输出其mod 9999973的结果。
中国象棋中炮的行走方式大家应该很清楚吧。
100%的数据中N,M不超过100
50%的数据中,N,M至少有一个数不超过8
30%的数据中,N,M均不超过6
题解:
DP:
题目可以发现,每一列最多放2个炮,所以可以做动规:
f[i,j,k]表示前i行j列放1个棋,k列放2个棋子的最大值。
所以对于到f[i,j,k]有6个情况:
1.不放棋子丨f[i-1][j][k]
2.放一个棋子,放在之前没有棋子的一列丨f[i-1][j-1][k]*(m-j-k+1)
3.放一个棋子,放在之前有一个棋子的一列丨f[i-1][j+1][k-1]*(j+1);
4.放两个棋子,放在之前没有棋子的两列丨f[i-1][j-2][k]*C(m-j-k+2)
5.放两个棋子,都放在之前没有棋子的一列丨f[i-1][j][k-1]*(m-j-k+1)*j
6.放两个棋子,分别放在之前没有棋子和有一个棋子的两列丨f[i-1][j+2][k-2]*C(j+2)
C的操作是x*(x-1) div 2,这是某个很神奇的组合数操作….
var
f:array [-10..101,-10..101,-10..101] of longint;
ans,n,m,i,j,k:longint;
function c(a:longint):longint;
begin
exit(a*(a-1) div 2);
end;
begin
readln(n,m);
f[0,0,0]:=1;
for i:=1 to n do
for j:=0 to m do
for k:=0 to m-j do
begin
f[i,j,k]:=(f[i-1,j,k]+
f[i-1,j-1,k]*(m-j-k+1)+
f[i-1,j+1,k-1]*(j+1)+
f[i-1,j-2,k]*c(m-j-k+2)+
f[i-1,j,k-1]*(m-j-k+1)*j+
f[i-1,j+2,k-2]*c(j+2)) mod 9999973;
end;
for i:=0 to m do
for j:=0 to m-i do
ans:=(ans+f[n,i,j]) mod 9999973;
writeln(ans);
end.