标签:ret stream pos long return 连通块 加速 int acm
题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256
题意:给一个n*m的棋盘,求从左上到左下的经过所有格子的方案数
在左边加一列问题就变成了求回路
由于m很大,所以我们需要按列dp
构造出矩阵后,用矩阵快速幂加速
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int mod=7777777;
const int HASH=419;
const int STATE=1010;
int n,m,D;
int code[10],ch[10];
struct p
{
int a[200][200];
p(){memset(a,0,sizeof(a));}
p operator *(const p&t)
{
p ans;
for(int i=0;i<D;i++)
for(int j=0;j<D;j++)
{
ll tem=0;
for(int k=0;k<D;k++)
tem+=1LL*a[i][k]*t.a[k][j];
ans.a[i][j]=tem%mod;
}
return ans;
}
};
p g;
p qpow(p x,int m)
{
p ans;
for(int i=0;i<D;i++)
ans.a[i][i]=1;
while(m)
{
if (m&1) ans=ans*x;
x=x*x;
m>>=1;
}
return ans;
}
struct hashmap
{
int head[HASH],nextt[STATE],sz;
int state[STATE];
void init()
{
sz=0;
memset(head,-1,sizeof(head));
}
int push(int st)
{
int h=st%HASH;
for(int i=head[h];i!=-1;i=nextt[i])
if (state[i]==st)
return i;
state[sz]=st;
nextt[sz]=head[h];
head[h]=sz++;
return sz-1;
}
}hm;
void decode(int st)
{
for(int i=n-1;i>=0;i--)
{
code[i]=st&3;
st>>=2;
}
}
int encode()
{
int cnt=1,st=0;
memset(ch,-1,sizeof(ch));
ch[0]=0;
for(int i=0;i<n;i++)
{
if (ch[code[i]]==-1) ch[code[i]]=cnt++;
st<<=2;
st|=ch[code[i]];
}
return st;
}
bool check(int st,int nst)
{
decode(st);
int flag=0;//当前格子是否有上插头
int k,cnt=0;
for(int i=0;i<n;i++)
{
if (flag==0)//没有
{
if (!code[i]&&!(nst>>i&1)) return false;//没有左右插头
if (code[i]&&nst>>i&1) continue;//有左右插头
if (code[i]) flag=code[i];//插头从左边来,向下延伸
else flag=-1;//插头从下面来,向右延伸
k=i;
}
else
{
if (code[i]&&nst>>i&1) return false;//有上左右插头
if (!code[i]&&!(nst>>i&1)) continue;//没有左右插头,向下延伸
if (code[i])//有左插头
{
if (code[i]==flag&&(i!=n-1||nst!=0)) return false;//如果不是最后一个格子,不能合并相同的插头
if (flag>0)//合并插头
{
for(int j=0;j<n;j++)
if (code[j]==code[i]&&j!=i)
code[j]=code[k];
code[i]=code[k]=0;
}
else//向右延伸
{
code[k]=code[i];
code[i]=0;
}
}
else
{
if (flag>0)//向右延伸
{
code[i]=code[k];
code[k]=0;
}
else//建立新的连通块
{
code[i]=code[k]=n+cnt;
cnt++;
}
}
flag=0;
}
}
if (flag!=0) return false;
return true;
}
void init()//构造矩阵
{
hm.init();
memset(code,0,sizeof(code));
code[0]=code[n-1]=1;
hm.push(0);
hm.push(encode());
memset(g.a,0,sizeof(g.a));
for(int i=1;i<hm.sz;i++)
{
int st=hm.state[i];
for(int nst=0;nst<1<<n;nst++)
if (check(st,nst))
{
int j=hm.push(encode());
g.a[i][j]=1;
}
}
D=hm.sz;
}
void solve()
{
p ans=qpow(g,m);
if (ans.a[1][0]==0) printf("Impossible\n");
else printf("%d\n",ans.a[1][0]);
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
solve();
}
return 0;
}
ZOJ 3256 Tour in the Castle 矩阵快速幂加速
标签:ret stream pos long return 连通块 加速 int acm
原文地址:http://www.cnblogs.com/bk-201/p/7493851.html