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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

矩阵乘法学习记录

發(fā)布時間:2023/12/3 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 矩阵乘法学习记录 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這要從校賽的一個區(qū)間與非操作題說起,群里大佬用的ddp思想使其滿足結(jié)合律,但是我連矩陣乘法都不會于是從頭開始學(xué)習(xí)矩陣乘法。

P3390 【模板】矩陣快速冪

和快速冪一模一樣,只是把數(shù)乘換成矩陣乘,只需要定義結(jié)構(gòu)體矩陣然后重載一下乘法*即可。
注意:
111乘以任何數(shù)都等于這個數(shù)本身
單位矩陣乘以任何矩陣就等于這個矩陣本身

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=110; int n; ll k; struct node {ll m[N][N];node(){memset(m,0,sizeof m);};node operator *(const node &b) const{node res;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)for(int k=1;k<=n;k++) res.m[i][j]=(res.m[i][j]+m[i][k]*b.m[k][j])%mod;return res;} }; node qmi(node a,ll b) {node res;for(int i=1;i<=n;i++)// 單位矩陣res.m[i][i]=1;while(b){if(b&1) res=res*a;a=a*a;b>>=1;}return res; } int main() {IO;int T=1;//cin>>T;while(T--){node a;cin>>n>>k;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) cin>>a.m[i][j];node res=qmi(a,k);for(int i=1;i<=n;i++){for(int j=1;j<=n;j++) cout<<res.m[i][j]<<' ';cout<<'\n';}}return 0; }

P1962 斐波那契數(shù)列

[0011][fn?2fn?1]=[fn?1fn]→[0011]n?2[f1f2]=[fn?1fn]\begin{bmatrix} 0 & 0 \\ 1&1 \end{bmatrix} \begin{bmatrix} f_{n-2}\\f_{n-1} \end{bmatrix}=\begin{bmatrix} f_{n-1}\\f_{n} \end{bmatrix} \to\begin{bmatrix} 0 & 0 \\ 1&1 \end{bmatrix}^{n-2} \begin{bmatrix} f_{1}\\f_{2} \end{bmatrix}=\begin{bmatrix} f_{n-1}\\f_{n} \end{bmatrix} [01?01?][fn?2?fn?1??]=[fn?1?fn??][01?01?]n?2[f1?f2??]=[fn?1?fn??]
矩陣乘法滿足結(jié)合律,由此可以根據(jù)上述式子進(jìn)行矩陣快速乘

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const ll mod=1e9+7; const int N=110; int sz;//矩陣大小 ll n,k; struct node {ll m[N][N];node(){memset(m,0,sizeof m);};node operator *(const node &b) const{node res;for(int i=1;i<=sz;i++)for(int j=1;j<=sz;j++)for(int k=1;k<=sz;k++) res.m[i][j]=(res.m[i][j]+m[i][k]*b.m[k][j])%mod;return res;} }; node qmi(node a,ll b) {node res;for(int i=1;i<=sz;i++)// 單位矩陣res.m[i][i]=1;while(b){if(b&1) res=res*a;a=a*a;b>>=1;}return res; } int main() {IO;int T=1;//cin>>T;while(T--){cin>>n;if(n<=2) {cout<<1<<'\n';continue;}sz=2;node a;a.m[1][1]=0,a.m[1][2]=1,a.m[2][1]=1,a.m[2][2]=1;node res=qmi(a,n-2);ll ans=0;ans=(ans+res.m[1][2]+res.m[2][2])%mod;cout<<ans<<'\n';}return 0; }

P1939 【模板】矩陣加速(數(shù)列)和上面這個題基本一樣。

P2044 [NOI2012]隨機(jī)數(shù)生成器

[a101][xn?1c]=[xnc]→[a101]n[x0c]=[xnc]\begin{bmatrix} a & 1 \\ 0&1 \end{bmatrix} \begin{bmatrix} x_{n-1}\\c \end{bmatrix}=\begin{bmatrix} x_{n}\\c \end{bmatrix} \to\begin{bmatrix} a & 1 \\ 0&1 \end{bmatrix}^n \begin{bmatrix} x_{0}\\c \end{bmatrix}=\begin{bmatrix} x_{n}\\c \end{bmatrix}[a0?11?][xn?1?c?]=[xn?c?][a0?11?]n[x0?c?]=[xn?c?]
這題比較dt的地方是兩個數(shù)相乘會爆long long,于是上龜速乘防止乘積爆

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=110; int sz;//矩陣大小 ll mod; ll mul(ll a,ll b)//龜速乘 {ll res=0;a%=mod;while(b){if(b&1) res=(res+a)%mod;a=(a+a)%mod;b>>=1;}return res; } struct node {ll m[N][N];node(){memset(m,0,sizeof m);};node operator *(const node &b) const{node res;for(int i=1;i<=sz;i++)for(int j=1;j<=sz;j++)for(int k=1;k<=sz;k++) res.m[i][j]=(res.m[i][j]+mul(m[i][k],b.m[k][j]))%mod;return res;} }; node qmi(node a,ll b) {node res;for(int i=1;i<=sz;i++)// 單位矩陣res.m[i][i]=1;while(b){if(b&1) res=res*a;a=a*a;b>>=1;}return res; } int main() {IO;int T=1;//cin>>T;sz=2;ll a,c,x0,n,g;while(T--){cin>>mod>>a>>c>>x0>>n>>g;node now;now.m[1][2]=now.m[2][2]=1,now.m[1][1]=a;node res=qmi(now,n);ll ans=(mul(res.m[1][1],x0)+mul(res.m[1][2],c))%mod%g;cout<<ans<<'\n';}return 0; }

SP1716 GSS3 - Can you answer these queries III

矩陣乘法優(yōu)化dp
考慮P1115 最大子段和如何做?
不難得知設(shè)計dp即可。
狀態(tài)表示:fif_ifi?表示以第iii個位置為結(jié)尾最大字段和,gi=max(f1,f2,…,fi)g_i=max(f_1,f_2,\dots,f_i)gi?=max(f1?,f2?,,fi?)
狀態(tài)轉(zhuǎn)移:fi=max(fi?1+ai,ai)f_i=max(f_{i-1}+a_i,a_i)fi?=max(fi?1?+ai?,ai?)gi=max(gi?1,fi)g_i=max(g_{i-1},f_i)gi?=max(gi?1?,fi?)
最終答案即是gng_ngn?

總所周知遞推不滿足結(jié)合律,換句話說就是你必須一步一步遞推,不過矩陣乘法能夠優(yōu)化遞推 斐波那契前 n 項(xiàng)和 ,而優(yōu)化的方式就是使計算過程具有結(jié)合律,那么如果我們通過矩陣操作使一些不具有結(jié)合律的東西具有結(jié)合律那么我們就能用線段樹維護(hù)這個東西,花費(fèi)log代價顯然使非常優(yōu)秀的。

效仿矩陣乘法優(yōu)化斐波那契的方法尋找矩陣
[ai?∞aiai0ai?∞?∞0]?[fn?1gn?10]=[fngn0]\begin{bmatrix} a_i&-\infty&a_i\\a_i&0&a_i\\ -\infty&-\infty&0\\ \end{bmatrix}? \begin{bmatrix} f_{n-1}\\g_{n-1}\\0 \end{bmatrix}= \begin{bmatrix} f_n\\g_n\\0 \end{bmatrix} ???ai?ai????0??ai?ai?0????????fn?1?gn?1?0????=???fn?gn?0????
???表示一個運(yùn)算
[abcd]?[ef]=[max(a+e,b+f)max(c+e,d+f)]\begin{bmatrix} a&b\\c&d \end{bmatrix}? \begin{bmatrix} e\\f \end{bmatrix}=\begin{bmatrix}max(a+e,b+f)\\max(c+e,d+f) \end{bmatrix}[ac?bd?]?[ef?]=[max(a+e,b+f)max(c+e,d+f)?]
不難發(fā)現(xiàn)上述定義的新運(yùn)算是具有結(jié)合律的!!!
對比此運(yùn)算和矩陣乘法與運(yùn)算不難發(fā)現(xiàn):
矩陣乘法中的“乘”相當(dāng)于這里的“加”而矩陣乘法中的“加”相當(dāng)于這里的“max”
矩陣乘法滿足結(jié)合律實(shí)際上使“乘”對“加”滿足分配了,而這里“加”對“max”同樣滿足分配率于是新運(yùn)算具有結(jié)合律。

滿足結(jié)合律并且區(qū)間查詢單點(diǎn)修改無疑線段樹,只需要每個節(jié)點(diǎn)維護(hù)一個矩陣即可。

考慮答案在哪?
定義:
Ai=[ai?∞aiai0ai?∞?∞0]A_i= \begin{bmatrix} a_i&-\infty&a_i\\a_i&0&a_i\\ -\infty&-\infty&0\\ \end{bmatrix}Ai?=???ai?ai????0??ai?ai?0????
Bi=A1?A2?…?AiB_i= A_1?A_2?\dots\ ?A_i Bi?=A1??A2????Ai?
那么再看此題 P1115 最大子段和,不難得出
Bn?[000]=[fngn0]B_n ?\begin{bmatrix} 0\\0\\0 \end{bmatrix}=\begin{bmatrix} f_n\\g_n\\0 \end{bmatrix}Bn?????000????=???fn?gn?0????
答案就是gng_ngn?,不難發(fā)現(xiàn)答案就蘊(yùn)藏著BnB_nBn?矩陣中,分析一下不難得知如果Bn=[b11b12b12b21b22b23b31b32b33]B_n=\begin{bmatrix} b_{11}&b_{12}&b_{12}\\b_{21}&b_{22}&b_{23}\\ b_{31}&b_{32}&b_{33}\\ \end{bmatrix}Bn?=???b11?b21?b31??b12?b22?b32??b12?b23?b33?????那么答案就是max(b21,b23)max(b_{21},b_{23})max(b21?,b23?)

而本題有了之前的工作只需要套個線段樹就是基本的區(qū)間修改單點(diǎn)查詢問題。

#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=3,INF=0x3f3f3f3f; const int N=50010;//投機(jī)取巧 int n,q,a; int sz;//矩陣大小 struct node {int l,r;int m[maxn][maxn];node(){l=r=0;memset(m,0,sizeof m);};node operator *(const node &b) const{node res;res.l=l,res.r=b.r;memset(res.m,-0x3f,sizeof res.m);for(int i=0;i<sz;i++)for(int j=0;j<sz;j++)for(int k=0;k<sz;k++) res.m[i][j]=max(res.m[i][j],m[i][k]+b.m[k][j]);return res;}int ans(){return max(m[1][0],m[1][2]);} }tree[N<<2]; void pushup(int u) {tree[u]=tree[u<<1]*tree[u<<1|1]; } void build(int u,int l,int r) {if(l==r){cin>>a;//這樣輸入省空間tree[u].l=tree[u].r=r;tree[u].m[0][0]=tree[u].m[1][0]=tree[u].m[0][2]=tree[u].m[1][2]=a;tree[u].m[0][1]=tree[u].m[2][0]=tree[u].m[2][1]=-INF;return;}int mid=l+r>>1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);pushup(u); } void modify(int u,int pos,int x) {if(tree[u].l==tree[u].r){tree[u].m[0][0]=tree[u].m[1][0]=tree[u].m[0][2]=tree[u].m[1][2]=x;return;}int mid=tree[u].l+tree[u].r>>1;if(pos<=mid) modify(u<<1,pos,x);else modify(u<<1|1,pos,x);pushup(u); } node query(int u,int l,int r) {if(tree[u].l>=l&&tree[u].r<=r) return tree[u];int mid=tree[u].l+tree[u].r>>1;if(r<=mid) return query(u<<1,l,r);else if(l>mid)return query(u<<1|1,l,r);else return query(u<<1,l,r)*query(u<<1|1,l,r); } int main() {IO;cin>>n;sz=3;build(1,1,n);cin>>q;while(q--){int op,x,y;cin>>op>>x>>y;if(op==1){if(x>y) swap(x,y);cout<<query(1,x,y).ans()<<'\n';}elsemodify(1,x,y);}return 0; } 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的矩阵乘法学习记录的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。