hdu 4965 Fast Matrix Calculation【矩阵快速幂】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4965

题目大意:给出一个N*K和一个K*N的矩阵A,B(4<=N<=1000&&2<=K<=6)按顺序进行如下四种操作之后,求出最终得到的矩阵的所有元素的和。

step 1 :令C=A*B;

step 2 :令D=C^(N*N);

step 3 :D中所有元素模6

step 4 :求出D中所有元素之和


首先当然想到的只能是顺着做下来,但是想想,step 2中,我们求一个N*N的矩阵就算用矩阵快速幂,那复杂度也是O(N^3*logN),这很明显已经超时。那么应该怎么做呢?

再看看数据,K最大只有6?那我们可不可以转化一下方法,将复杂度变成K相关呢?换一下相乘的顺序吗?


突然想到这样一个式子: (AB)^N=A(BA)^(N-1)B


利用这样一个式子,我们就可以将快速幂的复杂度降到O(K^3*logK) 这样就 已经节约了大量的时间。


代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define N 1010
using namespace std;
int** mul(int** A,int** B,int n,int m,int l)//其实不用返回二重指针这样麻烦,先开好自己需要用的数组,每次将该数组传进来赋值给该数组即可。下同
{
    int **t=new int*[n];
    for(int i=0;i<n;i++)
        t[i]=new int[l];
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<l;j++)
        {
            int tmp=0;
            for(int k=0;k<m;k++)
            {
                tmp+=(A[i][k]*B[k][j]);
            }
            t[i][j]=tmp%6;
        }
    }
    return t;
}
int** expo(int **p,int k,int n)
{
    if(k==1) return p;
    int **e=new int*[n];
    for(int i=0;i<n;i++)
        e[i]=new int[n];
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j)
            e[i][j] = (i == j);
    while(k)
    {
        if(k&1)
            e=mul(e,p,n,n,n);
        p=mul(p,p,n,n,n);
        k>>=1;
    }
    return e;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("D:/in.txt","r",stdin);
    //freopen("D:/my.txt","w",stdout);
#endif
    int NN,K;
    while(~scanf("%d%d",&NN,&K)&&(NN||K))
    {
        int **a=new int*[NN];
        for(int i=0;i<NN;i++)
            a[i]=new int[K];
        int **b=new int*[K];
        for(int i=0;i<NN;i++)
            b[i]=new int[NN];
        int **c;
        for(int i=0;i<NN;i++)
            for(int j=0;j<K;j++)
                scanf("%d",&a[i][j]);
        for(int i=0;i<K;i++)
            for(int j=0;j<NN;j++)
                scanf("%d",&b[i][j]);
        c=mul(b,a,K,NN,K);
        int temp=NN*NN-1;
        c=expo(c,temp,K);
        c=mul(a,c,NN,K,K);
        c=mul(c,b,NN,K,NN);
        int ans=0;
        for(int i=0;i<NN;i++)
            for(int j=0;j<NN;j++)
                ans+=c[i][j];
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值