日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

矩阵快速幂的一份小结

發布時間:2024/4/15 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 矩阵快速幂的一份小结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

矩陣真是個好東西!雖然矩乘的復雜度有點難看... ...

這幾天也做了不少矩陣題目,還是有幾道好題目的。不過我打算從入門開始。

  • 矩陣乘法:A[i][k]*B[k][j]=C[i][j];(A的第i行的每項依次乘以B的第j列的每項的和)

  很顯然這是一個n^3的算法,還是比較難看的。

  代碼就差不多是這樣了。

struct Matrix{int T[51][51];}; Matrix Mul(Matrix a,Matrix b,int I,int K,int J) {Matrix S=S0;for(int i=1;i<=I;++i)for(int j=1;j<=J;++j)for(int k=1;k<=K;++k)S.T[i][j]=(S.T[i][j]+a.T[i][k]*b.T[k][j]%Mod)%Mod;return S; }

?

  然后我們發現矩乘有一些性質:

  • 不滿足交換律。
  • 滿足結合律。
  •   所以矩乘是可以用來快速冪的!

    • 一些題目

       題型1.手推矩陣+快速冪

        這類題目很多,簡單的有求斐波那契數列第多少多少項,難的也有,一般難題重點不在矩陣上。

        舉幾個栗子:

          1.斐波那契數列?

            剛才奶到的求第n項的問題。初始矩陣為

    10
    00

    ?

    轉移矩陣為

    11
    10

    ?

    代碼就大概長這樣。矩乘的基本操作了。

    #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #define LL long long int #define ls (x << 1) #define rs (x << 1 | 1) #define MID int mid=(l+r)>>1 using namespace std; int n,Mod,ans[2][3][3],S[3][3]; int gi() {int x=0,res=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*res; } void calc(int a,int b) {for(int i=1;i<=2;++i)for(int j=1;j<=2;++j)for(int k=1;k<=2;++k)S[i][j]=(S[i][j]+ans[a][i][k]*ans[b][k][j])%Mod;for(int i=1;i<=2;++i)for(int j=1;j<=2;++j)ans[a][i][j]=S[i][j],S[i][j]=0; } int Qpow(int z) {for(;z;z>>=1){if(z&1)calc(0,1);calc(1,1);}return ans[0][1][1]; } int main() {int T=gi();while(T--){n=gi();Mod=gi();if(n==0){printf("0\n");continue;}ans[0][1][1]=1;ans[0][1][2]=0;ans[0][2][1]=0;ans[0][2][2]=0;ans[1][1][1]=1;ans[1][1][2]=1;ans[1][2][1]=1;ans[1][2][2]=0;S[1][1]=S[1][2]=S[2][1]=S[2][2]=0;printf("%d\n",Qpow(n));}return 0; }

    ?

    ?

    ?

          2.Xn數列

          題目大意就是給你一個A[n+1]=pA[n]+q的簡單數列,求(第n項mod m)mod g;

          構造等比數列什么的出去,泥萌已經過時了。

          手玩方程構造出矩陣。初始矩陣是2*2的?

    x0?C
    00

    ?

    轉移矩陣也是2*2的

    a0
    11

    ?  剩下的也就那樣了。我也不知道為什么是大師的題目。

      哦對了矩陣乘法要用龜速乘,不然會爆。

    #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #define int long long #define ls (x << 1) #define rs (x << 1 | 1) #define MID int mid=(l+r)>>1 using namespace std; int m,a,c,x0,n,g; int A[5][5],S[5][5],ans[5][5][5]; int gi() {int x=0,res=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*res; } int aXb(int a,int b,int mod) {a%=mod;b%=mod;int ans=0;for(;b;b>>=1){if(b&1)ans=(ans+a)%mod;a=(a<<1)%mod;}return ans; } void calc(int a,int b) {for(int i=1;i<=2;++i)for(int j=1;j<=2;++j)for(int k=1;k<=2;++k)S[i][j]=(S[i][j]+aXb(ans[a][i][k],ans[b][k][j],m))%m;for(int i=1;i<=2;++i)for(int j=1;j<=2;++j)ans[a][i][j]=S[i][j],S[i][j]=0; } void Qpow(int z) {for(;z;z>>=1){if(z&1)calc(0,1);calc(1,1);} } void work() {int Ans=ans[0][1][1]%g;cout<<Ans<<endl; } main() {m=gi();a=gi();c=gi();x0=gi();n=gi();g=gi();ans[0][1][1]=x0;ans[0][1][2]=c;ans[1][1][1]=a;ans[1][2][1]=1;ans[1][2][2]=1;Qpow(n);work();return 0; }

      2.要根據輸入處理轉移矩陣。

        1.沼澤鱷魚

        來我們理理思路。

        最暴力的暴力都會打吧,隨便怎么樣的DFS或者BFS。或者你還可以加個記憶化。

        然后是一些特殊的點。在沒有任何一只鱷魚的情況下我們就可以用矩陣乘法——初始矩陣是1×n的,(1,ST)=1,其他點都是0的矩陣。轉移矩陣就是n*n對應的鄰接矩陣。(手玩體會感受一下它的轉移)。

        下面就是對鱷魚的處理了。鱷魚在那個點的話,就不能走到嘛。所以這個轉移矩陣的那個對應的"1"就要變成"0"。處理完這一秒之后這樣就變成了這一步的轉移矩陣。這樣每次都在鄰接矩陣基礎上修改轉移矩陣,也能得到正確的答案。但我們沒有控制1s的能力,這樣會T。

        再看看,發現魚的線路是有規律的,有周期的,而且只有2,3,4三種周期。所以12s后的轉移矩陣和12s前的是相同的——一個循環結出現了!于是我們興高采烈地用上矩陣乘法結合律,把一個循環結乘成一個矩陣,快速冪就好了。至于剩下的一點點余數,暴力就可以啦,反正也就那么點點東西。

    ?

    #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #define LL long long int using namespace std; struct Matrix{int T[51][51];}S0,Tx[20],Alt,Ans; int n,m,st,ed,KKK,Fish,Map[20][99],map[99][99]; int gi() {int x=0,res=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*res; } Matrix Mul(Matrix a,Matrix b,int I,int K,int J) {Matrix S=S0;for(int i=1;i<=I;++i)for(int j=1;j<=J;++j)for(int k=1;k<=K;++k)S.T[i][j]=(S.T[i][j]+a.T[i][k]*b.T[k][j]%10000)%10000;return S; } Matrix Qpow(int z) {Matrix d=Ans,f=Alt;for(;z;z>>=1,f=Mul(f,f,n,n,n))if(z&1)d=Mul(d,f,1,n,n);return d; } int main() {n=gi();m=gi();st=gi()+1;ed=gi()+1;KKK=gi();for(int i=1;i<=m;++i){int u=gi()+1,v=gi()+1;map[u][v]=map[v][u]=1;}Fish=gi();for(int i=1;i<=Fish;++i){int T=gi();for(int j=0;j<T;++j){int x=gi()+1;for(int k=j;k<12;k+=T)Map[k][x]=1;}}for(int t=0;t<12;++t)for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)if(map[i][j] && !Map[(t+1)%12][j])Tx[t].T[i][j]=1;Alt=Tx[0];Ans.T[1][st]=1;for(int i=1;i<12;++i)Alt=Mul(Alt,Tx[i],n,n,n);Ans=Qpow(KKK/12);for(int t=0,s=KKK%12;t<s;++t)Ans=Mul(Ans,Tx[t%12],1,n,n);printf("%d",Ans.T[1][ed]);return 0; }

       2.GT考試(光頭考試)

        題面就是要你找有多少種沒出現過一個數字串的數字串。

        方案,取膜,匹配,想到DP。

        設狀態。想知道有沒有出現過,就要知道有沒有匹配到m位。所以狀態就是[i,j],表示主串匹配到第i位,小串匹配到第j位。答案就是sigma F[n,i],i from 1 to m-1;

        想轉移。F[i,j]表示的既然是最多能匹配到的位置,那就必須用到KMP來求匹配的最長前綴。先預處理出來。轉移就明顯了,把上一次j的加到這一次相應的j'里面就好。這么做固然是正確的,但是會T,N<=10^9... ...

        找優化。我們發現沒一次的轉移都可以寫成f[i+1,J]=f[i,j1]*...+f[i,j2]*...+...——一階行列式!矩陣乘法!快速冪!(想想鱷魚沼澤那題,沒有鱷魚的情況就是一個一樣的一階行列式)。快速冪碼完走人。

        總結:這題思維和代碼都是有的,還要用到KMP這種東西。B站上一次過,在校內OJ被某無良WG卡了輸入... ...

    ?

    #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <cstring> #include <queue> #define LL long long int #define ls (x << 1) #define rs (x << 1 | 1) using namespace std; struct Matrix{int T[22][22];}S0,ST,Inv; int N,M,Mod,Next[25],Hash[200],A[200],Ans; int gi() {int x=0,res=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*res; } LL gl() {LL x=0,res=1;char ch=getchar();while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();return x*res; } Matrix Mul(Matrix a,Matrix b,int I,int K,int J) {Matrix S=S0;for(int i=0;i<I;++i)for(int j=0;j<J;++j)for(int k=0;k<K;++k)S.T[i][j]=(S.T[i][j]+a.T[i][k]*b.T[k][j]%Mod)%Mod;return S; } Matrix Qpow(Matrix d,int z,int len) {Matrix ans=S0;for(int i=0;i<len;++i)ans.T[i][i]=1;for(;z;z>>=1,d=Mul(d,d,len,len,len))if(z&1)ans=Mul(ans,d,len,len,len);return ans; } int main() {N=gi();M=gi();Mod=gi();for(int i=1;i<=M;++i)A[i]=getchar()-'0';Next[1]=0;ST.T[0][0]=1;for(int i=2,j=0;i<=M;++i){while(j&&A[j+1]!=A[i])j=Next[j];if(A[j+1]==A[i])++j;Next[i]=j;}for(int i=0;i<M;++i)for(int j=0;j<10;++j){int x=i;while(x && A[x+1]!=j)x=Next[x];if(A[x+1]==j)Inv.T[i][x+1]=(Inv.T[i][x+1]+1)%Mod;else Inv.T[i][0]=(Inv.T[i][0]+1)%Mod;}Inv=Qpow(Inv,N,M);ST=Mul(ST,Inv,M,M,M);for(int i=0;i<M;++i)Ans=(Ans+ST.T[0][i])%Mod;printf("%d\n",Ans);return 0; }

    ?

    ?

    ?

        

    上面幾題都是很水的題目了(by An***大佬,我知道他不會看見),祝大家統統成神犇!    

    ?

    轉載于:https://www.cnblogs.com/fenghaoran/p/6575311.html

    總結

    以上是生活随笔為你收集整理的矩阵快速幂的一份小结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。