發表文章

目前顯示的是有「矩陣乘法」標籤的文章

[TIOJ] 1331. 索拉數列

題目連結: http://tioj.infor.org/problems/1331 看一眼大概就可以發現這就是一個經典的矩陣優化DP的題目,稍微算一下後得到轉移矩陣$ \begin{bmatrix} 0 & x \\ 1 & y \\ \end{bmatrix} $,所以要求$a_n$其實就是算$ \begin{bmatrix} a_0 & a_1 \\ \end{bmatrix} \times \begin{bmatrix} 0 & x \\ 1 & y \\ \end{bmatrix}^n = \begin{bmatrix} a_n & a_{n+1} \\ \end{bmatrix}$ ,然後冪次的部分用快速冪解決。 #include <bits/stdc++.h> using namespace std; typedef long long lld; typedef unsigned long long llu; const llu mod = 1LL<<32; auto A = new llu[2][2]; auto B = new llu[2][2]; auto C = new llu[2][2]; auto F = new llu[2][2]; void mTimes(llu[2][2],llu[2][2],llu[2][2],int,int,int); int main(){ ios_base::sync_with_stdio(0);cin.tie(0); lld n, a, b, x, y; while(cin>>n, n>=0){ cin>>a>>b>>x>>y; F[0][0]=a; F[0][1]=b; A[0][0]=0; A[0][1]=x; A[1][0]=1; A[1][1]=y; B[0][0]=...

[TIOJ] 1136. 3.熱鍋上的螞蟻

題目連結: http://tioj.infor.org/problems/1136 因為我們知道若把圖用鄰接矩陣存下來,他的t次方就是走t步後有幾種走法,所以就可以看下面的做法做了。 本題要求的其實就是從所有a($0 \leq a \leq n$)開始走到x的機率和最後再除以n,但是顯然直接乘再算機率會overflow(除非你寫大數),所以有個比較方便的技巧就是一開始就算機率,之後做矩陣乘法的時候就不會因此而overflow了,大概這樣就可以AC了吧 #include <bits/stdc++.h> using namespace std; typedef double lf; typedef long long lld; #define N 100 auto m1 = new lf[N+10][N+10]; auto m2 = new lf[N+10][N+10]; auto m3 = new lf[N+10][N+10]; lld mm[N+10][N+10]; inline void mTimes(lf[][N+10],lf[][N+10],lf[][N+10]); int n,t; int main(){ scanf("%d%d",&n,&t); while(n+t!=0){ for(int i=0;i<n;i++)for(int j=0;j<n;j++)m1[i][j]=m2[i][j]=m3[i][j]=mm[i][j]=0; int x; scanf("%d",&x); while(x--){ int s,t; scanf("%d%d",&s,&t); s--,t--; mm[s][t]=1; mm[t][s]=1;...

[TIOJ] 1936. 雖然我是工具,但是我樂在其中

題目連結: http://tioj.infor.org/problems/1936 這題其實我覺得滿難的,一開始我一直以為他是簡單的矩陣乘法題,結果發現時間好像會超時,然後看了2015校隊培訓講義,發現原來是某種隨機演算法,想說那就直接隨機戳驗驗看吧,結過送了後一直TLE才估了一下複雜度發現也還是慘慘的,然後就莫名被雷到了,發現原來是隨機生成一個$n \times 1$的矩陣然後跟其他人乘,然後因為矩陣乘法有交換律(若$A \times B = C$,則$A \times B \times L = C \times L \rightarrow A \times (B \times L) = C \times L $),所以若發現$ABL \neq CL$,那AB不等於C,但若$ABL=CL$也不代表$AB=C$所以多生個幾個L算一下吧 #include <stdio.h> #include <stdlib.h> #include <time.h> typedef long long lld; lld mA[1024 + 10][1024 + 10], mB[1024 + 10][1024 + 10], mC[1024 + 10][1024 + 10], l[1024 + 10]; int n; inline void times(lld[][1024+10],lld[],lld[]); inline bool same(lld[],lld[]); int main(){ srand(time(NULL)); int T; gn(T); while(T--){ gn(n); for(int i=0;i<n;i++) for(int j=0;j<n;j++) scanf("%lld",&mA[i][j]); for(int i=0;i<n;i++) for(int...

[TIOJ] 1354. 池塘裡的青蛙

題目連結: http://tioj.infor.org/problems/1354 因為不確定題目的範圍所以先開個long long壓壓驚(?,這題也是一樣,矩陣乘法快速冪,因為把圖用鄰接矩陣存下來後,其的n次方就是任意點走到任一點走n步的可能方法總數。只是因為也不確定題目給的n是否遞增,所以就把他排個序,然後再做矩陣快速冪,理論上應該會比較快(?,複雜度$O(t log_2 t + log_2 n)$ #include <stdio.h> #include <algorithm> typedef long long lld; inline void gn(lld &_){_=0;char c=getchar();while(c<'0'||c>'9')c=getchar();while(c>='0'&&c<='9')_=_*10+c-'0',c=getchar();} using std::sort; using std::swap; struct inp{ lld i, val; }; inline void matrixTimes(lld [][4],lld [][4],lld [][4]); bool cmp(inp a,inp b){ return a.val<b.val; } int main(){ lld n; gn(n); auto v = new inp[n]; auto ans = new lld[n]; for(lld i=0;i<n;i++){ v[i].i=i; gn(v[i].val); } sort(v,v+n,cmp); inp k = v[0]; auto matrix = new lld[4][4]; auto ta = new lld[4][4]; ...

[TIOJ] 1146 . 1.城市道路連通網

題目連結: http://tioj.infor.org/problems/1146 這題其實跟 [TIOJ]1428 很像,只是他不能快速冪,而是要$O(n)$做矩陣乘法,然後每次做完後就把答案加起來 #include <stdio.h> #include <algorithm> int size; auto graph = new int[35][35]; auto temp = new int[35][35]; inline void matrixTimes(int [][35], int[][35], int[][35]); int main(){ scanf("%d",&size); for(int i=0;i<size;i++){ char inp[35]; scanf("%s",inp); for(int j=0;j<size;j++){ temp[i][j]=i==j; graph[i][j]=inp[j]-'0'; } } int x,y,n,ans=0; scanf("%d\n%d\n%d",&x,&y,&n); while(n){ auto tp = new int[35][35]; matrixTimes(graph,temp,tp); std::swap(tp,temp); ans+=temp[x-1][y-1]; n--; } printf("%d",ans); return 0; } inline void matrixTimes(int a[][35], int b[][35], int...

[TIOJ] 1428. 影分身之術

題目連結: http://tioj.infor.org/problems/1428 其實鄰接矩陣除了MLE外其實還有個功能,那就是你可以直接把他n次方,得到的就是任意兩點走n步有幾種走法的答案,然後n次方都可以用快速冪,所以這題其實就把圖用鄰接矩陣存起來,然後快速冪,複雜度$O(N^3 \log_2{L})$ #include <stdio.h> #include <algorithm> typedef long long lld; int n,m,q,l; auto graph = new lld[160][160]; auto temp0 = new lld[160][160]; auto temp1 = new lld[160][160]; inline void matrixTime(lld [][160],lld [][160],lld [][160]); int main(){ scanf("%d %d %d %d",&n,&m,&q,&l); for(int j=0;j<n;j++){ for(int k=0;k<n;k++){ graph[j][k]=(j==k)?1:0; } } for(int i=0;i<m;i++){ int s,e; scanf("%d %d",&s,&e); temp0[s][e]++; } bool which=0; while(l){ if(l&1){ auto tp = new lld[160][160]; matrixTime(graph,which?temp1:temp0,tp); std::swap(t...

[IOJ] 14. 費氏數列問題

題目連結: https://ioj.infor.org/problems/14 由題目可看出這是一個標準的線性遞迴,而居然是線性遞迴的話,那都可以用矩陣乘法搭配快速冪來讓時間複雜度降到$O(m^3 \log_2{(n-m)})$,然後不難發現其要用的$1 \times m$橫矩陣是$\left( \begin{array}{clr} 1 & 1 & \cdots & 1 \end{array} \right)$,而$m \times m$正方形矩陣則是$\left( \begin{array}{clr} k_{1} & 1 & 0 & 0 & \cdots \\ k_{2} & 0 & 1 & 0 & \cdots \\ k_{3} & 0 & 0 & 1 & \cdots \\ \vdots & \vdots & \vdots & \vdots & \ddots \\ k_{m} & 0 & 0 & 0 & \cdots \end{array} \right)$至於會溢位的部分則按照題敘,每次在做加法乘法之類的時候都模一次$10^9+7$,因為可以證明先算再模跟先模再算再模都會得到相同的結果的。 #include <stdio.h> #include <algorithm> typedef long long lld; const lld mmdd = 1000000007; lld m1[110][110]={0}; auto aas = new lld [110][110]; lld n,m; void qPow(lld); void matrixTimes(lld[][110],lld[][110],lld[][110]); int main(){ scanf("%lld %lld",&n,&m); for(lld i=0;i<m;i++){ scanf("%lld",&m1[i][0]); if(i+1<m) m1[i][i+1] = 1;...