【日更】矩阵方面的各种习题?

来源:互联网 发布:刀锋上的救赎 知乎 编辑:程序博客网 时间:2024/06/07 21:45

恩……大二小萌新。
老板说要开始系统的学算法了呢恩……。
我先把之前开的矩阵习题做完再说别的好了。
然后后面可能会有一些最近刚出的题……2017年的icpc什么的。
打算停止更新啦……需要用的dp啊递推啊什么的知识太多了,只凭着数学有点忙不过来,先去补点dp。

题目列表来自http://blog.csdn.net/a601025382s/article/details/10251613

1.hdu 1005 矩阵基础题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1005
题解代码:http://blog.csdn.net/a601025382s/article/details/10251423

#include<stdio.h> #include<string.h>using namespace std;const int m=2; const int mod=7;struct matrix{    int x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int a,b,n;    while(scanf("%d%d%d",&a,&b,&n)!=EOF){        if(a==0 && b==0 && n==0) break;        matrix st;        st.x[0][0]=a;        st.x[0][1]=1;        st.x[1][0]=b;        st.x[1][1]=0;        st=powmatrix(st,n-1);        printf("%d\n",(st.x[0][1]+st.x[1][1])%mod);    }    return 0;}

2.hdu 1575 矩阵基础题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1575
题解代码:http://blog.csdn.net/a601025382s/article/details/10122331

#include<stdio.h> #include<string.h>using namespace std;int m;const int mod=9973;struct matrix{    int x[10][10];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int T;    scanf("%d",&T);    while(T--){        matrix st;        int n,k;        scanf("%d%d",&n,&k);        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                scanf("%d",&st.x[i][j]);        m=n;        st=powmatrix(st,k);        int sum=0;        for(int i=0;i<n;i++)            sum+=st.x[i][i];        printf("%d\n",sum%mod);    }    return 0;}

3.hdu 1757 矩阵基础题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1757
题解代码:http://blog.csdn.net/a601025382s/article/details/10122695

#include<stdio.h> #include<string.h>using namespace std;const int m=10;int mod;struct matrix{    int x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int n;    while(scanf("%d%d",&n,&mod)!=EOF){        matrix st;        for(int i=0;i<10;i++)            for(int j=0;j<10;j++) st.x[i][j]=0;        for(int i=0;i<=9;i++)            scanf("%d",&st.x[0][i]);        st.x[1][0]=st.x[2][1]=st.x[3][2]=st.x[4][3]=st.x[5][4]=st.x[6][5]=st.x[7][6]=st.x[8][7]=st.x[9][8]=1;        st=powmatrix(st,n-9);        printf("%d\n",(9*st.x[0][0]+8*st.x[0][1]+7*st.x[0][2]+6*st.x[0][3]+5*st.x[0][4]+4*st.x[0][5]+3*st.x[0][6]+2*st.x[0][7]+st.x[0][8])%mod);    }    return 0;}

4.poj 3734 找出递推关系,然后用矩阵加速
题目链接:http://poj.org/problem?id=3734
题解代码:http://blog.csdn.net/a601025382s/article/details/10240251

#include<stdio.h> #include<string.h>using namespace std;const int m=3;const int mod=10007;struct matrix{    int x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int T;    scanf("%d",&T);    while(T--){        int n;        scanf("%d",&n);        matrix st;        st.x[0][0]=2;        st.x[0][1]=1;        st.x[0][2]=0;        st.x[1][0]=2;        st.x[1][1]=2;        st.x[1][2]=2;        st.x[2][0]=0;        st.x[2][1]=1;        st.x[2][2]=2;        st=powmatrix(st,n);        printf("%d\n",st.x[0][0]%mod);    }    return 0;}

5.poj 2888 较难题,需要用到置换(burnside引理),欧拉phi函数,最后用矩阵加速
题目链接:http://poj.org/problem?id=2888
题解代码:http://blog.csdn.net/a601025382s/article/details/10239295

6.poj 3420 dp+矩阵(相关的有poj2663,poj2411)
题目链接:http://poj.org/problem?id=3420
题解代码:http://blog.csdn.net/a601025382s/article/details/10218563

这可能是我做的第一道比较难……对不起,至少不是基础题的矩阵题,置于前面那道矩阵+Burnside引理+欧拉函数+不动点的例题……恩……等我什么时候脑子清楚了再说,刚开始练习矩阵的时候被板子坑的不行。
然后这道题其实就是一个递推,非要说dp的话其实也不用。
首先尝试用递推解法来解。我们首先用手模拟画出4*2,4*3,4*4,4*5以及4*6的不可分割的矩阵。令a[n]表4*n规模的矩阵的摆放骨牌总数,b[n]表示4*n规模的不可分割的矩阵个数。
我们会发现a[1]=b[1]=1,b[2]=4,并且当n>=3时有以下规律:
当n为奇数时:b[n]=2
当n为偶数时:b[n]=3
然后按照递推关系可得公式:a[n]=a[n-1]*b[1]+a[n-2]*b[2]+…a[1]*b[n-1]+a[0]*b[n]
又因为b[n]=b[n-2]=b[n-4]=…
b[n-1]=b[n-3]=b[n-5]=…
所以上面推出的公式有把无限项消掉的可能。
由公式得:a[n-2]=a[n-3]*b[1]+a[n-4]*b[2]+…a[1]*b[n-3]+a[0]*b[n-2]
将两个式子相减可得a[n]-a[n-2]=b[1]*a[n-1]+b[2]*a[n-2]+(b[3]-b[1])*a[n-3]+(b[4]-b[2])*a[n-4]
然后我们把b[1],b[2],b[3],b[4]代进去。
得到递推公式:a[n]=a[n-1]+5a[n-2]+a[n-3]-a[n-4]

说是需要用轮廓线dp验证一下可是我就是因为不会轮廓线dp才用的递推嘛。
然后就是很正常的四阶矩阵了。
下面ac代码。
不得不说我在结果那边wa了很久因为结果有可能是负的需要加个mod再模mod。
然后改了又wa了因为1%1=0,我当时下意识1是直接输出的。
总之,很烦。

#include<stdio.h> #include<string.h>using namespace std;const int m=4;int mod;struct matrix{    int x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int n;    while(scanf("%d%d",&n,&mod)!=EOF){        if(n==0&&mod==0) break;        if(n==1)            printf("%d\n",1%mod);        else if(n==2)            printf("%d\n",5%mod);        else if(n==3)            printf("%d\n",11%mod);        else{            matrix st;            for(int i=0;i<4;i++)                for(int j=0;j<4;j++) st.x[i][j]=0;            st.x[0][0]=1;            st.x[0][1]=5;            st.x[0][2]=1;            st.x[0][3]=-1;            st.x[1][0]=st.x[2][1]=st.x[3][2]=1;            st=powmatrix(st,n-3);            printf("%d\n",((11*st.x[0][0]+5*st.x[0][1]+st.x[0][2]+st.x[0][3])%mod+mod)%mod);            }    }    return 0;}

7.zoj 3690 递推+矩阵
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3690
题解代码:http://blog.csdn.net/a601025382s/article/details/8742961

之前矩阵做了几道题思路被限制住了……因为每次都是推的单一数列的递增关系,然后碰到有关联的两组数列就不知道怎么弄了……我的锅。

然后题目的意思是有n个人,m个数和一个k,现在每个人可以选择一个数,但是要求如果相邻的两个人选择相同的数,那么这个数要大于k。

假设F(n)表示前n个人第n个人选择的数大于k的个数,G(n)表示的是前n个人第n个人选择的数小于等于k的个数,那么F(n) = F(n-1) x (m-k)+G(n-1) x (m-k) , G(n) = F(n-1) x k+G(n-1) x (k-1) , 最后的结果就是F(n)+G(n)。(里面的x就是乘……两个*会自动转化成斜体我也很无奈。)

前面递归写出来都是an,an-1用矩阵和an-1,an-2表示的对吧,然后这题是F(n),G(n)用矩阵和F(n-1),G(n-1)表示……额算是两个一维矩阵?其实也很好理解只是因为我菜所以想了很久……恩。

有的地方会超int要注意,wa了一发。

#include<stdio.h> #include<string.h>using namespace std;const int m=2;const int mod=1000000007;struct matrix{    long long x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int n,p,k;    while((scanf("%d%d%d",&n,&p,&k))!=EOF){        matrix st;        st.x[0][0]=p-k;        st.x[0][1]=p-k;        st.x[1][0]=k;        st.x[1][1]=k-1;        st=powmatrix(st,n-1);        printf("%d\n",(st.x[0][0]*(p-k)+st.x[0][1]*k+st.x[1][0]*(p-k)+st.x[1][1]*k)%mod);    }    return 0;}

8.poj 3150 循环矩阵题,从前一组状态推出后一组状态即可,不过n太大,需要用循环矩阵加速
题目链接:http://poj.org/problem?id=3150
题解代码:http://blog.csdn.net/a601025382s/article/details/9840613,在uva交的,poj上输入输出格式可能不一样

9.hdu 4565 13年长沙邀请赛的题目,需要数论知识推出矩阵关系
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4565
题解代码:http://blog.csdn.net/a601025382s/article/details/10045229

是的所以我又空了一道题,来我们先做简单点的。

啊这题,首先第一反应是快速幂,然后不行,有小数。接着考虑矩阵快速幂,我们的目的是把小数排除掉,我第一个想法是从展开式里做文章,把小数分成整数部分和小数部分,小数乘小数的舍掉因为永远小于1,后来推了推不是很好实现。

然后我想到直接把可能出现小数部分的始作俑者提出来,也就是√b。

自然而然的可以想到,Sn一定可以用一个整数和一个带系数的√b项表示,即Sn=Xn+Yn*√b。

Xn+Yn*√b = (Xn-1 + Yn-1*√b)*(a+√b)
Xn+Yn*√b = a*Xn-1 + a*Yn-1*√b + Xn-1*√b + b*Yn-1

把整数和带√b的项分别合并,显然得:

Xn = a*Xn-1 + b*Yn-1
Yn = Xn-1 + a*Yn-1

然后就跟第七题一样构建矩阵做就好啦……。

这道题其实我wa了很多次,我写矩阵都是很规矩按照公式来的,从x1开始推就乘n-1次,从x0开始推就乘n次这样的,最后也是很规矩的把系数一项一项乘进去。这题本来也是这样的,但是后面精度一直爆,其实我也不知道是不是爆了精度,只不过我比较自信其他的没写错。最后还是改成了n次相乘才过了题。

……可是我看了看取值范围还是不觉得会爆long long啊就很烦。

下面ac代码。

#include<stdio.h>#include<string.h>#include<math.h>using namespace std;const int m=2;int mod;struct matrix{    long long x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,int b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    int a,b,n;    while((scanf("%d%d%d%d",&a,&b,&n,&mod))!=EOF){        matrix st;        st.x[0][0]=a;        st.x[0][1]=b;        st.x[1][0]=1;        st.x[1][1]=a;        st=powmatrix(st,n);        printf("%lld\n",2*st.x[0][0]%mod);    }    return 0;}

10.hdu 4686 推公式,需要点时间
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4686
题解代码:http://blog.csdn.net/a601025382s/article/details/10114885

这题一开始我以为我和上一题一样死大数了,后来发现死0的特判了,wa的不值。

这题就是推一个关于an,bn,fn,Sn的矩阵,其中fn=an*bn,Sn为所求前n项和。然后推出来你发现递推公式里有常数项,所以就需要创一个关于an,bn,fn,Sn,1的五维矩阵,最后的1用来抵常数项。

递推公式推出来挺简单的,写着太麻烦了我就不写了,看代码就行,代码是按照数学矩阵规范写的。

以下ac代码。

#include<stdio.h> #include<string.h>using namespace std;const int m=5;const int mod=1000000007;struct matrix{    long long x[m][m];};matrix mutimatrix(matrix a,matrix b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        for(int j=0;j<m;j++)            for(int k=0;k<m;k++){                temp.x[i][j]+=a.x[i][k]*b.x[k][j];                temp.x[i][j]%=mod;            }    return temp;}matrix powmatrix(matrix a,long long b){    matrix temp;    memset(temp.x,0,sizeof(temp.x));    for(int i=0;i<m;i++)        temp.x[i][i]=1;    while(b){        if(b%2==1) temp=mutimatrix(temp,a);        a=mutimatrix(a,a);        b=b/2;    }    return temp;}int main(){    long long n;    while((scanf("%lld",&n))!=EOF){        long long a0,ax,ay,b0,bx,by;        scanf("%lld%lld%lld%lld%lld%lld",&a0,&ax,&ay,&b0,&bx,&by);        a0%=mod;        b0%=mod;        matrix st;        st.x[0][0]=ax%mod;        st.x[0][1]=0;        st.x[0][2]=0;        st.x[0][3]=0;        st.x[0][4]=ay%mod;        st.x[1][0]=0;        st.x[1][1]=bx%mod;        st.x[1][2]=0;        st.x[1][3]=0;        st.x[1][4]=by%mod;        st.x[2][0]=ax*by%mod;        st.x[2][1]=ay*bx%mod;        st.x[2][2]=ax*bx%mod;        st.x[2][3]=0;        st.x[2][4]=ay*by%mod;        st.x[3][0]=ax*by%mod;        st.x[3][1]=ay*bx%mod;        st.x[3][2]=ax*bx%mod;        st.x[3][3]=1;        st.x[3][4]=ay*by%mod;        st.x[4][0]=0;        st.x[4][1]=0;        st.x[4][2]=0;        st.x[4][3]=0;        st.x[4][4]=1;        st=powmatrix(st,n-1);        if(n==0) printf("0\n");        else printf("%lld\n",(st.x[3][0]*a0%mod+st.x[3][1]*b0%mod+st.x[3][2]*((a0*b0)%mod)%mod+a0*b0%mod+st.x[3][4]%mod)%mod);     }    return 0;}

11.hdu 3893 状态很多,需要通过对称性来简化题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3893
题解代码:http://blog.csdn.net/a601025382s/article/details/10122107

12.hdu 4291 找循环,在3次矩阵
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4291
题解代码:http://blog.csdn.net/a601025382s/article/details/10133651

13.hdu 2256 跟长沙邀请赛的那题很想,将2n中的2花掉,就一样了
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2256
题解代码:http://blog.csdn.net/a601025382s/article/details/10135719

14.hdu 2604 dp+矩阵,
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2604
题解代码:http://blog.csdn.net/a601025382s/article/details/10137011

15.fzu 1683 又是函数求和s[n]=s[n-1]+f[n],以此推矩阵
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1683
题解代码:http://blog.csdn.net/a601025382s/article/details/10142725

16.hdu 1588 需要推导下,等比矩阵和。。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1588
题解代码:http://blog.csdn.net/a601025382s/article/details/10147389

17.hdu 3117 这题也用到斐波那契通项公式,不过不是用来推矩阵的
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3117
题解代码:http://blog.csdn.net/a601025382s/article/details/10150441

18.hdu 2254 经典题,用矩阵求路径的走法方案数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2254
题解代码:http://blog.csdn.net/a601025382s/article/details/10159845

19.hdu 2276 普通矩阵题,直接求状态即可,虽然矩阵是个循环矩阵。。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2276
题解代码:http://blog.csdn.net/a601025382s/article/details/10160467

20.fzu 1692 又一道循环矩阵题
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1692
题解代码:http://blog.csdn.net/a601025382s/article/details/10161947

21.zoj 2853 概率的矩阵题
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2853
题解代码:http://blog.csdn.net/a601025382s/article/details/10170785

22.zoj 2974 还是概率矩阵题,不过需要注意下特殊的数据
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2974
题解代码链接:http://blog.csdn.net/a601025382s/article/details/10171941
23.poj 3735 理解各个处理方式有点。。推出来就简单了
题目链接:http://poj.org/problem?id=3735
题解代码:http://blog.csdn.net/a601025382s/article/details/10173521

24.hdu 2855 较难题,需要用斐波那契数列通项公式推导,当然你眼力够强,也可以从数据里得出规律
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2855
题解代码:http://blog.csdn.net/a601025382s/article/details/10195939

25.hdu 2971 较难题,主要需要推公式,有点难发现
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2971
题解代码:http://blog.csdn.net/a601025382s/article/details/10196907

26.hdu 2294 dp+矩阵,不多说了,只要会用长度和种数dp就好了
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2294
题解代码:http://blog.csdn.net/a601025382s/article/details/10198553

27.hdu 3233 等比矩阵和,可以讲矩阵看做一个元素,这样就可以得到以矩阵为元素的矩阵了
题目链接:http://poj.org/problem?id=3233
题解代码:http://blog.csdn.net/a601025382s/article/details/10199559

28.poj 3744 较难题,根据地雷前后的状态来推,需要多次矩阵
题目链接:http://poj.org/problem?id=3744
题解代码:http://blog.csdn.net/a601025382s/article/details/10209009