由于每颗棋子只影响下一行状态,首先dfs出两行合法转移状态,再枚举状态和个数求解。
ACcode:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int LIM=1024;
const int NS=1000000;
int num[LIM];
LL dp[2][LIM][26];
int state[NS][2],top;
int getone(int x)
{
int cnt=0;
for (; x; cnt++,x&=(x-1));
return cnt;
}
void dfs(int x,int y,int pos)
{
if (pos<0) return ;
if (pos==0)
{
state[top][0]=x;
state[top++][1]=y;
return ;
}
int a=x&1,b=y&1;
dfs(x<<1,y<<1,pos-1);
if (!(a|b))
dfs(x<<1|1,y<<1,pos-1),
dfs(x<<1,y<<1|1,pos-1);
}
void print(int x,int y)
{
for (int i=0; i<y; i++,x>>=1)
printf("%d",x&1);
puts("");
}
int move(int x)
{
return (x|(x<<1)|(x>>1));
}
void ttt(int n)
{
int cnt=0;
printf("top=%d\n",top);
for (int i=0; i<top; i+=100)
{
printf("i=%d\n",i);
print(state[i][0],n);
print(state[i][1],n);
}
printf("cnt=%d\n",cnt);
}
void init(int x,int y,int z)
{
for (int i=0;i<LIM;i++)
for (int k=0;k<=z;k++)
dp[x][i][k]=0;
}
int main()
{
int n,k,p,q,r,s,t;
for (int i=0; i<LIM; i++)
num[i]=getone(i);
while (~scanf("%d%d",&n,&k))
{
t=(n+1)>>1;
if (t*t<k)
{
printf("0\n");
continue;
}
s=top=0;
dfs(0,0,n),init(0,n,k);
// ttt(n);
for (int i=0;i<top;i++)
{
p=state[i][0];
dp[0][p][num[p]]=1;
}
for (int i=2;i<=n;i++)
{
s^=1,init(s,n,k);
for (int j=0;j<top;j++)
{
p=state[j][0],q=state[j][1],t=num[q];
for (int c=num[p];c<=(k-t);c++)
dp[s][q][c+t]+=dp[1-s][p][c];
}
}
LL res=0;
for (int i=0;i<LIM;i++)
res+=dp[s][i][k];
// cout<<res<<endl;
printf("%I64d\n",res);
}
return 0;
}