BZOJ4417: [Shoi2013]超级跳马

Description

现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角。每一步它向右跳奇数列,且跳到本行或相邻行。跳越期间,马不能离开棋盘。例如,当n = 3, m = 10时,下图是一种可行的跳法。
  BZOJ4417: [Shoi2013]超级跳马_第1张图片
试求跳法种数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\n",(ans.A[N][1]+(n>1?ans.A[N-1][1]:0))%mod);
    return 0;
}
View Code

你可能感兴趣的:(BZOJ4417: [Shoi2013]超级跳马)