zoukankan      html  css  js  c++  java
  • 矩阵快速幂基础

    这里放一下矩阵快速幂的模板.

    首先我们怎样记得转移矩阵的行列数呢,我么用手比划一下,先横,再竖着.为答案矩阵的一个元素,

    所以第一个矩阵的列数与转移矩阵的横数相等,转移矩阵的列数与答案矩阵的列数相等...

    205. 斐波那契

        #include<bits/stdc++.h>
        #define db double
        #define ll long long
        #define reg register
        #define pb(x) push_back(x)
        #define fup(i,x,y) for(reg int i=x;i<=y;++i)
        #define fdw(i,x,y) for(reg int i=x;i>=y;--i)
        using namespace std;
        const int mod=10000;
        int n;
        struct wy
        {
            ll a[5][5];
            wy(){memset(a,0,sizeof(a));}
            inline void clear ()
            {
                memset(a,0,sizeof(a));
            }
            wy friend operator *(wy a,wy b) 
            {
                wy c;
                fup(i,1,2) fup(j,1,2) fup(k,1,2) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
                return c;
            }
            wy friend operator ^(wy a,ll y)
            {
                wy c;
                fup(i,1,2) c.a[i][i]=1;
                while(y)
                {
                    if(y&1) c=c*a;
                    y>>=1;
                    a=a*a;
                 }
                 return c;
            } 
        }A,B,C;
        inline int read()
        {
            int x=0,ff=1;
            char ch=getchar();
            while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
            while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
            return x*ff;
        }
        int main()
        {
            freopen("1.in","r",stdin);
            B.a[1][1]=0;B.a[1][2]=1;
            B.a[2][1]=1;B.a[2][2]=1;
            while(1)
            {
                n=read();
                if(n==-1) break;
                if(n<=2) 
                {
                    if(n==0) puts("0");
                    else puts("1");
                    continue;
                }
                A.clear();
                A.a[1][1]=1;A.a[1][2]=1;
                C=B^(n-2);
                A=A*C;
                printf("%lld
    ",A.a[1][2]);
            }
            return 0;
        }
        
    View Code

     206. 石头游戏

    注意判断边界..

    #include<bits/stdc++.h>
    #define db double
    #define ll long long
    #define reg register
    #define pb(x) push_back(x)
    #define fup(i,x,y) for(reg int i=x;i<=y;++i)
    #define fdw(i,x,y) for(reg int i=x;i>=y;--i)
    using namespace std;
    int l=64,n,m,t,act;
    int d[10][10],len[20];
    char st[20][10];
    struct wy
    {
        ll a[70][70];
        wy(){memset(a,0,sizeof(a));}
        inline void dan()
        {
            memset(a,0,sizeof(a));
            fup(i,0,l) a[i][i]=1;
        }
        wy friend operator *(wy a,wy b)
        {
            wy c;
            fup(i,0,l) fup(j,0,l) fup(k,0,l) c.a[i][j]=c.a[i][j]+a.a[i][k]*b.a[k][j];
            return c;
        }
        wy friend operator ^(wy a,ll y)
        {
            wy c;
            fup(i,0,l) c.a[i][i]=1;
            while(y)
            {
                if(y&1) c=c*a;
                y>>=1;
                a=a*a;
            }
            return c;
        }
    }A[70],B,C;    
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    int main()
    {
        n=read();m=read();t=read();act=read();
        fup(i,1,n) fup(j,1,m) 
        {
            char c;cin>>c;
            d[i][j]=c-'0';
        }
        fup(i,0,act-1) scanf("%s",st[i]+1),len[i]=strlen(st[i]+1);
        fup(k,1,60)
        {
            A[k].a[0][0]=1;
            fup(i,1,n) fup(j,1,m)
            {
                int id=(i-1)*m+j;
                int op=k%len[d[i][j]]?(k%len[d[i][j]]):(len[d[i][j]]);
                if(st[d[i][j]][op]>='0'&&st[d[i][j]][op]<='9')
                {
                    A[k].a[0][id]=st[d[i][j]][op]-'0';
                    A[k].a[id][id]=1;
                }
                else if(st[d[i][j]][op]=='D') continue;
                else 
                {
                    if(st[d[i][j]][op]=='N'&&i!=1) A[k].a[id][(i-2)*m+j]=1;
                    else if(st[d[i][j]][op]=='W'&&j!=1) A[k].a[id][id-1]=1;
                    else if(st[d[i][j]][op]=='S'&&i!=n) A[k].a[id][i*m+j]=1;
                    else if(st[d[i][j]][op]=='E'&&j!=m) A[k].a[id][id+1]=1;
                }
            }
        }
        C.dan();
        fup(i,1,60) C=C*A[i];
        C=C^(t/60);
        B.a[1][0]=1;
        B=B*C;
        fup(i,1,t%60) 
        {
            B=B*A[i];
        }
        ll ans=0;
        fup(i,1,n*m) ans=max(ans,B.a[1][i]);
        printf("%lld",ans);
        return 0;
    }
    View Code

    [TJOI2017]可乐

    //又是一眼看过去就没有思路的题...
    //算了,还是慢慢来吧,一点一点看这道题..
    //首先看到这道题的第一印象,dp嗯..
    //可后来发现由于好像有环...好像不怎么行,但还是得抱着人有多大胆,地有多大产的思想试试.
    //我们设f[i][j]表示前j秒到达i的方案数...f[i][j]+=f[k][j-1]..(k->i). 
    //但好像有环,且原地不动和自爆怎么搞...不行,看来dp不能用这种形式瞎搞,思考这道题的本质.
    //题目给定无向图,求在t内的所有方案数....
    //由于最开始处于1号点,实际上就是求1号点在t时间内到其他点的方案数. 
    //我们思考如何求到其他点的方案数...我们发现由于环的缘故我们不能简单的用上一个dp类似的状态求解.
    //这要求我们增加状态,设f[i][j]表示i到j的方案数.显然f[i][j]=f[i][k]*f[k][j].
    //(这样思考,我们由于无法确定从哪过来的所以这样记录下来.表示前t秒从i到j的方案数.所以不用管t秒是如何分配的)
    //之后思考原地不动和爆炸如何搞定.原地不动就是待在原地,那连个自环即可.爆炸就是我们新建一个虚拟节点,只从各个节点
    //向它连边即可,这样就能达到爆炸就无法复原的效果了.
    //之后由于时间的限制,我们无法快速求解上面的dp,但却能惊奇的发现,好像矩阵乘法啊.....
    //于是就愉快地写题了. 
    #include<bits/stdc++.h>
    #define db double
    #define ll long long
    #define reg register
    #define pb(x) push_back(x)
    #define fup(i,x,y) for(reg int i=x;i<=y;++i)
    #define fdw(i,x,y) for(reg int i=x;i>=y;--i)
    using namespace std;
    const int N=110,mod=2017;
    int n,m,t;
    struct wy
    {
        int a[N][N];
        wy(){memset(a,0,sizeof(a));}
        wy friend operator *(wy a,wy b)
        {
            wy c;
            fup(i,0,n) fup(j,0,n) fup(k,0,n) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
            return c;
        }
        wy friend operator ^(wy a,int y)
        {
            wy c;
            fup(i,0,n) c.a[i][i]=1;
            while(y)
            {
                if(y&1) c=c*a;
                y>>=1;
                a=a*a;
            }
            return c;
        }
    }C;
    inline int read()
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    int main()
    {
        freopen("1.in","r",stdin);
        n=read();m=read();
        fup(i,1,m)
        {
            int x=read(),y=read();
            C.a[x][y]=1;C.a[y][x]=1;
        }
        t=read();
        fup(i,0,n) C.a[i][0]=1,C.a[i][i]=1;
        C=C^t;
        int ans=0;
        fup(i,0,n) ans=(ans+C.a[1][i])%mod;
        printf("%d",ans);
        return 0;
    }
    View Code

    P5175 数列

    #include<bits/stdc++.h>
    #define db double
    #define ll long long
    #define reg register
    #define pb(x) push_back(x)
    #define rep(i,x,y) for(reg int i=x;i<=y;++i)
    #define fdw(i,x,y) for(reg int i=x;i>=y;--i)
    using namespace std;
    const int mod=1e9+7;
    ll T,n,a1,a2,x,y; 
    struct wy
    {
        ll a[5][5];
        wy() {memset(a,0,sizeof(a));}
        inline void clear()    {memset(a,0,sizeof(a));}
        wy friend operator *(wy a,wy b)
        {
            wy c;
            rep(i,1,4) rep(j,1,4) rep(k,1,4) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod;
            return c;
        }
        wy friend operator ^(wy a,ll y)
        {
            wy c;
            rep(i,1,4) c.a[i][i]=1;
            while(y)
            {
                if(y&1) c=c*a;
                y>>=1;
                a=a*a;
            }
            return c;
        } 
    }A,B;
    inline ll read()
    {
        ll x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        T=read();
        while(T--)
        {
            n=read();a1=read();a2=read();x=read();y=read();
            if(n==1) printf("%lld
    ",a1*a1%mod);
            else if(n==2) printf("%lld
    ",(a1*a1%mod+a2*a2%mod)%mod);
            else 
            {
                A.clear();B.clear();
                A.a[1][1]=a1*a1%mod;A.a[1][2]=a2*a2%mod;A.a[1][3]=a1*a2%mod;A.a[1][4]=(a1*a1%mod+a2*a2%mod)%mod;
                B.a[1][1]=0;B.a[1][2]=y*y%mod;B.a[1][3]=0;B.a[1][4]=y*y%mod;
                B.a[2][1]=1;B.a[2][2]=x*x%mod;B.a[2][3]=x;B.a[2][4]=x*x%mod;
                B.a[3][1]=0;B.a[3][2]=2*x*y%mod;B.a[3][3]=y;B.a[3][4]=2*x*y%mod;
                B.a[4][1]=0;B.a[4][2]=0;B.a[4][3]=0;B.a[4][4]=1;
                B=B^(n-2);
                A=A*B;
                printf("%lld
    ",A.a[1][4]);
            }    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Ubuntu分区挂载
    YOLOv3:Demo needs OpenCV for webcam images
    tf.strided_slice函数
    numpy:np.random.seed()
    python:split()函数
    python:set() 函数
    python:zip() 函数
    python:enumerate 函数
    电脑无法上网,DNS出现fec0:0:0:ffff::1%1问题
    python:map 函数
  • 原文地址:https://www.cnblogs.com/gcfer/p/12720606.html
Copyright © 2011-2022 走看看