因为不能往回走而且行数很少,可以按照列来转移。直接
O(nm)
记录距离显然是不可以的,但是发现相邻格子的最短路最多差
1
,因此我们只需要记录第
复杂度
O(6nm2)
。
#include<cstdio>
#include<algorithm>
using namespace std;
const int max4=1050,max2=70,maxm=110,maxn=10;
int transx[max4][max2],transy[max4][max2],dp[2][maxm][max4],last[2][maxm][max4],ans[maxm],
f[maxn],tem[maxn],dis[maxn],quex[2][300000],quey[2][300000],n,m,p;
void inc(int &x,int y)
{
x+=y;
x=(x>=p?x-p:x);
}
int main()
{
//freopen("a.in","r",stdin);
int x,y,x1,y1,ok,tl[2];
scanf("%d%d%d",&n,&m,&p);
for (int S=0;S<(1<<(2*(n-1)));S++)
{
ok=1;
for (int i=1;i<n;i++)
{
x=(S>>((i-1)*2))&3;
if (x==2)
{
ok=0;
break;
}
if (x)
{
if (x==1) f[i]=f[i-1]+1;
else f[i]=f[i-1]-1;
}
else f[i]=f[i-1];
}
if (!ok) continue;
for (int T=0;T<(1<<n);T++)
{
for (int i=0;i<n;i++)
tem[i]=(T>>i)&1;
dis[0]=f[0]+tem[0];
for (int i=1;i<n;i++) dis[i]=min(dis[i-1],f[i])+tem[i];
for (int i=n-2;i>=0;i--)
dis[i]=min(dis[i],dis[i+1]+tem[i]);
transy[S][T]=dis[0];
for (int i=1;i<n;i++)
{
if (dis[i]==dis[i-1]) x=0;
else if (dis[i]==dis[i-1]+1) x=1;
else x=3;
transx[S][T]|=x<<(2*(i-1));
}
}
}
for (int T=0;T<(1<<n);T++)
{
x=0;
for (int i=1;i<n;i++)
if ((T>>i)&1) x|=1<<(2*(i-1));
y=T&1;
if (last[1][y][x]) inc(dp[1][y][x],1);
else
{
last[1][y][x]=1;
dp[1][y][x]=1;
tl[1]++;
quex[1][tl[1]]=x;
quey[1][tl[1]]=y;
}
}
for (int i=2,c=0;i<=m;i++,c^=1)
{
tl[c]=0;
for (int j=1;j<=tl[c^1];j++)
{
x=quex[c^1][j];
y=quey[c^1][j];
for (int T=0;T<(1<<n);T++)
{
x1=transx[x][T];
y1=y+transy[x][T];
if (last[c][y1][x1]==i) inc(dp[c][y1][x1],dp[c^1][y][x]);
else
{
last[c][y1][x1]=i;
dp[c][y1][x1]=dp[c^1][y][x];
tl[c]++;
quex[c][tl[c]]=x1;
quey[c][tl[c]]=y1;
}
}
}
}
for (int j=1;j<=tl[m&1];j++)
{
x=quex[m&1][j];
y1=y=quey[m&1][j];
for (int i=1;i<n;i++)
{
x1=(x>>(2*(i-1)))&3;
if (x1==1) y1++;
else if (x1==3) y1--;
}
inc(ans[y1],dp[m&1][y][x]);
}
for (int i=0;i<n+m;i++) printf("%d\n",ans[i]);
}