矩阵乘法略解

矩阵乘法

对于一个 n × m n\times m n×m 的矩阵 A A A 和一个 m × k m\times k m×k 的矩阵 B B B,有且仅有一个 n × k n\times k n×k 的矩阵 C C C 使 A × B = C A\times B=C A×B=C且对于 ∀ i ∈ [ 1 , n ]   &   ∀ j ∈ [ 1 , k ] \forall i\in [1,n]\ \&\ \forall j\in [1,k] i[1,n] & j[1,k],有 C i , j = ∑ k = 1 m A i k × B k j C_{i,j}=\sum^{m}_{k=1}{A_{ik}\times B_{kj}} Ci,j=k=1mAik×Bkj这就是矩阵乘法。比如:
[ 1 2 3 3 2 1 ] × [ 1 1 2 2 3 3 ] = [ 14 14 10 10 ] \left[\begin{array}{ccc}1&2&3\\3&2&1\\\end{array}\right]\times\left[\begin{array}{ccc}1&1\\2&2\\3&3\\\end{array}\right]=\left[\begin{array}{ccc}14&14\\10&10\\\end{array}\right] [132231]×123123=[14101410]

题目描述 loj10220 \text{loj10220} loj10220

大家都知道 Fibonacci 数列吧, f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn1+fn2

现在问题很简单,输入 n n n m m m,求 f n m o d    m f_n\mod m fnmodm

输入格式

输入 n , m n,m n,m

输出格式

输出 f n m o d    m f_n\mod m fnmodm

样例输入

5 1000

样例输出

5

数据范围与提示

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 2 × 1 0 9 , 1 ≤ m ≤ 1 0 9 + 10 1\leq n\leq2\times10^9,1\leq m\leq 10^9+10 1n2×109,1m109+10

Solution 10220 \text{Solution 10220} Solution 10220

考虑使用矩阵快速幂优化时间复杂度。
若矩阵 A A A 使 [ f i − 2 f i − 1 ] × A = [ f i − 1 f i ] \left[ \begin{array}{ccc} f_{i-2}&f_{i-1} \end{array} \right] \times A=\left[ \begin{array}{ccc} f_{i-1} & f_i \end{array} \right] [fi2fi1]×A=[fi1fi]
[ f n f n − 1 ] = [ f 1 f 2 ] × A n − 1 \left[ \begin{array}{ccc} f_n & f_{n-1} \end{array} \right]=\left[ \begin{array}{ccc} f_1&f_2 \end{array} \right]\times A^{n-1} [fnfn1]=[f1f2]×An1 A n − 1 A^{n-1} An1可以使用快速幂求出。
下面推导 A A A。 由矩阵乘法知 A A A 是一个 2 × 2 2\times 2 2×2 的矩阵,且
f i − 1 = A 11 × f i − 2 + A 21 × f i − 1 f_{i-1}=A_{11}\times f_{i-2}+A_{21}\times f_{i-1} fi1=A11×fi2+A21×fi1 ∴ A 11 = 0 , A 21 = 1 , \therefore A_{11}=0,A_{21}=1, A11=0,A21=1,
同理得 A 12 = 1 , A 22 = 1 , A_{12}=1,A_{22}=1, A12=1,A22=1,
∴ A = [ 0 1 1 1 ] . \therefore A=\left[ \begin{array}{ccc} 0 & 1\\ 1 & 1 \end{array} \right]. A=[0111].

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register

typedef long long ll;

int n,m;

struct node{
	ll a[3][3];
	int x,y;
	node(){
		x=y=0;
		memset(a,0,sizeof(a));
	}
	void pt(){
		printf("%lld",a[1][2]);
	}
}s,t,ans;
node T(node a,node b){
	node c;c.x=a.x;c.y=b.y;
	for(reg int i=1;i<=c.x;++i)
		for(reg int j=1;j<=c.y;++j)
			for(reg int k=1;k<=a.y;++k)
				c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
	return c;
}
node QT(node a,int b){
	if(b<=1) return a;
	node c=QT(a,b/2);
	if(b%2)
		return T(T(c,c),a);
	else
		return T(c,c);
}

int main(){
	scanf("%d%d",&n,&m);
	s.x=1;s.y=2;s.a[1][1]=s.a[1][2]=1;
	t.x=2;t.y=2;t.a[1][1]=0;t.a[1][2]=t.a[2][1]=t.a[2][2]=1;
	ans=T(s,QT(t,n-2));
	ans.pt();
}

题目描述 loj10221 \text{loj10221} loj10221

大家都知道 Fibonacci 数列吧, f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn1+fn2

s n = ∑ k = 1 n f k m o d &ThinSpace;&ThinSpace; m s_n=\sum^{n}_{k=1}{f_k} \mod m sn=k=1nfkmodm的值。

样例输入

5 1000

样例输出

12

数据范围与提示

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 2 × 1 0 9 , 1 ≤ m ≤ 1 0 9 + 10 1\leq n\leq2\times10^9,1\leq m\leq 10^9+10 1n2×109,1m109+10

Solution 10221 \text{Solution 10221} Solution 10221

对于Fibonacci数列前 n n n 项和 s n s_n sn,显然有 s n = s n − 1 + f n s_n=s_{n-1}+f_n sn=sn1+fn。类似的,我们可以构造一矩阵 B B B,使 [ f i − 2 f i − 1 s i − 1 ] × B = [ f i − 1 f i s i ] \left[ \begin{array}{ccc} f_{i-2}&amp;f_{i-1}&amp;s_{i-1}\\ \end{array} \right] \times B=\left[ \begin{array}{ccc} f_{i-1}&amp;f_i&amp; s_i\\ \end{array} \right] [fi2fi1si1]×B=[fi1fisi],就能完成此题。

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register

typedef long long ll;

int n,m;

struct node{
	ll a[4][4];
	int x,y;
	node(){
		x=y=0;
		memset(a,0,sizeof(a));
	}
	void pt(){
		printf("%lld",a[1][3]);
	}
}s,t,ans;
node T(node a,node b){
	node c;c.x=a.x;c.y=b.y;
	for(reg int i=1;i<=c.x;++i)
		for(reg int j=1;j<=c.y;++j)
			for(reg int k=1;k<=a.y;++k)
				c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
	return c;
}
node QT(node a,int b){
	if(b<=1) return a;
	node c=QT(a,b/2);
	if(b%2)
		return T(T(c,c),a);
	else
		return T(c,c);
}

int main(){
	scanf("%d%d",&n,&m);
	s.x=1;s.y=3;s.a[1][1]=s.a[1][2]=1;s.a[1][3]=2;
	t.x=3;t.y=3;t.a[1][1]=t.a[3][1]=t.a[3][2]=0;t.a[1][2]=t.a[1][3]=t.a[2][1]=t.a[2][2]=t.a[2][3]=t.a[3][3]=1;;
	ans=T(s,QT(t,n-2));
	ans.pt();
}

题目描述 loj10222 \text{loj10222} loj10222

大家都知道 Fibonacci 数列吧, f n = f n − 1 + f n − 2 f_n=f_{n-1}+f_{n-2} fn=fn1+fn2

T n = ∑ k = 1 n k ⋅ f k m o d &ThinSpace;&ThinSpace; m T_n=\sum^{n}_{k=1}{k·f_k} \mod m Tn=k=1nkfkmodm 的值。

样例输入

5 5

样例输出

4

数据范围与提示

对于 100 % 100\% 100% 的数据, 1 ≤ n , m ≤ 2 31 − 1 1\leq n,m\leq 2^{31}-1 1n,m2311

Solution 10222 \text{Solution 10222} Solution 10222

考虑构造一 1 × 4 1\times 4 1×4 矩阵
A i = [ f i − 2 f i − 1 T i − 1 i − 1 ] A_i=\left[ \begin{array}{ccc} f_{i-2}&amp;f_{i-1}&amp;T_{i-1}&amp;i-1 \end{array} \right] Ai=[fi2fi1Ti1i1]
使
A i × B = A i + 1 A_i\times B=A_{i+1} Ai×B=Ai+1
其中 B B B 是一个 4 × 4 4\times 4 4×4 的矩阵。同上文,我们有
f i − 1 = B 11 ⋅ f i − 2 + B 21 ⋅ f i − 1 + B 31 ⋅ T i − 1 + B 41 ⋅ ( i − 1 ) f_{i-1}=B_{11}·f_{i-2}+B_{21}·f_{i-1}+B_{31}·T_{i-1}+B_{41}·(i-1) fi1=B11fi2+B21fi1+B31Ti1+B41(i1) f i = B 12 ⋅ f i − 2 + B 22 ⋅ f i − 1 + B 32 ⋅ T i − 1 + B 42 ⋅ ( i − 1 ) f_i=B_{12}·f_{i-2}+B_{22}·f_{i-1}+B_{32}·T_{i-1}+B_{42}·(i-1) fi=B12fi2+B22fi1+B32Ti1+B42(i1) T i =   ⋅ ⋅ ⋅ T_i=\ ··· Ti= 
那么, T i T_i Ti 怎么用形如上式的表达式表示呢?
事实上,我们无法用形如上式的表达式表示 T i = T i − 1 + i ⋅ f i T_i=T_{i-1}+i·f_i Ti=Ti1+ifi,因为我们无法用方阵 B B B 的若干次幂的形式表示 i i i

考虑如何将 T i T_i Ti 表示成一次递推式。
(1) T n = ∑ k = 1 n k ⋅ f k T_n=\sum^{n}_{k=1}{k·f_k}\tag 1 Tn=k=1nkfk(1) (2) n s n = ∑ k = 1 n n ⋅ f k ns_n=\sum^{n}_{k=1}{n·f_k}\tag 2 nsn=k=1nnfk(2)
( 2 ) − ( 1 ) (2)-(1) (2)(1)
(3) n s n − T n = ∑ k = 1 n ( n − k ) ⋅ f k ns_n-T_n=\sum^{n}_{k=1}(n-k)·f_k\tag3 nsnTn=k=1n(nk)fk(3)
( 3 ) + s n (3)+s_n (3)+sn
n s n − T n + s n = ∑ k = 1 n ( n − k ) ⋅ f k + s n = ∑ k = 1 n ( n − k ) ⋅ f k + ∑ k = 1 n f k = ∑ k = 1 n ( n + 1 − k ) ⋅ f k = ∑ k = 1 n + 1 ( n + 1 − k ) ⋅ f k = ( n + 1 ) s n + 1 − T n + 1 \begin{aligned} ns_n-T_n+s_n&amp;=\sum^{n}_{k=1}{(n-k)·f_k}+s_n\\ &amp;=\sum^{n}_{k=1}{(n-k)·f_k}+\sum^n_{k=1}{f_k}\\ &amp;=\sum^{n}_{k=1}{(n+1-k)·f_k}\\ &amp;=\sum^{n+1}_{k=1}{(n+1-k)·f_k}\\ &amp;=(n+1)s_{n+1}-T_{n+1} \end{aligned} nsnTn+sn=k=1n(nk)fk+sn=k=1n(nk)fk+k=1nfk=k=1n(n+1k)fk=k=1n+1(n+1k)fk=(n+1)sn+1Tn+1
p k = k s k − T k p_k=ks_k-T_k pk=kskTk,于是我们得到 p p p 的递推关系式
p k = p k − 1 + s k − 1 p_k=p_{k-1}+s_{k-1} pk=pk1+sk1所以我们可以构造矩阵
A i ′ = [ p i s i f i f i − 1 ] A_i&#x27;=\left[ \begin{array}{ccc} p_i&amp;s_i&amp;f_i&amp;f_{i-1} \end{array} \right] Ai=[pisififi1] B ′ = [ 1 1 0 0 0 1 1 0 0 0 1 1 0 0 1 0 ] B&#x27;=\left[ \begin{array}{ccc} 1&amp;1&amp;0&amp;0\\ 0&amp;1&amp;1&amp;0\\ 0&amp;0&amp;1&amp;1\\ 0&amp;0&amp;1&amp;0 \end{array} \right] B=1000110001110010
使
A i ′ × B ′ = A i + 1 ′ A&#x27;_i\times B&#x27;=A&#x27;_{i+1} Ai×B=Ai+1

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register

typedef long long ll;

int n,m;

struct node{
	ll a[5][5];
	int x,y;
	node(){
		x=y=0;
		memset(a,0,sizeof(a));
	}
	void pt(){
		printf("%lld",(a[1][2]*n%m-a[1][1]+m)%m);
	}
}s,t,ans;
node T(node a,node b){
	node c;c.x=a.x;c.y=b.y;
	for(reg int i=1;i<=c.x;++i)
		for(reg int j=1;j<=c.y;++j)
			for(reg int k=1;k<=a.y;++k)
				c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
	return c;
}
node QT(node a,int b){
	if(b<=1) return a;
	node c=QT(a,b/2);
	if(b%2)
		return T(T(c,c),a);
	else
		return T(c,c);
}

int main(){
	scanf("%d%d",&n,&m);
	s.x=1;s.y=4;s.a[1][2]=s.a[1][3]=s.a[1][4]=1;
	t.x=4;t.y=4;t.a[1][1]=t.a[2][1]=t.a[2][2]=t.a[3][2]=t.a[3][3]=t.a[4][3]=t.a[3][4]=1;
	ans=T(s,QT(t,n-1));
	ans.pt();
}

题目描述 loj10225 \text{loj10225} loj10225

原题来自:SCOI 2009

Windy 在有向图中迷路了。 该有向图有 n n n 个节点,Windy 从节点 0 0 0 出发,他必须恰好在 T T T 时刻到达节点 。

现在给出该有向图,你能告诉 Windy 总共有多少种不同的路径吗?

注意:Windy 不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。

输入格式

第一行包含两个整数 n n n T T T
接下来有 n n n 行,每行一个长度为 n n n 的字符串。第 i i i 行第 j j j 列为 0 0 0 表示从节点 i i i 到节点 j j j 没有边,为 1 1 1 9 9 9 表示从节点 i i i 到节点 j j j 需要耗费的时间。

输出格式

包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以 2009 2009 2009 的余数。

样例输入 1

2 2
11
00

样例输出 1

1

样例输入 2

5 30
12045
07105
47805
12024
12345

样例输出 2

852

数据范围与提示

对于 100 % 100\% 100% 的数据,满足 2 ≤ n ≤ 10 , 1 ≤ T ≤ 1 0 9 2\leq n\leq 10,1\leq T\leq 10^9 2n10,1T109

Solution 10225 \text{Solution 10225} Solution 10225

n n n 的规模和边权都很小,考虑拆点,则时间复杂度为 O ( n T ) O(n^T) O(nT)
如何把 T T T 优化成 log ⁡ T \log T logT 呢?观察输入格式,我们很自然地想到矩阵,尝试使用矩阵快速幂优化。
设从 i i i j j j 的边权为 u i j u_{ij} uij。考虑当边权为 0 0 0 1 1 1 时,从 i i i j j j 路径长为 T T T 的路径数
s i j T = ∑ k = 1 n ( ∑ u = T ) s_{ijT}=\sum^{n}_{k=1}{(\sum u=T)} sijT=k=1n(u=T)
如果构造矩阵 U = { u i j ∣ i , j ∈ [ 1 , n ] } U=\{u_{ij}|i,j\in [1,n]\} U={uiji,j[1,n]} S = U T S=U^T S=UT
S i j = s i j T   ( ∀ i , j ) S_{ij}=s_{ijT}\ (\forall i,j) Sij=sijT (i,j)

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register

typedef long long ll;

int n,t;
const int m=2009;
char str[20][20];

struct node{
	ll a[110][110];
	int x,y;
	node(){
		x=y=0;
		memset(a,0,sizeof(a));
	}
}s,ans;
node T(node a,node b){
	node c;c.x=a.x;c.y=b.y;
	for(reg int i=1;i<=c.x;++i)
		for(reg int j=1;j<=c.y;++j)
			for(reg int k=1;k<=a.y;++k)
				c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
	return c;
}
node QT(node a,int b){
	node c;c.x=n;c.y=n;
	for(reg int i=1;i<=n;++i)
		c.a[i][i]=1;
	while(b){
		if(b&1) c=T(c,a);
		a=T(a,a);b>>=1;
	}
	return c;
}

int main(){
	scanf("%d%d",&n,&t);
	for(reg int i=1;i<=n;++i){
		scanf("%s",str[i]+1);
		for(reg int j=1;j<=n;++j)
			str[i][j]-='0';
	}
	for(reg int i=1;i<=n;++i){
		for(reg int j=1;j<=8;++j)
			s.a[(i-1)*9+j][(i-1)*9+j+1]=1;
		for(reg int j=1;j<=n;++j)
			if(str[i][j])
				s.a[(i-1)*9+str[i][j]][(j-1)*9+1]=1;
	}
	n*=9;s.x=s.y=n;
	ans=QT(s,t);
	printf("%d",ans.a[1][n-8]);
}

题目描述 情书


∑ k = 1 n f k + ∑ k = 1 n c k ( m o d &ThinSpace;&ThinSpace; m ) \sum_{k=1}^{n}f_k+\sum_{k=1}^{n}{c^k}\quad(\mod m) k=1nfk+k=1nck(modm)
的值,其中 ∀ i &gt; 2 \forall i&gt;2 i>2
f i = a ⋅ f i − 1 + b ⋅ f i − 2 f_i=a·f_{i-1}+b·f_{i-2} fi=afi1+bfi2

输入描述

一行 7 7 7 个整数,分别为 a , b , c , n , m , f 1 , f 2 a,b,c,n,m,f_1,f_2 a,b,c,n,m,f1,f2,相邻两数以一个空格隔开。

输出描述

一行,一个整数,表示答案。

输入样例

    1 1 1 3 5 1 1 \ \ \ \ \text{1 1 1 3 5 1 1}     1 1 1 3 5 1 1

输出样例

     2 \ \ \ \ 2     2

数据规模与约定

对于 100 % 100\% 100% 的数据,有 0 ≤ a , b , c , n , m , f i ≤ 2 31 0\leq a,b,c,n,m,f_i\leq2^{31} 0a,b,c,n,m,fi231,其中 i ∈ [ 1 , n ] i\in[1,n] i[1,n]

Solution 5 \text{Solution 5} Solution 5

Pt.1 求 s k s_k sk 的值

仿照例2知, a , b a,b a,b 是矩阵 B B B 的两个元素,请读者自己尝试推导。

Pt.2 求 ∑ k = 1 n c k \sum_{k=1}^{n}{c^k} k=1nck

简单等比数列求和。

S = ∑ k = 1 n c k ...(4) S=\sum_{k=1}^{n}{c^k}\quad\text{...(4)} S=k=1nck...(4)

c S = ∑ k = 1 n c k + 1 ...(5) cS=\sum_{k=1}^{n}{c^{k+1}}\quad\text{...(5)} cS=k=1nck+1...(5)
( 5 ) − ( 4 ) (5)-(4) (5)(4)
( c − 1 ) S = c k + 1 − c (c-1)S=c^{k+1}-c (c1)S=ck+1c
S = c k + 1 − c c − 1 S=\frac{c^{k+1}-c}{c-1} S=c1ck+1c
使用乘法逆元和快速幂即可完成求解。

#include<cstdio>
#include<cstdlib>
#include<cstring>

#define reg register
typedef long long ll;

struct node{
	int x,y;
	ll a[5][5];
	node(){
		memset(a,0,sizeof(a));
		x=y=0;
	}
}s,t;

ll a,b,c;
ll n,m,x,y,son;
ll sum=0;

node T(node a,node b){
	node c;c.x=a.x;c.y=b.y;
	for(reg int i=1;i<=c.x;++i)
		for(reg int j=1;j<=c.y;++j)
			for(reg int k=1;k<=a.y;++k)
				c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%m;
	return c;
}
node QT(node a,int b){
	if(b<=1) return a;
	node c=QT(a,b/2);
	if(b%2)
		return T(T(c,c),a);
	else
		return T(c,c);
}
void exgcd(ll A,ll B,ll&x,ll&y){
	if(!B){
		x=1;y=0;
		return;
	}
	exgcd(B,A%B,x,y);
	ll t=x;x=y;y=t-A/B*y;
}
ll qt(ll a,int b){
	if(b==1) return a;
	ll e=qt(a,b/2)%m;
	if(b%2)
		return (e*e)%m*a%m;
	else
		return (e*e)%m;
}
int main(){
	scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&n,&m,&s.a[1][1],&s.a[1][2]);c%=m;
	s.a[1][3]=s.a[1][1]+s.a[1][2];s.a[1][4]=s.a[1][1];
	s.x=1;s.y=4;t.x=t.y=4;
	t.a[2][1]=t.a[3][3]=t.a[3][4]=t.a[4][4]=1;
	t.a[1][2]=t.a[1][3]=b;t.a[2][2]=t.a[2][3]=a;
	s=T(s,QT(t,n-2));
	exgcd(c-1,m,x,y);son=(qt(c,n+1)-c+m)%m;x=(x%m+m)%m;
	printf("%lld",(((s.a[1][3]*n)%m-s.a[1][4]+m)%m+(x*son)%m+m)%m);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值