题意:n*n board,对角线棋子相互攻击,问放k个棋子的合法方案
首先想到黑白棋盘根据(i+j)的奇偶性上色,容易得出白色区域不会攻击黑色区域则在白色区域中放i个 黑色区域中放k-i个
如何转化成同行同列相互攻击?
将棋盘顺时针旋转45°则攻击方式则由对角45°变为垂直和水平,之后dp求解即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e9;
const int N=2e3+20;
int n,k;
ll w[N],b[N];//w[i] 第i行棋子个数
ll R_w[N][N],R_b[N][N];//r[i][j] 前i行放j个棋子的方法数
void Bishop(int n,int k,ll C[],ll R[][N])
{
for(int i=0;i<=n;i++)
R[i][0]=1;
for(int i=1;i<=k;i++)
R[0][i]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=C[i];j++)
{
//第i行如果放的话,列的选择方案有(c[i]-(j-1))
R[i][j]=R[i-1][j]+R[i-1][j-1]*(C[i]-(j-1));
}
}
}
int main()
{
while(cin>>n>>k&&(n+k))
{
memset(w,0,sizeof(w));
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i+j)&1)
w[(i+j)>>1]++;//把相互攻击的棋子转移到同行同列
else
b[(i+j)>>1]++;
}
}
sort(b+1,b+1+n);//每行棋子从上到下递增
sort(w+1,w+n);
Bishop(n,k,b,R_b);
Bishop(n-1,k,w,R_w);
ll ans=0;
for(int i=0;i<=k;i++)
{
ans+=R_b[n][i]*R_w[n-1][k-i];
}
cout<<ans<<endl;
}
return 0;
}