棋盘规模 2*n (n很大)
直接找出递推公式用矩阵快速幂求解
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=2; const LL mod=19999997; LL b[N]= {1,1}; //此处初始化列向量 LL hh[N][N]={{1,1}, {1,0} }; struct Mat { LL mat[N][N]; LL* operator [](int x) //注意这种写法 { return mat[x]; } } A; Mat Mut(Mat a,Mat b) { Mat c; memset(c.mat,0,sizeof(c.mat)); for(int i=0; i<N; i++) for(int k=0; k<N; k++) if(a[i][k]) for(int j=0; j<N; j++) { c[i][j]+=a[i][k]*b[k][j]%mod; c[i][j]=c[i][j]%mod; } return c; } Mat Qpow(Mat a,LL n) { Mat c; for(int i=0; i<N; ++i) for(int j=0; j<N; ++j) c[i][j]=(i==j); for(; n; n>>=1) { if(n&1) c=Mut(c,a); a=Mut(a,a); } return c; } LL cal(Mat A,LL n,LL b[]) { Mat A_=Qpow(A,n-1); LL ret=A_[0][0]*b[0]+A_[0][1]*b[1]; return (ret+mod)%mod; } void init_A() { for(int i=0; i<N; i++) for(int j=0; j<N; j++) A[i][j]=hh[i][j]; } int main() { LL n,ans; init_A(); while(cin>>n) { ans=cal(A,n,b); //假定下标从第1项开始计数,求第n项 cout<<ans<<endl; } }
Lv. 0
棋盘规模 k*n (k<=7,n很大)
利用dfs推出状态转移矩阵(矩阵规模 (2k)2 )
有一点要注意的是,比如说求的是两列的递推矩阵,那么前一列如果对应位是0,那么递推时,要在该位置横放一个骨牌,使当前列该为1
然后用矩阵快速幂求解
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=128; const LL mod=12357; int n,k,M; LL b[N];//= {0,0,0,0,0,0,0,1}; //此处初始化列向量 struct Mat { LL mat[N][N]; LL* operator [](int x) //注意这种写法 { return mat[x]; } } A; Mat Mut(Mat a,Mat b) { Mat c; memset(c.mat,0,sizeof(c.mat)); for(int i=0; i<M; i++) for(int k=0; k<M; k++) if(a[i][k]) for(int j=0; j<M; j++) { c[i][j]+=a[i][k]*b[k][j]%mod; c[i][j]=c[i][j]%mod; } return c; } Mat Qpow(Mat a,LL n) { Mat c; for(int i=0; i<M; ++i) for(int j=0; j<M; ++j) c[i][j]=(i==j); for(; n; n>>=1) { if(n&1) c=Mut(c,a); a=Mut(a,a); } return c; } LL cal(Mat A,LL n,LL b[]) { Mat A_=Qpow(A,n); return A_[M-1][M-1]; } void dfs(int pre,int nxt,int col,Mat& A) { if(col==k) { A[pre][nxt]=1; return ; } dfs(pre<<1,nxt<<1|1,col+1,A); dfs(pre<<1|1,nxt<<1,col+1,A); if(col+2<=k) dfs(pre<<2|3,nxt<<2|3,col+2,A); } int main() { while(cin>>k>>n) { memset(b,0,sizeof(b)); M=1<<k; b[M-1]=1; memset(A.mat,0,sizeof(A.mat)); dfs(0,0,0,A); LL ans=cal(A,n,b); //假定下标从第1项开始计数,求第n项 cout<<ans<<endl; } }
Lv. 1
棋盘规模 n*m (n,m<=11)
这时矩阵乘法的复杂度就太大了,可以直接利用利用递推关系搞
//#include<bits/stdc++.h> #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; typedef long long LL; const int N=2048; int n,k,M; int A[13][N]; void dfs(int pre,int nxt,int col,int r) { if(col==k) { A[r][nxt]+=A[r-1][pre]; return ; } dfs(pre<<1,nxt<<1|1,col+1,r); dfs(pre<<1|1,nxt<<1,col+1,r); if(col+2<=k) dfs(pre<<2|3,nxt<<2|3,col+2,r); } int main() { while(cin>>k>>n) { // cout<<k<<‘ ‘<<n<<endl; if(k==0&&n==0) break; if(k%2&&n%2) { puts("0"); continue; } memset(A,0,sizeof(A)); if(k>n) swap(k,n); M=1<<k; A[0][M-1]=1; for(int i=1;i<=n;i++) dfs(0,0,0,i); LL ans=A[n][M-1]; cout<<ans<<endl; } }
Lv. 2
未解决
棋盘规模 n*m (n,m<=100)
感觉这题应该不会考吧,出题人似乎是看过论文之后,强行按照论文出了个题
棋盘规模 n*m (n,m<=16)
稳定/免分割线多米诺骨牌的棋盘覆盖问题
要利用前面的Lv. 2的方法打表,然后用容斥原理解决,目前还不是很懂
时间: 2024-11-08 06:22:45