矩阵专题训练1

来源:互联网 发布:快手表白神器软件 编辑:程序博客网 时间:2024/05/29 08:37

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
原创粉丝点击