您的位置:首页 > 其它

[51nod1142] 棋子遍历棋盘

2017-02-23 16:26 239 查看

题目大意

一个M*N的棋盘, 有一个棋子每次可以向上下左右4个方向中的1个走1步,让这个棋子从(1,1)位置出发,走遍所有格子恰好1次,最后回到(1,1),有多少种不同的走法。由于方案数量巨大,输出数量Mod 10^9 + 7即可。

M≤109

N≤5

分析

题目相当于求一条哈密顿回路,那么可以不用管哪里出发(这个很显然)

发现N很小!很自然地可以往插头DP方面想。用括号序表示插头的联通状态即可。(手算一下发现当n=5,有用的状态只有21个)。

M却很大,但是21 * 21 * 21很小,所以可以矩阵乘法优化。

注意:由于是一条回路,在中间的部分不能转移到插头状态#####,只有最后f[m]
才能转移到#####,也就是做矩阵乘法求出f[m-1]
,然后最后一行暴力。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=113,mo=1e9+7;

typedef long long LL;

int n,m,p,q,ans,id[799],tot,Sta[25];

struct node
{
int H[maxn],tot,st[maxn],s[maxn];
void init()
{
memset(H,255,sizeof(H));
tot=0;
}
void add(int S,int v)
{
int i=S%maxn;
for (;H[i]>=0 && st[H[i]]!=S;i=(i+1)%maxn);
if (H[i]<0)
{
st[tot]=S; s[tot]=v; H[i]=tot++;
}else s[H[i]]=(s[H[i]]+v)%mo;
}
}f[2];

struct Matrix
{
int a[25][25];
}a,b,c;

Matrix operator * (const Matrix &a,const Matrix &b)
{
memset(c.a,0,sizeof(c.a));
for (int i=0;i<tot;i++)
{
for (int j=0;j<tot;j++)
{
for (int k=0;k<tot;k++) c.a[i][j]=(c.a[i][j]+(LL)a.a[i][k]*b.a[k][j])%mo;
}
}
return c;
}

int Get(int s,int w)
{
return (s>>(w<<1))&3;
}

void Set(int &s,int w,int v)
{
s^=Get(s,w)<<(w<<1);
s^=v<<(w<<1);
}

void dp(int m)
{
p=0; q=1;
f[0].init();
if (m>=0) f[0].add(m,1);else
{
for (int i=0;i<tot;i++) f[0].add(Sta[i],b.a[0][i]);
}
for (int i=0;i<n;i++,p^=1,q^=1)
{
f[q].init();
for (int j=0;j<f[p].tot;j++)
{
int st=f[p].st[j],s=f[p].s[j],x=Get(st,i),y=Get(st,i+1);
if (!x)
{
if (!y)
{
if (i==n-1) continue;
Set(st,i,1); Set(st,i+1,2);
f[q].add(st,s);
}else
{
if (i<n-1) f[q].add(st,s);
Set(st,i,y); Set(st,i+1,0);
f[q].add(st,s);
}
}else
{
if (!y)
{
f[q].add(st,s);
if (i==n-1) continue;
Set(st,i,0); Set(st,i+1,x);
f[q].add(st,s);
}else
{
Set(st,i,0); Set(st,i+1,0);
if (x==1)
{
if (y==1)
{
for (int k=i+2,t=1;;k++)
{
if (Get(st,k)==1) t++;
else if (Get(st,k)==2)
{
t--;
if (!t)
{
Set(st,k,1); break;
}
}
}
f[q].add(st,s);
}else if (m<0 && i==n-1) f[q].add(st,s);
}else
{
if (y==1) f[q].add(st,s);else
{
for (int k=i-1,t=1;;k--)
{
if (Get(st,k)==2) t++;
else if (Get(st,k)==1)
{
t--;
if (!t)
{
Set(st,k,2); break;
}
}
}
f[q].add(st,s);
}
}
}
}
}
}
for (int i=0;i<f[p].tot;i++) f[p].st[i]<<=2;
}

void Find(int x,int y,int st)
{
if (x>n)
{
if (!y) id[st]=tot,Sta[tot++]=st;
return;
}
Find(x+1,y,st);
Find(x+1,y+1,st+(1<<(x<<1)));
if (y>0) Find(x+1,y-1,st+(2<<(x<<1)));
}

void quick(int x)
{
if (!x) return;
quick(x>>1);
b=b*b;
if (x&1) b=b*a;
}

int main()
{
scanf("%d%d",&m,&n);
memset(id,255,sizeof(id));
Find(1,0,0);
for (int i=0;i<tot;i++)
{
dp(Sta[i]);
for (int j=0;j<f[p].tot;j++) if (id[f[p].st[j]]>0) a.a[i][id[f[p].st[j]]]=f[p].s[j];
b.a[i][i]=1;
}
quick(m-1);
dp(-1);
for (int i=0;i<f[p].tot;i++) if (f[p].st[i]==0)
{
printf("%d\n",(f[p].s[i])*2%mo); return 0;
}
printf("0\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: