矩阵快速幂
还没有
准备正式学习一下
学习日记
其实感觉矩阵快速幂本身是可以理解的,但是有一个问题就是你在学会了矩阵快速幂之后,如何将其和实践结合起来是个大问题,感觉还是要靠刷题吧。
题目
P10503 Matrix
其实具体矩阵快速幂的实现方面就是板子,没什么难点,主要的问题在于怎么推的转移矩阵。
这里给出我的一个小方法吧,熟练之后其实也挺快的。
显然矩阵快速幂是同一件事执行了 \(n\) 此,所以显然满足 \(F_{x}=F_{x-1}\times T\) (T是转移矩阵),并且,我们一定可以推出来该事件不执行和执行一次的矩阵,然后我们根据矩阵乘法的原理,直接写出转移式,对着转移式硬推就好了。
P5337 [TJOI2019] 甲苯先生的字符串
题目传送门
这很板子了,我们考虑,令字母 \(i\) 后面跟字母 \(j\)定义为字母 \(i\) 和字母 \(j\) 之间连一条权值为 \(1\) 的边, \(F_{t,i,j}\) 表示 \(i\) 和 \(j\) 之间通过 \(t\) 次可以到达的方案数个数,那么显然就转变成了简单版的(P4159 [SCOI2009] 迷路)[https://www.luogu.com.cn/problem/P4159] ,直接秒了。
考虑这是第一道纯自己写的代码,所以就给一下吧。
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n=30,N;
const int M=1e5+100;
char s[M];
const int mod=1e9+7;
struct node {
int a[110][110];
friend node operator *(node a,node b) {
node ans;
memset(ans.a,0,sizeof(ans.a));
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
for(int k=1;k<=n;k++) {
ans.a[i][j]+=a.a[i][k]*b.a[k][j];
ans.a[i][j]%=mod;
}
}
}
return ans;
}
}a,b;
int read(){int x;cin>>x;return x;}
node ksm(node a,int b) {
node t;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
t.a[i][j]=0;
if(i==j) t.a[i][j]=1;
}
}
while(b) {
if(b&1) t=t*a;
a=a*a;
b>>=1;
}
return t;
}
signed main() {
N=read();
scanf("%s",s+1);
int m=strlen(s+1);
for(int i=1;i<=26;i++) {
for(int j=1;j<=26;j++) {
a.a[i][j]=1;
}
}
for(int i=1;i<m;i++) {
a.a[s[i]-'a'+1][s[i+1]-'a'+1]=0;
}
b=ksm(a,N-1);
int ans=0;
for(int i=1;i<=26;i++) {
for(int j=1;j<=26;j++) {
ans=ans+b.a[i][j];
ans%=mod;
// cerr<<b.a[i][j]<<endl;
}
}
cout<<ans<<endl;
// cout<<b.a[1][26]<<endl;
return 0;
}
一些拓展
其实这里啥也没有,就是提供一个链接
线段树历史和
在线段树上维护当前节点曾经的所有值的和。
对于每个节点,我们考虑维护一个矩阵来转移,然后就做完了。
线段树+矩阵快速幂+dp
多次询问,每次询问都求对于一个序列中,某一段区间的dp值,这样的话,每次对于询问的时候,其实就是求一段区间矩阵乘法的结果,仍然线段树。

浙公网安备 33010602011771号