正题
题目大意
一个骑士会攻击对角线的位置,然后n∗nn*nn∗n的棋盘上放mmm个骑士求方案数。
解题思路
我们将棋盘翻转以两个对角线为中间,这样骑士就变成了横着打和竖着打。
设fi,s,jf_{i,s,j}fi,s,j表示第iii条对角线,不能放置骑士的位置状态为sss,已经放置了jjj个骑士。
我们注意到单数和偶数是分开的,所以我们分开处理
有fi,s,j=∑z=sxorkj&2kfi−2,z,j−1+fi−2,s,jf_{i,s,j}=\sum_{z=s\ xor\ k}^{j\&2^k} f_{i-2,z,j-1}+f_{i-2,s,j}fi,s,j=z=s xor k∑j&2kfi−2,z,j−1+fi−2,s,j
然后ans=∑im(∑(f2∗n−1,s,i)∗∑(f2∗n−2,s,m−i))ans=\sum_{i}^m(\sum (f_{2*n-1,s,i})*\sum(f_{2*n-2,s,m-i}))ans=i∑m(∑(f2∗n−1,s,i)∗∑(f2∗n−2,s,m−i))
然后数组滚动一下就过了
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=31;
ll n,m,f[3][32768][N],g[3][32768][N],ans1,ans2,ans;
int main()
{//freopen("chess.in","r",stdin);//freopen("chess.out","w",stdout);scanf("%lld%lld",&n,&m);f[1][0][0]=f[1][1<<((n+1)/2-1)][1]=1;ll MS=(1<<n);bool flag=0;ll l,r;l=r=(n+1)/2;for(ll i=3;i<=2*n-1;i+=3){int I=i%3,L=(i+1)%3;memset(f[I],0,sizeof(f[I]));if(i==n+1) l=l,r=r;else if(flag)l++,r--;else r++,l--;if(l==1) flag=1;for(ll j=0;j<MS;j++){for(ll k=l-1;k<=r-1;k++)if(j&(1<<k)){ll z=j^(1<<k);for(ll w=1;w<=m;w++)f[I][j][w]+=f[L][z][w-1];}for(ll w=0;w<=m;w++)f[I][j][w]+=f[L][j][w];}}l=n/2+1;r=n/2;flag=0;g[0][0][0]=1;for(ll i=2;i<=2*n-1;i+=2){int I=i%3,L=(i+1)%3;memset(g[I],0,sizeof(g[I]));if(i==n+1) l=l,r=r;else if(flag) l++,r--;else l--,r++;if(l==1) flag=1;for(ll j=0;j<MS;j++){for(ll k=l-1;k<=r-1;k++)if(j&(1<<k)){ll z=j^(1<<k);for(ll w=1;w<=m;w++)g[I][j][w]+=g[L][z][w-1];}for(ll w=0;w<=m;w++)g[I][j][w]+=g[L][j][w];}}for(ll i=0;i<=m;i++){ans1=ans2=0;int I1=(2*n-1)%3,I2=(2*n-2)%3;for(ll j=0;j<MS;j++)ans1+=f[I1][j][i];for(ll j=0;j<MS;j++)ans2+=g[I2][j][m-i];ans+=ans1*ans2;}printf("%lld",ans);
}