矩阵高速幂

Training little cats
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 9785   Accepted: 2340

Description

Facer's pet cat just gave birth to a brood of little cats. Having considered the health of those lovely cats, Facer decides to make the cats to do some exercises. Facer has well designed a set of moves for his cats. He is now asking you to supervise the cats to do his exercises. Facer's great exercise for cats contains three different moves:
g i : Let the ith cat take a peanut.
e i : Let the ith cat eat all peanuts it have.
s i j : Let the ith cat and jth cat exchange their peanuts.
All the cats perform a sequence of these moves and must repeat it m times! Poor cats! Only Facer can come up with such embarrassing idea. 
You have to determine the final number of peanuts each cat have, and directly give them the exact quantity in order to save them.

Input

The input file consists of multiple test cases, ending with three zeroes "0 0 0". For each test case, three integers nm and k are given firstly, where n is the number of cats and k is the length of the move sequence. The following k lines describe the sequence.
(m≤1,000,000,000, n≤100, k≤100)

Output

For each test case, output n numbers in a single line, representing the numbers of peanuts the cats have.

Sample Input

3 1 6
g 1
g 2
g 2
s 1 2
g 3
e 2
0 0 0

Sample Output

2 0 1

Source

PKU Campus 2009 (POJ Monthly Contest – 2009.05.17), Facer

矩阵高速幂模板。用到矩阵的一些性质

 1) ABC = A(BC),所以对矩阵处理时。仅仅须要对之后的m个矩阵处理就可以。最后乘的一个向量矩阵事实上就是获取最后一行的n-1个元素,所以能够忽略,最后用一个循环来处理最后一行就可以;

2)在对矩阵进进行变幻时,由于我们如果一个向量矩阵(x。y,  z),为我们所须要的结果,在处理交换和消0时,对单位矩阵的处理时很easy的,可是在对加法处理时,会出如今对角线p[n][n]的时候多加一,累加的时候会出错,所以我们须要将矩阵的大小扩展1,这样对矩阵处理时,就不影响x,y,z的变值。

3)快速幂的剪枝:一般我们用二分法进行剪枝时处理出现像矩阵这样的特殊的数据结构时。能够在两个矩阵相乘时。看看是不是稀疏矩阵,假设是稀疏或者可能是稀疏矩阵的话,能够改变矩阵相乘的顺序,我举个样例。也许非常easy就明确:

1 2 3      1 2 3         1*1  1*2  1*3

4 5 6 *   4 5 6    =  4*1  4*2  4*3

67 8        6 7 8        6*1 6*2   6*3 ,相乘时。不是一次相加,而是分别相加,红色的想象成队列,然后里面有一串相加的数。每一行的每一个数都进行相应的操作 分别加到每一列,这样仅仅要前一个矩阵的数是0,那么这个数相应的列在当前情况下的一个加数为0,不考虑。

事实上上面是对模板的解释,由于这就是个非常普通的模板题。

代码:

#include<stdio.h>
#include<string.h>
int n;
struct cat{
	__int64 v[110][110];
	cat(){
		memset(v,0,sizeof(v));
	}
};
cat Mul_M_M(cat p,cat q){
	cat t;
	for(int i=0;i<=n;i++)
	for(int j=0;j<=n;j++)
	if(p.v[i][j])
	for(int k=0;k<=n;k++)
	t.v[i][k]+=p.v[i][j]*q.v[j][k];
	return t;
}
void Mul_MM(cat p,int x){
	cat t;
	for(int i=0;i<=n;i++)
	t.v[i][i] = 1;
	while(x){
		if(x&1){
			t = Mul_M_M(t,p);
		}
		p = Mul_M_M(p,p);
		x>>=1;
	}
	for(int i=0;i<n-1;i++)
	printf("%I64d ",t.v[n][i]);
	printf("%I64d
",t.v[n][n-1]);
}
int main(){
	int m,k;
	char a[2];
	int d,c;
	while(scanf("%d%d%d",&n,&m,&k),n||m||k){
		cat p;
		for(int i=0;i<=n;i++)p.v[i][i] = 1;
		for(int i=0;i<k;i++){
			scanf("%s",a);
			switch(a[0]){
				case 'g':
				scanf("%d",&d);
				p.v[n][d-1]++;
				break;//加一。
				case 'e':
				scanf("%d",&d);
				for(int j=0;j<=n;j++)p.v[j][d-1] = 0;
				//qing0
				break;
				case 's':
				scanf("%d%d",&c,&d);
				for(int j=0;j<=n;j++){
					int t  = p.v[j][c-1];
					p.v[j][c-1] = p.v[j][d-1];
					p.v[j][d-1] = t;
				}	//jiaohuan 	
				break; 
			}
		}
		Mul_MM(p,m);
	}
}


原文地址:https://www.cnblogs.com/zfyouxi/p/5160792.html