C - 线代

C - 线代
Time Limit:10000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu

Description

学过线性代数后,Ocean又有了新的难题。 
现在Ocean有两个矩阵$A$和$B$,大小分别为$n * x$和$x * m$。现在Ocean想知道新矩阵$C = (A * B)^t$。 
但是输出矩阵太麻烦了,你只需要告诉他$C$矩阵元素之和对$666$取余的结果即可。 
所有测试数据保证$n$ 等于 $m$。请认真读题 

$C = A * B$程序实现: 
假设$A$矩阵是$n * x$的,$B$矩阵是$x * m$的,则得到的$C$矩阵是$n * m$的。 
程序实现$C = A * B$如下: 
int n, x, m;
int A[1001][10], B[10][1001], C[1001][1001];
int i, j, k;
for(i = 0; i < n; i++) {
    for(j = 0; j < m; j++) {
        C[i][j] = 0;
    }
}
for(i = 0; i < n; i++) {
    for(k = 0; k < x; k++) {
        if(A[i][k] == 0) continue;
        for(j = 0; j < m; j++) {
            C[i][j] = (C[i][j] + A[i][k] * B[k][j]) % 666;
        }
    }
}


Input

第一行输入一个整数$T$,代表有$T$组测试数据。 
每组数据占多行,第一行依次输入四个整数$n,x,m,t$分别代表上面提到的信息。 
接下来有$n$行,每行输入$x$个元素代表$A$矩阵。 
后面再有$x$行,每行输入$m$个元素代表$B$矩阵。 

注:$1 <= T <= 100,1 <= n,m,t <= 1000,1 <= x <= 6,1 <= $矩阵元素 $<= 66。$ 

Output

输出一个整数,代表$C$矩阵元素之和对$666$取余后的结果。

Sample Input

2
10 3 10 1000
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
2 2 2 2 2 2 2 2 2 2 
2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2
10 4 10 1000
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
1 2 3 4
7 7 7 7 7 7 7 7 7 7 
7 7 7 7 7 7 7 7 7 7 
7 7 7 7 7 7 7 7 7 7 
7 7 7 7 7 7 7 7 7 7 

Sample Output

396
340

Hint

题意:》》》》

思路:。。。雨神的骚题。。。(A*B)^t=A*B*A*B*A*......*B,根据结合律我们舍弃开头的A和结尾的B,那么(A*B)^t=A*B*(B*A)^t-1,之所以这样分解是因为A*B的范围有点大,,在结构体里开不了,而且容易超时,而(B*A)的只有10,10那么大,运算量小,并且易于写代码。。。。

下面附上代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define NUM 1005
#define mod 666
int n,x,m,t,T;
int A[NUM][10],B[10][NUM],N[NUM][10],D[NUM][NUM];
struct Matrix{
	int a[10][10];
	void init()
	{
		memset(a,0,sizeof(a));
		for(int i=0;i<x;i++)
			a[i][i]=1;
	}
}C;
Matrix MUL(Matrix a,Matrix b)
{
	Matrix ans;	 
	for(int i=0;i<x;i++)
		for(int j=0;j<x;j++)
		{
			ans.a[i][j]=0;
			for(int k=0;k<x;k++)
				ans.a[i][j]+=a.a[i][k]*b.a[k][j];
			ans.a[i][j]%=mod;
		}
	return ans;
}
Matrix pow(Matrix c,int t)
{
	Matrix ans;
	ans.init();
	while(t)
	{	
		if(t&1)
			ans=MUL(ans,c);
		t/=2;
		c=MUL(c,c);
	}
	return ans;
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d %d %d",&n,&x,&m,&t);
		for(int i=0;i<n;i++)
			for(int j=0;j<x;j++)
				scanf("%d",&A[i][j]);
		for(int i=0;i<x;i++)
			for(int j=0;j<m;j++)
				scanf("%d",&B[i][j]);
		for(int i=0;i<x;i++)
			for(int j=0;j<x;j++)
			{
				C.a[i][j]=0;
				for(int k=0;k<m;k++)
					C.a[i][j]=(C.a[i][j]+B[i][k]*A[k][j])%mod;
			}
		Matrix ans;
		t--;
		ans=pow(C,t);
		for(int i=0;i<n;i++)
			for(int j=0;j<x;j++)
			{
				N[i][j]=0;
				for(int k=0;k<x;k++)
					N[i][j]=(N[i][j]+A[i][k]*ans.a[k][j])%mod;
			}
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
			{
				D[i][j]=0;
				for(int k=0;k<x;k++)
					D[i][j]=(D[i][j]+N[i][k]*B[k][j])%mod;
			}
		int sum=0;
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
			{
				sum+=D[i][j];
				sum%=mod;
			}
		printf("%d\n",sum);
	}
	return 0;
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值