问题描述
很久以前,有一个强大的帝国,它的国土呈正方形状(转45度看)。
这个国家有若干诸侯。由于这些诸侯都曾立下赫赫战功,国王准备给他们每人一块封地(正方形中的一格)。但是,这些诸侯又非常好战,当两个诸侯位于同一行或同一列时,他们就会开战。如下图2-3为n=3时的国土,阴影部分表示诸侯所处的位置。前两幅图中的诸侯可以互相攻击,第三幅则不可以。
国王自然不愿意看到他的诸侯们互相开战,致使国家动荡不安。因此,他希望通过合理的安排诸侯所处的位置,使他们两两之间都不能攻击。
现在,给出正方形的边长n,以及需要封地的诸侯数量k,要求你求出所有可能的安置方案数。(n≤100,k≤2n2-2n+1)
由于方案数可能很多,你只需要输出方案数除以504的余数即可。
输入说明
仅一行,两个整数n和k,中间用一空格隔开。
输出说明
一个整数,表示方案数除以504的余数。
样例输入
2 2
样例输出
4
样例说明
四种安置方案如图2-4所示。注意:镜面和旋转的情况属于不同的方案。
思路
首先可以证明这个图可以转换成如下的形式:
然后我们会容易发现一种不同与搜索的动态规划做法.
f[i,j]:=f[i,j]+f[k,j-1]*(Len[i]-(j-1)) [j-1<=k<=i-1]
1.f[i,j]表示前i列放置j个的方案,且第j个放在第i列上,
2.前面f[k,j-1]个都需要累加上来,举一个说明为什么需要累加:对于前4排放置2个的情况(平移后的),2个即可以放在第一列和第三列,也可以放在第一列和第四列,所以需要把这些分布在不同列的情况累加上来。
3.乘(Len[i]-(j-1))是因为前面k列放了j-1个棋子了,然后每行只能放一个棋子,所以第j个棋子在第i列可以放的情况就是Len[i]-(j-1),len[i]是第i列有多少行,程序中是L[i]
const mo=504; var f:array[0..200,0..200]of int64; l:array[0..2000]of longint; n,k,i,j,kk,m:longint; ans:int64=0; function min(a,b:longint):longint; begin if a>b then exit(b) else exit(a); end; procedure change; begin m:=2*n-1; if k>m then begin writeln(0); halt; end; if k=0 then begin writeln(1); halt; end; end; begin fillchar(f,sizeof(f),0); readln(n,k); change; for i:=1 to m do if odd(i) then l[i]:=i else l[i]:=i-1; for i:=1 to m do begin f[i,1]:=l[i]; for j:=2 to min(i-1,k) do for kk:=j-1 to i-1 do f[i,j]:=(f[i,j]+f[kk,j-1]*(l[i]-j+1))mod mo; end; ans:=0; if k=1 then begin writeln((n shl 1)*(n-1)+1); halt; end; for i:=k to m do ans:=(ans+f[i,k]) mod mo; writeln(ans mod mo); end.