矩阵应用

之前遇到矩阵的一直没看  有时间了  学习学习。。。

(1)快速幂  原理不再赘述  来个模版:
int n;//矩阵的大小
const int mod=9973;
struct matrix
{
    int a[10][10];
};


matrix ori,res;

void init()
{
    memset(res.a,0,sizeof(res.a));
    for(int i=0;i<n;i++)
        res.a[i][i]=1;
}//给res初始化为单位矩阵  

matrix multiply(matrix x,matrix y)
{
    matrix temp;
    memset(temp.a,0,sizeof(temp.a));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            for(int k=0;k<n;k++)
            {
                temp.a[i][j]+=(x.a[i][k]*y.a[k][j]);
                temp.a[i][j]%=mod;
            }
        }
    }
    return temp;
}

void calc(int num)
{
    while(num)
    {
        if(num&1)
            res=multiply(ori,res);
        num>>=1;
        ori=multiply(ori,ori);
    }//最终的结果保存在res 中
//    for(int i=0;i<n;i++)
//    {
//        for(int j=0;j<n;j++)
//            cout<<res.a[i][j]<<"\t";
//        cout<<endl;
//    }


hdu 1575 Tr A

题目大意就是求所给矩阵的k次方后得到一个矩阵  然后求所得矩阵主对角线上数字之和 

模版题  直接套用模版即可

代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
int n;//矩阵的大小
const int mod=9973;

struct matrix
{
    int a[10][10];
};

matrix ori,res;

void init()
{
    memset(res.a,0,sizeof(res.a));
    for(int i=0;i<n;i++)
        res.a[i][i]=1;
}

matrix multiply(matrix x,matrix y)
{
    matrix temp;
    memset(temp.a,0,sizeof(temp.a));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            for(int k=0;k<n;k++)
            {
                temp.a[i][j]+=(x.a[i][k]*y.a[k][j]);
                temp.a[i][j]%=mod;
            }
        }
    }
    return temp;
}

void calc(int num)
{
    while(num)
    {
        if(num&1)
            res=multiply(ori,res);
        num>>=1;//num的值要变化
        ori=multiply(ori,ori);
    }
//    for(int i=0;i<n;i++)
//    {
//        for(int j=0;j<n;j++)
//            cout<<res.a[i][j]<<"\t";
//        cout<<endl;
//    }
}

int main()
{
freopen("ceshi.txt","r",stdin);
    int tc;
    scanf("%d",&tc);
    while(tc--)
    {
        int  k;
        scanf("%d%d",&n,&k);
        init();
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                scanf("%d",&ori.a[i][j]);
            }
        }
        calc(k);
        int sum=0;
        for(int i=0;i<n;i++)
        {
            sum=sum+res.a[i][i];
//            sum%=mod;
        }
//        while(sum<0)
//            sum+=mod;
        printf("%d\n",sum%mod);
    }
    return 0;
}



hdu 1757  A Simple Math Problem

求一个递推的函数f(k)的值  k<2*10^9    k的值可能会比较大 不能直接求  函数中涉及到的值比较多

f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10)
构造的矩阵是:

|0 0 ......... 0|    |f0|   |f1 |
|0 0 ....... 0|    |f1|   |f2 |
|................1|  |..| = |...|
|a9 a8 .........a0|    |f9|   |f10|

构造一个关于矩阵的计算 

我一开始做的时候 矩阵构造错了  最后一行写的是a0-a9  

读题要仔细啊骚年!!!

最后将矩阵相乘得到的值的最后一行以此与f0-f9相乘然后相加求和

代码相对来说就比较简单了  代码如下:

#include <iostream>
#include <cstdio>
#include <cstring>


using namespace std;

int m;

struct matrix
{
    int a[10][10];
};

matrix ori,res;


void init()
{
    memset(res.a,0,sizeof(res.a));
    for(int i=0;i<10;i++)
        res.a[i][i]=1;
}

matrix multiply(matrix x,matrix y)
{
    matrix temp;
    memset(temp.a,0,sizeof(temp.a));
    for(int i=0;i<10;i++)
        for(int j=0;j<10;j++)
            for(int k=0;k<10;k++)
            {
                temp.a[i][j]+=x.a[i][k]*y.a[k][j];
                temp.a[i][j]%=m;
            }
    return temp;
}

void calc(int n)
{
    while(n)
    {
        if(n&1)
            res=multiply(ori,res);
        n>>=1;
        ori=multiply(ori,ori);
    }
}

int main()
{
//freopen("ceshi.txt","r",stdin);
    int k;
    while(scanf("%d%d",&k,&m)!=EOF)
    {
        memset(ori.a,0,sizeof(ori.a));
        for(int i=0;i<10;i++)
            scanf("%d",&ori.a[9][9-i]);
        if(k<10)
            printf("%d\n",k%m);
        else
        {
            init();
            for(int i=0;i<9;i++)
            {
                ori.a[i][i+1]=1;
            }
            int b[10];
            for(int i=0;i<10;i++)
                b[i]=i;
            calc(k-9);
            int sum=0;
            for(int i=0;i<10;i++)
            {
                sum+=res.a[9][i]*b[i];
                sum%=m;
            }
            printf("%d\n",sum%m);
        }
    }
    return 0;
}




hdu 2256 Problem of Precision 

题目大意就是求一个表达式的2n次方后整数部分模1024的值  与之前在MSDN上末三位整数是一样的 

就是表达式一个精度的计算  

主要是要推出那个表达式 

(sqrt(2)+sqrt(3))^2n=(5+2*sqrt(6))^n=An+sqrt(6)*Bn

(5+2*sqrt(6))^(n+1)=An+1+sqrt(6)*Bn+1=(An+sqrt(6)*Bn)*(5+2*sqrt(6))

所以 An+1=5An+12Bn   Bn+1=2*An+5*Bn  从而就可以构造矩阵了

但是光是这样 还不能正确求得解

看的别人的。。


简直了。。。

贴个代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

const int mod=1024;

struct matrix
{
    int a[2][2];
};

matrix ori,res;

void init()
{
    res.a[0][1]=res.a[1][0]=0;
    res.a[0][0]=res.a[1][1]=1;
}

matrix multiply(matrix x,matrix y)
{
    matrix temp;
    memset(temp.a,0,sizeof(temp.a));
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
    {
        temp.a[i][j]+=x.a[i][k]*y.a[k][j];
        temp.a[i][j]%=mod;
    }
    return temp;
}

void calc(int n)
{
    while(n)
    {
        if(n&1)   res=multiply(ori,res);
        n>>=1;
        ori=multiply(ori,ori);
    }
}

int main()
{
    freopen("ceshi.txt","r",stdin);
    int tc;
    scanf("%d",&tc);
    while(tc--)
    {
        init();
        int a1=5,b1=2;
        ori.a[0][0]=ori.a[1][1]=5;
        ori.a[0][1]=12;
        ori.a[1][0]=2;
        int n;
        scanf("%d",&n);
        calc(n-1);
        int a2,b2;
//for(int i=0;i<2;i++)
//{
//    for(int j=0;j<2;j++)
//    {
//        printf("%d\t",res.a[i][j]);
//    }
//    puts("");
//}
        a2=res.a[0][0]*a1%mod+res.a[0][1]*b1%mod;

        b2=res.a[1][0]*a1%mod+res.a[1][1]*b1%mod;
        a2%=mod;
        b2%=mod;
//cout<<a2<<"  "<<b2<<endl;
//        int sum=(int)(a2+sqrt(6)*b2);
        int sum=2*a2-1;
        printf("%d\n",sum%mod);
    }
    return 0;
}




//待续  欢迎大家评论 给点建议

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值