矩阵快速幂。poj3070 3233 3735 3150

矩阵快速幂解题技巧
本文介绍了使用矩阵快速幂解决三道经典问题的方法:求斐波那契数列的第N项、猫的花生数量变化及多项式求和。通过具体实例展示了如何构造矩阵、进行矩阵乘法和快速幂运算。
poj 3070;
这是弱的第一道矩阵快速幂,然后试试手,总之还是裸模板。但还是蛮难的
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int mod=10000;
ll n;
struct Matrix
{
    ll ma[2][2];
    Matrix()
    {
        for(int i=0;i<2;i++)
         for(int j=0;j<2;j++)
            ma[i][j]=0;
    }
};

Matrix mult(Matrix a, Matrix b)
{
    Matrix c;
    for(int i=0;i<2;i++)
    {
      for(int j=0;j<2;j++)
      {
          for(int k=0;k<2;k++)
          {
              c.ma[i][j]=(c.ma[i][j]+a.ma[i][k]*b.ma[k][j]%mod)%mod;
          }
      }
    }
    return c;
}

Matrix pow(Matrix a,ll b)
{
    Matrix temp;
    for(int i=0;i<2;i++) temp.ma[i][i]=1;
    while(b)
    {
        if(b&1) temp=mult(temp,a);
        a=mult(a,a);
        b>>=1;
    }
    return temp;
}
int main()
{
    while(scanf("%I64d",&n)!=EOF)
    {
        if(n==-1) break;
        else if(n==0) {printf("0\n"); continue;}
        Matrix a,b;
        a.ma[0][0]=1;
        a.ma[0][1]=1;
        a.ma[1][0]=1;
        b=pow(a,n);
        printf("%I64d\n",b.ma[0][1]%mod);
    }
    return 0;
}

poj  3725.
将每只猫的花生数放在一个1*n的矩阵中,考虑用k次操作构造成一个n*n矩阵A,因为三种操作中存在某种猫的花生数加一的操作,所以要把矩阵扩展一位放1,即[1,cnt1,cnt2,…,cntn],初始化矩阵A为单位矩阵,对于操作1,要把A[0][x]++;对于操作2,要令A[i][x]=0;对于操作3,要swap(A[i][x],A[i][y]),构造出A矩阵之后用矩阵快速幂求出A^m后第一行元素即为操作后每只猫的花生数. 但是弱还是不太会。看了题解,感觉这类题还是蛮神奇的。
#include <iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
ll n,m,k;
struct Matrix
{
    ll ma[120][120];
    Matrix()
    {
        for(int i=0;i<120;i++)
        {
            for(int j=0;j<120;j++)
            {
                ma[i][j]=0;
            }
        }
    }
} ;

Matrix mult(Matrix a, Matrix b)
{
    Matrix c;
    for(int i=0;i<=n;i++)// 行
    {
        for(int j=0;j<=n;j++)
        {
           if(b.ma[i][j])
           {
               for(int k=0;k<=n;k++)
               {
                   c.ma[i][k]=(c.ma[i][k]+a.ma[i][j]*b.ma[j][k]);
               }
           }
        }
    }
    return c;
}

Matrix pow(Matrix a,ll b)
{
   if(b==1) return a;
   Matrix ans;
   for(int  i=0;i<=n;i++) ans.ma[i][i]=1;
   while(b)
   {
       if(b & 1) ans=mult(ans,a);
       b>>=1;
       a=mult(a,a);
   }
   return ans;
}
int main()
{
    while(scanf("%I64d%I64d%I64d",&n,&m,&k)!=EOF)
    {
        if(n==0&&m==0&&k==0) break;
        Matrix x,y;
        for(int i=0;i<=n;i++) x.ma[i][i]=1;
        while(k--)
        {
            char s[5];
            scanf("%s",s);
            if(s[0]=='g')
            {
                int t;
                scanf("%d",&t);
                x.ma[0][t]++;
            }
            else if(s[0]=='e')
            {
                int  t;
                scanf("%d",&t);
                for(int i=0;i<=n;i++)
                    x.ma[i][t]=0;
            }
            else
            {
                int p,q;
                scanf("%d%d",&p,&q);
                for(int i=0;i<=n;i++)
                {
                    swap(x.ma[i][p],x.ma[i][q]);
                }
            }
        }
        y=pow(x,m);
        for(int i=1;i<n+1;i++)
        {
            printf("%I64d",y.ma[0][i]);
            if(i==n) printf("\n");
            else printf(" ");
        }
    }
    return 0;
}

poj 3233.很牛逼的一道题,就看了一眼题解。神马二分。。。弱完全没想到最后的方法。
a^1+a^2+a^3+a^4+a^5=(a^1+a^2+a^3+a^4)+a^5
(a^1+a^2+a^3+a^4)=(a^1+a^2+a^2(a^1+a^2))=(a^1+a^2)*(1+a^2)
(a^1+a^2)=a^1(1+a^1)

如果k为偶数,那么(A+A^2+....A^K) = (A+...+A^K/2)+A^K/2*(A+...+A^K/2)

如果k为奇数,那么(A+A^2+....A^K) = (A+...+A^K/2)+A^K/2*(A+...+A^K/2)+A^k

讨论奇偶性
式子不会放大。。。
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
ll n,k,m;
struct Matix
{
    ll ma[31][31];
    Matix()
    {
        for(int i=0;i<31;i++)
        {
            for(int j=0;j<31;j++)
            {
                ma[i][j]=0;
            }
        }
    }
};
Matix p,q,ans;
Matix mult(Matix a,Matix b)
{
    Matix c;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
           {
               for(int k=0;k<n;k++)
               {
                   c.ma[i][j]=(c.ma[i][j]+a.ma[i][k]*b.ma[k][j])%m;
               }
           }
    }
    return c;
}
Matix sum(Matix a,Matix b)
{
    Matix c;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            c.ma[i][j]=(a.ma[i][j]+b.ma[i][j])%m;
        }
    }
    return c;
}

Matix pow(Matix a,ll b)
{
    Matix ans;
    for(int i=0;i<n;i++) ans.ma[i][i]=1;
    while(b)
    {
        if(b&1) ans=mult(ans,a);
        a=mult(a,a);
        b>>=1;
    }
    return ans;
}
Matix solve(Matix m,ll k)
{
    if(k==1) return m;
    else if(k%2) return m=sum(solve(m,k-1),pow(m,k));
    else return mult(solve(m,k/2),sum(p,pow(m,k/2)));
}
int main()
{
    scanf("%I64d%I64d%I64d",&n,&k,&m);
    for(int i=0;i<n;i++) p.ma[i][i]=1;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            scanf("%I64d",&q.ma[i][j]);
        }
    }
    ans=solve(q,k);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            printf("%I64d",ans.ma[i][j]);
            if(j==n-1) printf("\n");
            else printf(" ");
        }
    }
    return 0;
}









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值