$\text{GYM}$ 链接:[[https://codeforces.com/gym/102644|Matrix Exponentiation]] ==== F - Min Path ==== 给一个无向图,求包含 $k$ 条边的最小路径。 考虑 $\text{dp}$,定义 $f[i][j][k]$ 为从第 $i$ 个点出发经过 $k$ 条边到第 $j$ 个点的最短路。则会有如下的转移方程 $$f[i][j][k] = min_u\{f[i][u][k-1] + g[u][j]\}$$ 但 $k$ 值很大,所以不能直接$\text{dp}$。因为取最小值的操作和乘法都满足结合律交换律,且上述形式和矩阵乘法类似,所以可以把矩阵乘法改写成上面的转移方程,再用矩阵快速幂加速。 #include #define ALL(x) (x).begin(),(x).end() #define ll long long #define db double #define ull unsigned long long #define pii_ pair #define mp_ make_pair #define pb push_back #define fi first #define se second #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define show1(a) cout<<#a<<" = "< \\ ==== G - Recurrence With Square ==== 求序列 $$a_i = c_1\cdot a_{i-1} + c_2\cdot a_{i-2} + \cdots + c_n\cdot a_{i-n} + p + i\cdot q + i^2 \cdot r$$ 的第 $k$ 项,也就是归纳一般的线性递推式的矩阵构造方法。 /* #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") */ #include #define ALL(x) (x).begin(),(x).end() #define ll long long #define db double #define ull unsigned long long #define pii_ pair #define mp_ make_pair #define pb push_back #define fi first #define se second #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define show1(a) cout<<#a<<" = "< #define ALL(x) (x).begin(),(x).end() #define ll long long #define db double #define ull unsigned long long #define pii_ pair #define mp_ make_pair #define pb push_back #define fi first #define se second #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define show1(a) cout<<#a<<" = "< #define ALL(x) (x).begin(),(x).end() #define ll long long #define db double #define ull unsigned long long #define pii_ pair #define mp_ make_pair #define pb push_back #define fi first #define se second #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define show1(a) cout<<#a<<" = "<