【BZOJ4417】: [Shoi2013]超级跳马

题目链接:

  传送。

题解:

  矩阵快速幂优化DP。

  先考虑$nm^2$DP,设$f_{(i,j)}$表示从$1,1$到$i,j$的方案,显然这个方程和奇偶性有关,我们考虑某列的$i$同奇偶性的转移和奇偶性相异的贡献,很容易把刚才的方程变成$nm$的轮换式方程,即$f_{(0/1,j)}$表示偶/奇数列第$j$行的方案数。此时转移方程为$$f_{(i,j)}=f_{(i,j)}+\sum_{x=-1}^{1}f_{(i(xor)1,j+x)}$$

  然后考虑如何用矩阵优化,画图发现十字相乘时,如果我们把奇偶分成两列会没办法转移,然后考虑十字相乘性质,我们可以把奇偶两列转换为一列上的两段,这样我们构建$(2n)^2$的矩阵,至于递推矩阵,YY一下即可。

代码:

  

#define Troy 10/24/2017

#include <bits/stdc++.h>

using namespace std;

inline int read(){
    int s=0,k=1;char ch=getchar();
    while(ch<'0'|ch>'9')    ch=='-'?k=-1:0,ch=getchar();
    while(ch>47&ch<='9')    s=s*10+(ch^48),ch=getchar();
    return s*k;
}

const int mod=30011;

int n,m;

struct Matrix{
    int a[101][101];
    Matrix(){memset(a,0,sizeof(a));}
    inline void e1(){
        for(int i=1;i<=2*n;i++)
            a[i][i]=1;
    }
    inline friend Matrix operator *(Matrix x,Matrix y){
        Matrix z;
        for(int i=1;i<=2*n;i++)
            for(int j=1;j<=2*n;j++)
                for(int k=1;k<=2*n;k++)    
                    z.a[i][j]=(z.a[i][j]+x.a[i][k]*1ll*y.a[k][j])%mod;
        return z;
    }
    inline friend Matrix operator ^(Matrix a,long long b){
        Matrix ret;ret.e1();
        while(b){
            if(b&1) ret=ret*a;
            a=a*a;b>>=1;
        }return ret;
    }
};

int main(){
    n=read(),m=read();
    if(m==1){
        puts(n==1?"1":"0");
        return 0;
    }
    Matrix ans;
    ans.a[1+n][1]=1;
    if(n>1)
        ans.a[2+n][1]=1;
    Matrix t;
    for(int i=1;i<=n;i++){
        t.a[i][i+n]=1;
        t.a[i+n][i]=1;
        t.a[i+n][i+n]=1;
        if(i-1)
            t.a[i+n][i+n-1]=1;
        if(i+1<=n)
            t.a[i+n][i+n+1]=1;
    }
    ans=(t^(m-2))*ans;
    printf("%d",ans.a[2*n][1]);
}

 

posted @ 2017-10-24 17:57  Troywar  阅读(197)  评论(0编辑  收藏  举报