zoukankan      html  css  js  c++  java
  • ZOJ3256-Tour in the Castle

    题意

    有一个 (n imes m) 的棋盘,要从 ((1,1)) 走到 ((n,1)) ,经过所有格子一次且仅一次,求方案数。(2le nle 7,1le mle 10^9)

    分析

    这是一个曼哈顿路径问题,做法应该基于插头dp,但 (m) 非常大,考虑是否有优化的方法。

    从一列的某个状态转移到下一列的某个状态,所有转移都是一样的!

    于是枚举每一个行状态,求出它转移到下一行的方案数,用矩阵乘法处理到前 (m-1) 列,最后一列再拿出来dp一下即可。

    复杂度为 (O(ns^2+s^3log m))

    代码

    直接用所有状态去矩阵乘法是会TLE的,不过可以去掉开头不是 0 的状态,剩下的大概只有 100 种左右,就能过了。

    #include<bits/stdc++.h>
    #include<ext/pb_ds/assoc_container.hpp>
    #include<ext/pb_ds/hash_policy.hpp>
    using namespace std;
    using namespace __gnu_pbds;
    typedef long long giant;
    typedef cc_hash_table<int,int> Map;
    typedef Map::iterator itt;
    const int maxm=9;
    const int maxs=350; // enough?
    const int numb=2.7e5;
    const int q=7777777;
    inline int Plus(int x,int y) {return ((giant)x+(giant)y)%q;}
    inline void Pe(int &x,int y) {x=Plus(x,y);}
    inline int Sub(int x,int y) {return Plus(x,q-y);}
    inline int Multi(int x,int y) {return (giant)x*y%q;}
    int n,m,id[numb],mat[numb][maxm],ids,c[maxm],back[maxs],all,aid[numb];
    Map f,g;
    struct Matrix {
    	int a[maxs][maxs];
    	Matrix () {clear();}
    	inline void clear() {memset(a,0,sizeof a);}
    	inline void eye() {clear();for (int i=1;i<=all;++i) a[i][i]=1;}
    	inline int* operator [] (int x) {return a[x];}
    	friend Matrix operator * (Matrix a,Matrix b) {
    		Matrix ret;
    		for (int k=1;k<=all;++k) for (int i=1;i<=all;++i) for (int j=1;j<=all;++j) Pe(ret.a[i][j],Multi(a.a[i][k],b.a[k][j]));
    		return ret;
    	}
    } A,B;
    inline int conv(int x) {return x?(x==1?1:-1):0;}
    inline void match(int mt[]) {
    	static int sta[maxm];
    	int top=0;
    	for (int i=1;i<=m+1;++i) if (c[i]==1) sta[++top]=i; else if (c[i]==2) {
    		int x=sta[top--];
    		mt[x]=i,mt[i]=x;
    	}
    }
    inline int gen() {
    	int ret=0;
    	for (int i=m+1;i;--i) (ret+=c[i])<<=2;
    	return ret;
    }
    void dfs(int now,int sum) {
    	if (now>m+1) {
    		if (sum) return;
    		int s=gen();
    		match(mat[id[s]=++ids]);
    		back[ids]=s;
    		return;
    	}
    	for (int i=0;i<3;++i) if (sum+conv(i)>=0) c[now]=i,dfs(now+1,sum+conv(i));
    }
    inline int get(int x,int p) {return (x>>(p<<1))&3;}
    inline int mod(int x,int p,int d) {return (x&(~(3<<(p<<1))))+(d<<(p<<1));}
    void work() {
    	if (!((~m&1) || (n&1))) {
    		puts("Impossible");
    		return;
    	}
    	if (n==1) {
    		puts("1");
    		return;
    	}
    	memset(id,0,sizeof id),memset(aid,0,sizeof aid),memset(mat,0,sizeof mat),ids=0,all=0;
    	dfs(1,0);
    	B.clear(),A.clear();
    	for (int i=1;i<=ids;++i) if (get(back[i],1)==0) aid[back[i]]=++all;
    	for (int i=1;i<=ids;++i) if (get(back[i],1)==0) {
    		f.clear(),g.clear();
    		f[back[i]]=1;
    		for (int j=1;j<=m;++j) {
    			f.swap(g),f.clear();
    			for (itt it=g.begin();it!=g.end();++it) {
    				const int &d=it->first,&w=it->second;
    				int x=get(d,j),y=get(d,j+1),*mt=mat[id[d]];
    				if (x==0 && y==0) Pe(f[mod(mod(d,j,1),j+1,2)],w); else
    				if (x==1 && y==1) {
    					int v=mod(mod(d,j,0),j+1,0);
    					v=mod(v,mt[j+1],1);
    					Pe(f[v],w);
    				} else if (x==2 && y==2) {
    					int v=mod(mod(d,j,0),j+1,0);
    					v=mod(v,mt[j],2);
    					Pe(f[v],w);
    				} else if (x==0 || y==0) {
    					Pe(f[mod(mod(d,j,x+y),j+1,0)],w);
    					Pe(f[mod(mod(d,j,0),j+1,x+y)],w);
    				} else if (x==2 && y==1) Pe(f[mod(mod(d,j,0),j+1,0)],w);
    			}
    		}
    		for (itt it=f.begin();it!=f.end();++it) {
    			const int &d=it->first,&w=it->second;
    			if (get(d,m+1)==0) A[aid[back[i]]][aid[d<<2]]=w;
    		}
    	}
    	B.eye();
    	for (int i=n-1;i;i>>=1,A=A*A) if (i&1) B=B*A;
    	int fir=aid[mod(mod(0,2,1),m+1,2)];
    	f.clear(),g.clear();
    	for (int i=1;i<=all;++i) if (B[fir][i]) f[back[i]]=B[fir][i];
    	for (int j=1;j<=m;++j) {
    		f.swap(g),f.clear();
    		for (itt it=g.begin();it!=g.end();++it) {
    			const int &d=it->first,&w=it->second;
    			int x=get(d,j),y=get(d,j+1),*mt=mat[id[d]];
    			if (x==0 && y==0) Pe(f[mod(mod(d,j,1),j+1,2)],w); else
    			if (x==1 && y==1) {
    				int v=mod(mod(d,j,0),j+1,0);
    				v=mod(v,mt[j+1],1);
    				Pe(f[v],w);
    			} else if (x==2 && y==2) {
    				int v=mod(mod(d,j,0),j+1,0);
    				v=mod(v,mt[j],2);
    				Pe(f[v],w);
    			} else if (x==0 || y==0) {
    				Pe(f[mod(mod(d,j,x+y),j+1,0)],w);
    				Pe(f[mod(mod(d,j,0),j+1,x+y)],w);
    			} else if (x==1 && y==2) {
    				if (j==m) Pe(f[mod(mod(d,j,0),j+1,0)],w);
    			} else if (x==2 && y==1) Pe(f[mod(mod(d,j,0),j+1,0)],w);
    		}
    	}
    	printf("%d
    ",f[0]);
    }
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    #endif
    	while (~scanf("%d%d",&m,&n)) work();
    	return 0;
    }
    
  • 相关阅读:
    第一次练习总结
    第一次上机总结
    写在程序组干活之前
    虚拟机Centos7安装Mysql
    第一章 开发体验
    如何优雅的移植JavaScript组件到Blazor
    Asp.net core中RedisMQ的简单应用
    docker容器安装mysql
    Centos 8安装Docker
    c# 定时启动一个操作、任务(版本2)
  • 原文地址:https://www.cnblogs.com/owenyu/p/7512405.html
Copyright © 2011-2022 走看看