线代 [矩阵]

Description

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

Input

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

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

Output

输出一个整数,代表CC矩阵元素之和对666666取余后的结果

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

题意

题解:

先求B*A 这样快速幂复杂度降很多 因为B*A的矩阵边长只有x
即A*(B*A)^t*B

AC代码

#include <cstdio>
#include <cstring>
const int mod = 666;
struct mat{
    int rix[15][15];
};
int aa[1005][15];
int bb[15][1005];
int lt[1005][15];
int ans[1005][1005];
int n,m,x;

mat mul(mat a,mat b){
    mat c;
    for (int i = 0;i < x; ++i) for (int j = 0;j < x; ++j) c.rix[i][j] = 0;
    for (int i = 0;i < x; ++i){
        for (int j = 0; j < x; ++j){
            for (int k = 0;k < x; ++k){
                c.rix[i][j] += a.rix[i][k]*b.rix[k][j];
                c.rix[i][j] %= mod;
            }
        }
    }
    return c;
}

mat q_mod(mat a,int b){
    mat tmp;
    for (int i = 0;i < x; ++i) for (int j = 0;j < x; ++j) tmp.rix[i][j] = (i==j);
    while (b){
        if (b&1) tmp = mul(tmp,a);
        a = mul(a,a);
        b>>=1;
     }
     return tmp;
 }
int main(){
    int t;
    scanf("%d",&t);
    while (t--){
        memset(aa,0,sizeof(aa));
        memset(bb,0,sizeof(bb));
        memset(lt,0,sizeof(lt));
        memset(ans,0,sizeof(ans));
        int tt;
        scanf("%d%d%d%d",&n,&x,&m,&tt);
        for (int i = 0;i < n; ++i) for (int j = 0;j < x; ++j) scanf("%d",&aa[i][j]);
        for (int i = 0;i < x; ++i) for (int j = 0;j < m; ++j) scanf("%d",&bb[i][j]);
        mat st;
        for (int i = 0;i < x; ++i) for (int j = 0;j < x; ++j) st.rix[i][j] = 0;
        for (int i = 0;i < x; ++i) for (int j = 0;j < x; ++j) for (int k = 0;k < m; ++k){
            st.rix[i][j] += bb[i][k]*aa[k][j];
            st.rix[i][j] %= mod;
        }
        mat ed;
         ed = q_mod(st,tt-1);
         for (int i = 0;i < n; ++i) for (int j = 0;j < x; ++j) for (int k = 0;k < x; ++k){
            lt[i][j] += aa[i][k]*ed.rix[k][j];
            lt[i][j] %= mod;
         }
         for (int i = 0;i < n; ++i) for (int j = 0;j < m; ++j) for (int k = 0;k < x; ++k){
            ans[i][j] += lt[i][k]*bb[k][j];
            ans[i][j] %= mod;
         }
         int sum = 0;
         for (int i = 0;i < n; ++i) for(int j = 0;j < m; ++j) sum=(sum+ans[i][j])%mod;
         printf("%d\n",sum);

    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值