P3216 [HNOI2011]數學作業 (矩陣快速冪)
阿新 • • 發佈:2018-07-12
接下來 hnoi2011 輸入 matrix spl play clu 快速冪 define
從而可以得到
\[\begin{pmatrix} f[n+1],n+1,1 \end{pmatrix}= =\begin{pmatrix} f[1],1,1 \end{pmatrix} \times \begin{bmatrix} 10^{k},0,0\\1,1,0\\1,1,1\end{bmatrix}^{n-1}\]
ps:k是位數
P2774 方格取數問題
題目背景
none!
題目描述
在一個有 m*n 個方格的棋盤中,每個方格中有一個正整數。現要從方格中取數,使任意 2 個數所在方格沒有公共邊,且取出的數的總和最大。試設計一個滿足要求的取數算法。對於給定的方格棋盤,按照取數要求編程找出總和最大的數。
輸入輸出格式
輸入格式:
第 1 行有 2 個正整數 m 和 n,分別表示棋盤的行數和列數。接下來的 m 行,每行有 n 個正整數,表示棋盤方格中的數。
輸出格式:
程序運行結束時,將取數的最大總和輸出
輸入輸出樣例
輸入樣例#1:
3 3
1 2 3
3 2 3
2 3 1
輸出樣例#1:
11
說明m,n<=100
遞推式容易得到:\[ f[i+1]=f[i]*10^{k}+i+1 \]
範圍 $ n<=10^{18} $
線性算法肯定TLE,那就考慮log的算法(快速冪或者倍增)
考慮把遞推式轉換成矩陣
遞推式有三項
經驗告訴我們,也許要用到\(3*3\)的矩陣
經過一系列 碰數,湊數,計算
我們得到矩陣
\[\begin{pmatrix} f[n+1],n+1,1 \end{pmatrix}=
\begin{pmatrix} f[n],n,1 \end{pmatrix} \times \begin{bmatrix} 10^{k},0,0\\1,1,0\\1,1,1 \end{bmatrix} \]
從而可以得到
\[\begin{pmatrix} f[n+1],n+1,1 \end{pmatrix}= =\begin{pmatrix} f[1],1,1 \end{pmatrix} \times \begin{bmatrix} 10^{k},0,0\\1,1,0\\1,1,1\end{bmatrix}^{n-1}\]
ps:k是位數
k雖然是不確定的,但k的範圍卻很小 <=18
所以分開做就可以了
#include <iostream> #include <cstdio> #include <cstring> #define ll long long using namespace std; ll n,mod; struct node { ll m[4][4]; } ans,ss,a; node mul(node x,node y) { node c= {}; for(int i=1; i<=3; ++i) for(int j=1; j<=3; ++j) for(int k=1; k<=3; ++k) c.m[i][j]=(c.m[i][j]+(x.m[i][k]*y.m[k][j])%mod)%mod; return c; } void fpow(ll p) { while(p) { if(p&1) ans=mul(ans,ss); ss=mul(ss,ss); p>>=1; } } int main() { //全部開long long不要質疑 cin>>n>>mod; ans.m[1][3]=a.m[1][1]=a.m[2][1]=a.m[2][2]=a.m[3][1]=a.m[3][2]=a.m[3][3]=1; for(ll i=1,j; i<=n; i=j+1) { j=i*10-1; if(j>n) j=n; a.m[1][1]=a.m[1][1]*(ll)10%mod; ss=a; fpow(j-i+1); } printf("%lld\n",ans.m[1][1]%mod); return 0; }
自己還是太弱,最後處理菜的要死
P3216 [HNOI2011]數學作業 (矩陣快速冪)