【jzoj4854】【小澳的坐标系】【动态规划】【矩阵快速幂】

题目大意

小澳在坐标系的原点,他可以向上、向左或者向右走。他可以走n步,但不能经过相同的点。小澳想知道他有多少种走法。

解题思路

f[i]表示可以走i步的答案,当i>4是f[i]=f[i-2]*3-f[i-2]*2+f[i-3]+f[i-4]。接着就是矩阵快速幂。

code

#include
#include
#include
#include
#include
#include
#define LL long long
#define LD double
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a>b)?b:a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const inf=2147483647;
int const maxn=100000;
int n;
LL ans[10][10],mat[10][10],tmp[10][10],mod=1e9+7;
void multansmat(){
    fo(i,1,4)fo(j,1,4)tmp[i][j]=0;
    fo(i,1,4)
        fo(j,1,4)
            fo(k,1,4)
                tmp[i][k]=(tmp[i][k]+ans[i][j]*mat[j][k])%mod;
    fo(i,1,4)fo(j,1,4)ans[i][j]=tmp[i][j];
}
void multmatmat(){
    fo(i,1,4)fo(j,1,4)tmp[i][j]=0;
    fo(i,1,4)
        fo(j,1,4)
            fo(k,1,4)
                tmp[i][k]=(tmp[i][k]+mat[i][j]*mat[j][k])%mod;
    fo(i,1,4)fo(j,1,4)mat[i][j]=tmp[i][j];
}
int main(){
    //freopen("sunset.in","r",stdin);
    //freopen("sunset.out","w",stdout);
    freopen("coordinate.in","r",stdin);
    freopen("coordinate.out","w",stdout);
    scanf("%d",&n);
    ans[1][1]=1;ans[1][2]=3;ans[1][3]=7;ans[1][4]=17;
    if(n<=3){
        printf("%lld",ans[1][n+1]);
        return 0;
    }
    n-=3;
    mat[1][4]=mat[2][1]=mat[2][4]=mat[3][2]=mat[4][3]=1;
    mat[3][4]=-2;mat[4][4]=3;
    for(;n;){
        if(n&1)multansmat();
        multmatmat();
        n=n>>1;
    }
    printf("%lld",ans[1][4]);
    return 0;
}

你可能感兴趣的:(动态规划,jzoj,其他重要思想)