05 矩阵优化 (斜率优化等待补)

矩阵快速幂

https://www.luogu.com.cn/problem/P3390
就是矩阵乘法+快速幂,本来想用宏定义定义mod,结果不知道为什么会出错,改成const就过了

//#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll max_n=1e5+1000;
const ll inf=0x3f3f3f3f;
ll n,m,a[120][120];
struct mat{
    int len;
    ll m[110][110];
    mat times(mat b){
        mat c;
        c.len=len;
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                ll res=0;
                for(int v=0;v<len;v++){
                    res+=m[i][v]*b.m[v][j]%mod;
                }c.m[i][j]=(res+mod)%mod;
            }
        }
        return c;
    }
    void output(){
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                cout<<m[i][j]<<' ';
            }cout<<endl;
        }
    }
    void uni(){
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                if(i==j) m[i][j]=1;
                else m[i][j]=0;
            }
        }
    }
};
mat qmp(mat a,ll k){
    mat res,x;
    res.len=a.len;
    x.len=a.len;
    res.uni(),x=a;
    while(k){
        if(k&1){
            res=res.times(x);
        }x=x.times(x);
        k>>=1;
    }
    return res;
}
int main(){
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    mat a;
    a.len=n;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>a.m[i][j];
        }
    }
    qmp(a,m).output();
    return 0;
}

矩阵加速

https://www.luogu.com.cn/problem/P1939
板子题,矩阵长这样:

\( \left[ \begin{array}{c} a_n\\ a_{n-1}\\ a_{n-2}\\ \end{array} \right] =\left[ \begin{matrix} 1& 0& 1\\ 1& 0& 0\\ 0& 1& 0\\ \end{matrix} \right] \left[ \begin{array}{c} \begin{array}{c} a_{\begin{array}{c} n-1\\ \end{array}}\\ a_{n-2}\\ \end{array}\\ a_{n-3}\\ \end{array} \right] \)
然后就是套上快速幂求就可以了,结果就是第一行的和

//#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll max_n=1e5+1000;
const ll inf=0x3f3f3f3f;
ll n,m,a[120][120];
struct mat{
    int len;
    ll m[110][110];
    mat times(mat b){
        mat c;
        c.len=len;
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                ll res=0;
                for(int v=0;v<len;v++){
                    res+=m[i][v]*b.m[v][j]%mod;
                }c.m[i][j]=(res+mod)%mod;
            }
        }
        return c;
    }
    void output(){
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                cout<<m[i][j]<<' ';
            }cout<<endl;
        }
    }
    void uni(){
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                if(i==j) m[i][j]=1;
                else m[i][j]=0;
            }
        }
    }
};
mat qmp(mat a,ll k){
    mat res,x;
    res.len=a.len;
    x.len=a.len;
    res.uni(),x=a;
    while(k){
        if(k&1){
            res=res.times(x);
        }x=x.times(x);
        k>>=1;
    }
    return res;
}
int main(){
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n;
    mat a,ans;
    a.len=3;
    a.m[0][0]=1,a.m[0][1]=0,a.m[0][2]=1;
    a.m[1][0]=1,a.m[1][1]=0,a.m[1][2]=0;
    a.m[2][0]=0,a.m[2][1]=1,a.m[2][2]=0;
    while(n--){
        cin>>m;
        if(m<=3){
            cout<<1<<endl;
            continue;
        }else{
            ans=qmp(a,m-3);
            ll res=(ans.m[0][0]+ans.m[0][1]+ans.m[0][2])%mod;
            cout<<res<<endl;
        }
        
    }
    
    return 0;
}

斐波那契公约数

https://www.luogu.com.cn/problem/P1306
事实证明,打表乃找规律第一要义,打出来前20x20个结果,发现结果总就那么几个值,又发现这些值全是本身数列里的元素,结果就可以得到以下规律:

\[gcd\left( f_n,f_m \right) =f_{gcd\left( n,m \right)} \]

然后就简单了,同上。

//#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e8;
const ll max_n=1e5+1000;
const ll inf=0x3f3f3f3f;
ll n,m,a[120][120];
struct mat{
    int len;
    ll m[110][110];
    mat times(mat b){
        mat c;
        c.len=len;
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                ll res=0;
                for(int v=0;v<len;v++){
                    res+=m[i][v]*b.m[v][j]%mod;
                }c.m[i][j]=(res+mod)%mod;
            }
        }
        return c;
    }
    void output(){
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                cout<<m[i][j]<<' ';
            }cout<<endl;
        }
    }
    void uni(){
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
                if(i==j) m[i][j]=1;
                else m[i][j]=0;
            }
        }
    }
};
mat qmp(mat a,ll k){
    mat res,x;
    res.len=a.len;
    x.len=a.len;
    res.uni(),x=a;
    while(k){
        if(k&1){
            res=res.times(x);
        }x=x.times(x);
        k>>=1;
    }
    return res;
}
ll gcd(ll a,ll b){
    if(b==0){
        return a;
    }else return gcd(b,a%b);
}
int main(){
    //freopen("in.txt","r",stdin);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>m;
    mat a,ans;
    a.len=2;
    a.m[0][0]=1,a.m[0][1]=1;
    a.m[1][0]=1,a.m[1][1]=0;
    n=gcd(n,m);
    if(n<=2){
        cout<<1<<endl;
    }else{
        ans=qmp(a,n-2);
        cout<<(ans.m[0][0]+ans.m[0][1])%mod<<endl;
    }
    return 0;
}
posted @ 2020-08-02 16:47  Zabreture  阅读(81)  评论(0编辑  收藏  举报