矩阵快速幂 小澳的坐标系

1 篇文章 0 订阅
1 篇文章 0 订阅

矩阵快速幂

矩阵快速幂一般是为了求解递推问题
eg:菲波那切数列

关于矩阵快速幂,可以参见这里AND这里

2. 小澳的 坐标系

(coordinate.cpp/c/pas )

【题目描述】
小澳者表也,数学者景也,表动则景随矣。
小澳不喜欢数学,可数学却待小澳如初恋,小澳睡觉的时候也不放过。
小澳的梦境中出现了一个平面直角坐标系,自原点,向四方无限延伸。
小澳在坐标系的 原点,他可以 向上、向左或者向右走。他可以走 n 步, 但不能经过相同的点。
小澳想知道他有多少种走法。
【输入格式】
输入文件名为 coordinate.in。
输入文件仅第一行一个正整数 n,表示小澳可以走的步数。
【输出格式】
输出文件名为 coordinate.out。
输出文件共一行,输出一个正整数,表示答案(对 10^9+7 取模)。
【输入输出样例 1 】
in:
2

out:
7
【输入输出样例 1 说明】
从(0,0)出发走 2 步,共 7 种走法:
(0,0)->(0,1)->(0,2)
(0,0)->(0,1)->(1,1)
(0,0)->(0,1)->(-1,1)
(0,0)->(1,0)->(2,0)
(0,0)->(1,0)->(1,1)
(0,0)->(-1,0)->(-2,0)
(0,0)->(-1,0)->(-1,1)
【输入输出样例 2 】
in:
3

out:
17
【数据规模与约定 】
测试点编号  n
1~2  n<=10
3~4  n<=100
5~6  n<=1000
7~8  n<=10^6
9~10  n<=10^9

Solution:
做这题的时候先写了一个走迷宫的暴力DFS,找到递推公式
//DFS暴力
#include<cstdio>
#define LL long long
#define mod 100000
using namespace std;

int n,cnt;
int map[2002][2009];
int u[3]={0,1,0},v[3]={1,0,-1};

bool inmap(int a,int b){
    return a>=1 && a<=n+1 && b>=1 && b<=2*n+1;
}

void DFS(int x,int y,int t){
    int i;
    if(t==n){
        cnt++;
        if(cnt==mod) cnt=0;
        return;
    }
    for(i=0;i<3;i++){
        int xx=x+u[i],yy=y+v[i];
        if(!map[xx][yy] && inmap(xx,yy)){
            map[xx][yy]=1;
            DFS(xx,yy,t+1);
            map[xx][yy]=0;
        }
    }
}

int main(){
    freopen("coordinate.in","r",stdin);
    freopen("coordinate.out","w",stdout);
    scanf("%d",&n);
    map[1][n+1]=1;
    DFS(1,n+1,0);
    printf("%d",cnt);
    return 0;
}
十以内可以解决了(20分)

然后将1~10内的解输出来找到递推关系


矩阵快速幂之所以要用,是因为它确实求递推式的时候很快

一般递推:
//SLOW
#include<cstdio>
#define LL long long
#define mod 1000000007
using namespace std;

int n;

void solve(){
    if(n==1) {
        printf("3\n");
        return;
    }
    if(n==2){
        printf("7\n");
        return;
    }
    LL f1=3,f2=7,f3;
    int i;
    for(i=3;i<=n;i++){
        f3=2*f2+f1;
        f3%=mod;
        f1=f2;f2=f3;
    }
    printf("%I64d",f3%mod);
}

int main(){
    freopen("coordinate.in","r",stdin);
    freopen("coordinate.out","w",stdout);
    scanf("%d",&n);
    solve();
    return 0;
}
矩阵快速幂:
//FAST
#include<cstdio>
#define LL long long
#define mod 1000000007

int n;
struct M{
    LL map[3][3];
};

M s;

M work(M x,M y){
    int i,j,k;
    M ans;
    ans.map[1][1]=ans.map[1][2]=ans.map[2][1]=ans.map[2][2]=0;
    for(i=1;i<=2;i++){
        for(j=1;j<=2;j++){
            for(k=1;k<=2;k++){
                ans.map[i][j]+=x.map[i][k]*y.map[k][j];
            }
            ans.map[i][j]%=mod;
        }
    }
    return ans;
}

void solve(){
    M tmp;
    n-=2;
    tmp.map[1][1]=tmp.map[0][2]=0;tmp.map[1][2]=1;tmp.map[2][1]=1;tmp.map[2][2]=2;
    while(n){
        if(n&1){
            s=work(tmp,s);
        }
        tmp=work(tmp,tmp);
        n>>=1;
    }
    printf("%d",s.map[2][1]%mod);
}

int main(){
    freopen("coordinate.in","r",stdin);
    freopen("coordinate.out","w",stdout);
    scanf("%d",&n);
    if(n==1){
        printf("3\n");return 0;
    }
    if(n==2){
        printf("7\n");return 0;
    }
    s.map[1][1]=3;s.map[2][1]=7;
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值