zoukankan      html  css  js  c++  java
  • [SHOI2013] 超级跳马

    题意:

    现有一个n行m列的棋盘,一只马欲从棋盘的左上角跳到右下角。

    每一步它向右跳奇数列,且跳到本行或相邻行,但不能离开棋盘。

    求跳的方案数,对30011取模。

    $nleq 50,mleq 10^{9}$。

    题解:

    挺水的一道题。设$dp_{i,j}$为走到$(i,j)$的方案数,那么$dp_{i,j}=sum limits_{k\%2 eq j\%2}^{k<j}{dp_{i-1,k}+dp_{i,k}+dp_{i+1,k}}$。

    令$F_{i,j}=sum limits_{k\%2=0}^{kleq j}{dp_{i,k}},G_{i,j}=sum limits_{k\%2=1}^{kleq j}{dp_{i,k}}$,那么

    • 若$j\%2=1$,则$F_{i,j}=F_{i,j-1},G_{i,j}=G_{i,j-1}+F_{i-1,j-1}+F_{i,j-1}+F_{i+1,j-1}$。
    • 若$j\%2=0$,则$F_{i,j}=F_{i,j-1}+G_{i-1,j-1}+G_{i,j-1}+G_{i+1,j-1},G_{i,j}=G_{i,j-1}$。

    于是直接用$2n imes 2n$的矩阵转移F和G,最后用两个前缀和相减即可得到答案。

    复杂度$O(n^{3}log{m})$。注意矩阵乘法不满足交换律,必须按顺序乘。

    套路:

    • 矩阵乘法优化dp:i状态能转移到j状态$ ightarrow A_{i,j}=1$。
    • 形如$dp_{i,j}=sum dp_{k,j-1}$的转移$ ightarrow$矩阵乘法优化。
    • 矩阵乘法:不满足交换律,必须按顺序乘。

    代码:

    #include<bits/stdc++.h>
    #define maxn 205
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define mod 30011
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    struct Matrix{
        ll x,y,M[maxn][maxn];
        Matrix operator*(const Matrix b)const{
            Matrix res; res.x=x,res.y=b.y;
            for(ll i=1;i<=x;i++)
                for(ll j=1;j<=b.y;j++){
                    res.M[i][j]=0;
                    for(ll k=1;k<=y;k++)
                        res.M[i][j]=(res.M[i][j]+M[i][k]*b.M[k][j]%mod)%mod;
                }
            return res;
        }
    }A,B,C;
    
    inline ll read(){
        ll 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;
    }
    
    inline Matrix pw(Matrix a,ll b){
        Matrix res; res.x=res.y=0;
        while(b){
            if(b&1) res=(!res.x)?a:res*a;
            a=a*a,b>>=1;
        } 
        return res;
    }
    
    inline Matrix solve(int m){
        if(m&1) return A*pw(C*B,m/2)*C;
        else return A*pw(C*B,m/2);
    }
    
    /*inline void print(Matrix a){
        for(int i=1;i<=a.x;i++){
            for(int j=1;j<=a.y;j++)
                cout<<a.M[i][j]<<" ";
            cout<<endl;    
        }
        fgx;
    }*/
    
    int main(){
        ll n=read(),m=read();
        A.x=1,A.y=2*n,B.x=B.y=C.x=C.y=2*n,A.M[1][1]=1;
        for(ll i=1;i<=n;i++){
            B.M[i][i]=1,B.M[i+n][i+n]=1,B.M[i+n][i]=1;
            if(i>1) B.M[i+n-1][i]=1; 
            if(i<n) B.M[i+n+1][i]=1;
        }
        for(ll i=1;i<=n;i++){
            C.M[i][i]=1,C.M[i+n][i+n]=1,C.M[i][i+n]=1;
            if(i>1) C.M[i-1][i+n]=1; 
            if(i<n) C.M[i+1][i+n]=1;
        }
        //print(A),print(B),print(C);
        Matrix t1=solve(m-1),t2=solve(m-2);
        //print(t1),print(t2);
        if(m%2) printf("%lld
    ",(t1.M[1][n]-t2.M[1][n]+mod)%mod);
        else printf("%lld
    ",(t1.M[1][2*n]-t2.M[1][2*n]+mod)%mod);
        return 0;
    }
    超级跳马
  • 相关阅读:
    Dubbo2.0
    Dubbo--RPC框架
    ActiveMQ消息队列
    quartz开源任务调度框架
    webService
    crud最常用
    springBoot第三天
    springmvc--依赖
    springBoot第二天
    pom.xml和settings.xml的下载优先级
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13237959.html
Copyright © 2011-2022 走看看