Description
现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角。每一步它向右跳奇数列,且跳到本行或相邻行。跳越期间,马不能离开棋盘。例如,当n = 3, m = 10时,下图是一种可行的跳法。
试求跳法种数mod 30011。
Input
仅有一行,包含两个正整数n, m,表示棋盘的规模。
Output
仅有一行,包含一个整数,即跳法种数mod 30011。
Sample Input
3 5
Sample Output
10
HINT
对于100%的数据,1 ≤ n ≤ 50,2 ≤ m ≤ 10^9
目测要完啦,矩阵不会推啦。
大致是维护奇数项和偶数项的前缀和,然后矩阵快速幂。
忘记判n=1然后WA了好几发。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } typedef long long ll; const int mod=30011; const int maxn=110; int N; struct Matrix { ll A[maxn][maxn]; Matrix operator * (const Matrix& b) const { Matrix c; rep(i,1,N) rep(j,1,N) { c.A[i][j]=0; rep(k,1,N) c.A[i][j]+=A[i][k]*b.A[k][j]; c.A[i][j]%=mod; } return c; } }; void pow(Matrix& ans,int n) { Matrix t;t=ans;n--; while(n) { if(n&1) ans=ans*t; t=t*t;n>>=1; } } int main() { int n=read(),m=read(); Matrix ans;N=n*2; memset(ans.A,0,sizeof(ans.A)); rep(i,1,n) ans.A[i][i+n]=1; rep(i,n+1,2*n) { ans.A[i][i-n]=ans.A[i-n][i-n]=1; if(i-n>1) ans.A[i-n-1][i-n]=1; if(i-n<n) ans.A[i-n+1][i-n]=1; } pow(ans,m-1); printf("%lld ",(ans.A[N][1]+(n>1?ans.A[N-1][1]:0))%mod); return 0; }