矩阵专题训练1

HDU 1757

http://acm.hdu.edu.cn/showproblem.php?pid=1757

题意很清楚不同的X对应不同的FX,而且当X>=10时,有一个递推公式,因为N比较大,所以简单的暴力去写肯定不可能,所以要构造矩阵用快速幂解决。。。

思路:前10个FX简单保存下值,然后当X>=10时构造10*10的进行快速幂的矩阵 和10*1的初始矩阵。

大致可以写成/*****************************************
|0 1 0 0 0 0 0 0 0 0 |  |f(x-10)|   |f(x-9)|
|0 0 1 0 0 0 0 0 0 0 |  |f(x-9) |   |f(x-8)|
|0 0 0 1 0 0 0 0 0 0 |  |f(x-8) |   |f(x-7)|
|0 0 0 0 1 0 0 0 0 0 |  |f(x-7) |   |f(x-6)|
|0 0 0 0 0 1 0 0 0 0 |* |f(x-6) |=  |f(x-5)|
|0 0 0 0 0 0 1 0 0 0 |  |f(x-5) |   |f(x-4)|
|0 0 0 0 0 0 0 1 0 0 |  |f(x-4) |   |f(x-3)|
|0 0 0 0 0 0 0 0 1 0 |  |f(x-3) |   |f(x-2)|
|0 0 0 0 0 0 0 0 0 1 |  |f(x-2) |   |f(x-1)|
|a9 a8 a7 a6 a5... a1|  |f(x-1) |   |f(x)  |
******************************************/然后就O了,当时代码写的较矬 我自己都看不懂了。。。

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

int a[10][10];
int ans[10];
int k,m;
int f[20];
int b[10];
void fun()
{
    memset(f,0,sizeof(f));
    for(int i=0;i<=9;i++)
    {
        f[i]=i;
        f[i]%=m;
    }
    for(int i=10;i<20;i++)
    {
        for(int j=0;j<=9;j++)
        {
            f[i]+=(b[j]*f[i-j-1])%m;
            f[i]%=m;
        }
    }
}
void cheng1()
{
    int temp[10];
    memset(temp,0,sizeof(temp));
    for(int i=0;i<10;i++)
    {
        for(int j=0;j<10;j++)
        {
            temp[i]+=(ans[j]*a[j][i])%m;
            temp[i]%=m;
        }
    }
    for(int i=0;i<10;i++)
    {
        ans[i]=temp[i];
    }
}

void cheng2()
{
    int temp1[10][10];
    memset(temp1,0,sizeof(temp1));
    for(int i=0;i<10;i++)
    {
        for(int j=0;j<10;j++)
        {
            for(int k=0;k<10;k++)
            {
                temp1[i][j]+=(a[i][k]*a[k][j])%m;
                temp1[i][j]%=m;
            }
        }
    }
    for(int i=0;i<10;i++)
    {
        for(int j=0;j<10;j++)
        {
            a[i][j]=temp1[i][j];
        }
    }
}
int main()
{
    while(cin>>k>>m)
    {
        memset(a,0,sizeof(a));
        for(int i=0;i<10;i++)
        {
            cin>>b[i];
            a[i][0]=b[i];
        }
        for(int i=1;i<10;i++)
        {
            a[i-1][i]=1;
        }
        fun();
        if(k<=19)
        {
            cout<<f[k]<<endl;
        }
        else
        {  k=k-19;
           for(int i=0;i<10;i++)
           {
               ans[i]=f[19-i];
           }
           while(k)
           {
               if(k%2==0)
               {
                   cheng2();
                   k/=2;
               }
               else
               {
                   cheng1();
                   k--;
               }
           }
         cout<<ans[0]<<endl;
        }

    }
    return 0;
}
POJ 3233

S = A + A2 + A3 + … + Ak.

思路:对矩阵进行二分求和,若K为奇数,多出来的那个数直接快速幂,剩余的进行二分求和,然后二分进行递归按照是奇数单独拿一个去快速幂的思路可以敲出。

http://poj.org/problem?id=3233

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

struct juzhen{

int m[30][30];


};
int n,k,mod;

juzhen mut(juzhen a,juzhen b)
{
    juzhen c;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            c.m[i][j]=0;
            for(int k=0;k<n;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
                c.m[i][j]%=mod;
            }
        }
    }
   return c;
}

juzhen add(juzhen a,juzhen b)
{
    juzhen c;
    memset(c.m,0,sizeof(c.m));

    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            c.m[i][j]+=(a.m[i][j]+b.m[i][j])%mod;
            c.m[i][j]%=mod;
        }
    }
    return c;
}

juzhen pow(juzhen a,int p)
{
    juzhen c;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            if(i==j)
            {
                c.m[i][j]=1;
            }
            else
            {
                c.m[i][j]=0;
            }
        }
    }
    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a);
            p/=2;
        }
        else
        {
            c=mut(c,a);
            p--;
        }
    }
    return c;
}

juzhen erfen(juzhen a,int p)
{
    if(p==1)
        return a;
    if(p==2)
        return add(a,mut(a,a));
    if(p%2==1)
    {
        return add(erfen(a,p-1),pow(a,p));
    }
    if(p%2==0)
    {
        juzhen c;
        c=erfen(a,p/2);//这里先进行二分省的进入递归时每次再进行这步操作可以提高效率。。一开始没优化狂T。
        return add(c,mut(pow(a,p/2),c));
    }


}

int main()
{
    scanf("%d%d%d",&n,&k,&mod);

        juzhen a;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
               scanf("%d",&a.m[i][j]);
            }
        }
        a=erfen(a,k);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                printf("%d ",a.m[i][j]);
            }
            printf("\n");
        }





    return 0;
}

HDU 1588

http://acm.hdu.edu.cn/showproblem.php?pid=1588

也是矩阵二分求和,而且F是斐波那契矩阵只不过注意F(G(n))=F(K*n+b)=a^b(a^0+a^k+a^2k+a^3k+...a^(n-1)*k)

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

struct juzhen{

long long  m[2][2];

};

long long  k,b,n,M;

juzhen mut(juzhen a,juzhen b)
{
    juzhen c;
    for(long long  i=0;i<2;i++)
    {
        for(long long  j=0;j<2;j++)
        {
            c.m[i][j]=0;
            for(long long  k=0;k<2;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%M;
                c.m[i][j]%=M;
            }
        }
    }
    return c;
}

juzhen add(juzhen a,juzhen b)
{

    juzhen c;
    memset(c.m,0,sizeof(c.m));
    for(long long  i=0;i<2;i++)
    {
        for(long long  j=0;j<2;j++)
        {
            c.m[i][j]+=(a.m[i][j]+b.m[i][j])%M;
            c.m[i][j]%=M;
        }
    }
    return c;
}


juzhen pow(juzhen a,long long  p)
{
    juzhen b;
    b.m[0][0]=b.m[1][1]=1;
    b.m[0][1]=b.m[1][0]=0;

    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a);
            p/=2;
        }
        else
        {
            b=mut(b,a);
            p--;
        }
    }
    return b;
}


juzhen erfen(juzhen a,long long  p)
{
    if(p==1)
        return a;
    if(p==2)
        return add(a,mut(a,a));
    if(p%2==1)
    {
        return add(erfen(a,p-1),pow(a,p));
    }
    if(p%2==0)
    {
        juzhen c;
        c=erfen(a,p/2);
        return add(c,mut(pow(a,p/2),c));

    }
}

int  main()
{
    while(cin>>k>>b>>n>>M)
    {
        juzhen a;
        a.m[0][0]=a.m[0][1]=a.m[1][0]=1;
        a.m[1][1]=0;
        juzhen aa;
        aa=pow(a,b);
        juzhen bb;
        bb=pow(a,k);
        juzhen cc;
        cc=erfen(bb,n-1);
        juzhen dd;
        dd=mut(aa,cc);
        juzhen ans;
        ans=add(aa,dd);
        cout<<ans.m[0][1]<<endl;

    }


    return 0;

}

HDU 3306

http://acm.hdu.edu.cn/showproblem.php?pid=3306

Now we define another kind of Fibonacci : A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) (N >= 2).And we want to Calculate S(N) , S(N) = A(0)2 +A(1)2+……+A(n)2.

首先把AN平方有A(N)^2=X^2*A(N-1)^2+Y^2*A(N-2)^2+2*X*Y*A(N-1)*A(N-2) ,根据这个式子可以构造:

|1 x*x y*y 2*x*y|   |   SUMN      | |   SUMN+1      |
|0 x*x y*y 2*x*y|   |   A(N-1)^2  | |   A(N)^2      |
|0  1   0    0  |*  |   A(N-2)^2  |=|   A(N-1)^2    |
|0  x   0    y  |   |A(N-1)*A(N-2)| |   A(N)*A(N-1) |

特别注意A(N)*A(N-1)=(X*A(N-1)+Y*A(N-2))*A(N-1)=X*A(N-1)^2+Y*A(N-1)*(N-2)故最后一阶构造成0 X 0 Y的形式

剩下的。。就是注意取余的问题了。。

当然如果下次要求SUM类的矩阵记得在原定义的矩阵上多加一阶用来存放SUM的值然后就O了。

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


int n,x,y;
const int mod=10007;

struct juzhen {

int m[4][4];

};


juzhen mut(juzhen a,juzhen b)
{
    juzhen c;
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            c.m[i][j]=0;
            for(int k=0;k<4;k++)
            {
                c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
                c.m[i][j]%=mod;
            }
        }
    }
    return c;
}

juzhen pow(juzhen a,int p)
{
    juzhen b;
    memset(b.m,0,sizeof(b.m));
    for(int i=0;i<4;i++)
    {
        b.m[i][i]=1;
    }

    while(p)
    {
        if(p%2==0)
        {
            a=mut(a,a);
            p/=2;
        }
        else
        {
            b=mut(b,a);
            p--;
        }
    }
    return b;
}


int main()
{
    while(cin>>n>>x>>y)
    {
        juzhen a;
        x%=mod;
        y%=mod;
        a.m[0][0]=a.m[2][1]=1;
        a.m[1][0]=a.m[2][0]=a.m[3][0]=a.m[2][2]=a.m[2][3]=a.m[3][2]=0;
        a.m[0][1]=a.m[1][1]=(x*x)%mod;
        a.m[0][2]=a.m[1][2]=(y*y)%mod;
        a.m[0][3]=a.m[1][3]=(2*x*y)%mod;
        a.m[3][1]=x%mod;
        a.m[3][3]=y%mod;
        juzhen ans;
        ans=pow(a,n-1);

        int sum;
        sum=(2*ans.m[0][0]+ans.m[0][1]+ans.m[0][2]+ans.m[0][3])%mod;
        cout<<sum<<endl;


    }

return 0;

}

今天先写简单写下四题。。大概刷了12题,然后明天有时间更新2和3,智商比较低代码比较挫还望勿见怪,实力有限。。还得继续努力。。。

.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值