矩阵乘

来源:互联网 发布:洛阳聚麟网络怎么样 编辑:程序博客网 时间:2024/04/26 16:00

一年前这个时候学的矩阵乘法, 但是当时好像就没怎么懂, 前天碰到了这种题果然还是不会做, ,,多做几道练习吧。

求K位的相邻两位之差不大于2的题。

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#define mod 1000000007using namespace std;long long k;inline void cheng(int a[11][11], int b[11][11]){    int c[11][11] = {0};    for(int i = 0; i < 10; i ++)        for(int j = 0; j < 10; j ++)            for(int k = 0; k < 10; k ++)                c[i][j] = ((long long)a[i][k] * b[k][j] + c[i][j]) % mod;    for(int i = 0; i < 10; i ++)        for(int j = 0; j < 10; j ++)            a[i][j] = c[i][j];  }int a[11][11], b[11][11], ans;int main(){    freopen("sam.in", "r", stdin);    freopen("sam.out", "w", stdout);    scanf("%I64d", &k);    long long n = k;    if(n == 1){puts("10"); return 0;}    for(int i = 0; i < 10; i ++)a[i][i] = 1;    for(int i = 0; i < 10; i ++){        for(int j = 0; j < 10; j ++)            if(abs(j - i) <= 2)                b[i][j] = 1;        }    n--;    while(n){        if(n & 1)cheng(a, b);        n = n >> 1;        cheng(b, b);        }    for(int j = 1; j < 10; j ++)        for(int k = 0; k < 10; k ++)            ans= (ans + a[k][j]) % mod;    cout<<ans<<endl;   // system("pause");    return 0;}
然后做了noi2012随机数生成器

这个只是一个简单的两位的矩阵但是两个longlong乘起来会爆, 所以还需要用快速乘, 以前没写过快速乘, 不过还是很好写的, 就是和快速幂一样的思想, 从乘2到乘4再到乘8这样注意地把一个乘数分解就好了。但是我做这道题的时候还是不能自己构建出矩阵。。继续联系吧

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>using namespace std;long long m, a, c, x0, n, q;long long cheng1(long long x, long long y){    long long ans = 0;    for(; y; y>>=1, x = (x * 2) % m)        if(y & 1) ans = (ans + x) % m;    return ans;}inline void cheng(long long aa[5][5], long long bb[5][5]){    long long cc[5][5] = {0};    cc[1][1] = (cheng1(aa[1][1] , bb[1][1]) + cheng1(aa[1][2] , bb[2][1]))%m ;      cc[1][2] = (cheng1(aa[1][1] , bb[1][2]) + cheng1(aa[1][2] , bb[2][2]))%m ;    cc[2][1] = (cheng1(aa[2][1] , bb[1][1]) + cheng1(aa[2][2] , bb[2][1]))%m ;      cc[2][2] = (cheng1(aa[2][1] , bb[1][2]) + cheng1(aa[2][2] , bb[2][2]))%m ;    aa[1][1] = cc[1][1]; aa[1][2] = cc[1][2]; aa[2][1] = cc[2][1]; aa[2][2] = cc[2][2];}long long aa[5][5], bb[5][5];int main(){    scanf("%lld%lld%lld%lld%lld%lld", &m, &a, &c, &x0, &n, &q);    aa[1][1] = c; aa[1][2] = x0;    bb[1][1] = 1; bb[1][2] = 1;bb[2][2] = a;    for(; n; n>>=1, cheng(bb, bb))        if(n & 1)cheng(aa, bb);    printf("%lld\n", aa[1][2] % q);   // system("pause");    return 0;}

对了lc 讲课的时候说到了一个很简单但是很好用的技巧

就是在

    for(int i = 0; i < 10; i ++)        for(int j = 0; j < 10; j ++)            for(int k = 0; k < 10; k ++)
这个循环中写成这样:

    for(int i = 0; i < 10; i ++)        for(int k = 0; k < 10; k ++)if(a[i][k])            for(int j = 0; j < 10; j ++)

就可以一下子快很多了!!!!!


这篇 写构造矩阵的文章真的觉得挺好的。


然后要做一下  这个   M67 的矩阵十题练下手吧。

关于题解M67 已经写得很详细了。


关于我总是弄错的一个点旋转之后的坐标, 可以  见此  , 有一个简单的证明。就是用一个和角公式, 挺简单的。

然后这道题就没什么了。

丑恶代码

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#define A alter.a#define pi 3.141592653589793238452643383279502884197169using namespace std;int n, m;struct Matrix{    double a[5][5];    }point[10005], alter, now, ans;Matrix cheng(Matrix x, Matrix y){    Matrix tmp;    memset(tmp.a, 0, sizeof(tmp.a));    for(int i = 1; i <= 3; i ++)        for(int k = 1; k <= 3; k ++)if(x.a[i][k])            for(int j = 1; j <= 3; j ++)                tmp.a[i][j] += x.a[i][k] * y.a[k][j];    return tmp;    }int main(){    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; i ++)scanf("%lf%lf", &point[i].a[1][1], &point[i].a[2][1]), point[i].a[3][1] = 1;    memset(now.a, 0, sizeof(now.a));    for(int i = 1; i <= 3; i ++)now.a[i][i] = 1;         for(int i = 1; i <= m; i ++){        char c[5];     scanf("%s", c); double a, b;         memset(A, 0, sizeof(A));         for(int j = 1; j <= 3; j ++)A[j][j] = 1;        if(c[0] == 'M'){ scanf("%lf%lf", &a, &b);            A[1][3] = a; A[2][3] = b;           }        if(c[0] == 'X') A[2][2] = -1;        if(c[0] == 'Y') A[1][1] = -1;        if(c[0] == 'S'){    scanf("%lf", &a);            A[1][1] = A[2][2] = a;           }        if(c[0] == 'R'){    scanf("%lf", &a);            a = a / 180 * pi;            A[1][1] = A[2][2] = cos(a);            A[1][2] = -sin(a); A[2][1] = sin(a);        }   now = cheng(alter, now);    }    for(int i = 1; i <= n; i ++){        ans = cheng(now, point[i]);        printf("%.1lf %.1lf\n", ans.a[1][1], ans.a[2][1]);        }   // system("pause");    return 0;}


hdu 1575

裸的矩阵快速幂, 以前打过的。

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#define mod 9973using namespace std;int n, k;struct Matrix{    int a[11][11];    }now, a, tmp;Matrix cheng(Matrix a, Matrix b){    memset(tmp.a, 0, sizeof(tmp.a));    for(int i = 1; i <= n; i ++)        for(int k = 1; k <= n; k ++)if(a.a[i][k])            for(int j = 1; j <= n; j ++){                tmp.a[i][j] += (a.a[i][k] * b.a[k][j]) % mod;                tmp.a[i][j] %= mod;            }    return tmp;}void quick(int k){    memset(now.a, 0, sizeof(now.a));    for(int i = 1; i <= n; i ++) now.a[i][i] = 1;    while(k){        if(k & 1)now = cheng(now, a);        k >>= 1;        a = cheng(a, a);        }    }int main(){    int t; scanf("%d", &t); while(t --){        scanf("%d%d", &n, &k);        for(int i = 1; i <= n; i ++)            for(int j = 1; j <= n; j ++)                scanf("%d", &a.a[i][j]);        quick(k);        int sum = 0;        for(int i = 1; i <= n; i ++)        sum += now.a[i][i];cout<<sum % mod<<endl;            }  //  system("pause");    return 0;}


poj 3233

////////////////别人写的////////////////////

题目大意:给定矩阵A,求A + A^2 + A^3 + ... + A^k的结果(两个矩阵相加就是对应位置分别相加)。输出的数据mod m。k<=10^9。
  这道题两次二分,相当经典。首先我们知道,A^i可以二分求出。然后我们需要对整个题目的数据规模k进行二分。比如,当k=6时,有:
  A + A^2 + A^3 + A^4 + A^5 + A^6 =(A + A^2 + A^3) + A^3*(A + A^2 + A^3)
  应用这个式子后,规模k减小了一半。我们二分求出A^3后再递归地计算A + A^2 + A^3,即可得到原问题的答案。

      奇数: F[n]=F[n-1]+A^n        

        偶数: F[n]=F[n/2]+F[n/2]*An/2

 

          算法: 二分+矩阵快速幂

/////////////////////////////////////////////////////

很机智的题~~~~

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>int mod;using namespace std;int n, k;struct Matrix{    int a[31][31];    }now, a, tmp, ans;Matrix cheng(Matrix a, Matrix b){    memset(tmp.a, 0, sizeof(tmp.a));    for(int i = 1; i <= n; i ++)        for(int k = 1; k <= n; k ++)if(a.a[i][k])            for(int j = 1; j <= n; j ++){                tmp.a[i][j] += (a.a[i][k] * b.a[k][j]) % mod;                tmp.a[i][j] %= mod;            }    return tmp;}Matrix jia(Matrix a, Matrix b){    for(int i = 1; i <= n; i ++)        for(int j = 1; j <= n; j ++)            tmp.a[i][j] = (a.a[i][j] + b.a[i][j]) % mod;    return tmp;    }Matrix quick(Matrix a, int k){    memset(now.a, 0, sizeof(now.a));    for(int i = 1; i <= n; i ++) now.a[i][i] = 1;    while(k){        if(k & 1)now = cheng(now, a);        k >>= 1;        a = cheng(a, a);        }    return now;}Matrix work(int k){    if(k <= 1)return a;    if(k % 2)return jia(work(k - 1), quick(a, k));    Matrix bb = work(k>>1);    Matrix cc = quick(a, k>>1);    cc = cheng(cc, bb);    return jia(cc, bb);  }int main(){        scanf("%d%d%d", &n, &k, &mod);        for(int i = 1; i <= n; i ++)            for(int j = 1; j <= n; j ++)                scanf("%d", &a.a[i][j]);        ans = work(k);    for(int i = 1; i <= n; i ++){        for(int j = 1; j <= n; j ++)printf("%d ", ans.a[i][j]);cout<<endl;        }  //  system("pause");    return 0;}

剩下还有几道都要写完!

0 0