矩阵快速幂

还没有
准备正式学习一下

学习日记

其实感觉矩阵快速幂本身是可以理解的,但是有一个问题就是你在学会了矩阵快速幂之后,如何将其和实践结合起来是个大问题,感觉还是要靠刷题吧。

题目

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值,这样的话,每次对于询问的时候,其实就是求一段区间矩阵乘法的结果,仍然线段树。

posted @ 2025-06-30 11:38  wjx_2010  阅读(15)  评论(0)    收藏  举报