矩阵经典操作(4)

这是关于斐波拉切的经典操作

POJ3070

这是关于斐波拉切数列用矩阵表示的最基本的题,正如题目描述的那样,f[i]=A^i.a[0][1],在这儿A为固定矩阵

       |   1     1 |

A = |              |

      |    1     0 |

#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<climits>
#define maxn 10000
#define mod 10000
using namespace std;

struct matrix
{
    int a[2][2];
    void clear()
    {
        memset(a,0,sizeof(a));
    }

    void init()
    {
        a[0][0]=1;
        a[0][1]=1;
        a[1][0]=1;
        a[1][1]=0;
    }

    matrix operator +(const matrix &b)const
    {
        matrix c;
        c.clear();
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
            {
                c.a[i][j]=a[i][j]+b.a[i][j];
            }
        }
        return c;
    }

    matrix operator *(const matrix b)const
    {
        matrix c;
        c.clear();
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
            {
                for(int k=0; k<2; k++)
                {
                    c.a[i][j]+=a[i][k]*b.a[k][j];
                }
                c.a[i][j]=c.a[i][j]%mod;
            }
        }
        return c;
    }
};

matrix pow(matrix a,int b)
{
    matrix per;
    per.init();
    while(b)
    {
        if(b&1)
        {
            per=per*a;
        }
        a=a*a;
        b>>=1;
    }
    return per;
}


int main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
    int n;
    matrix a,ans;
    a.init();
    while(cin>>n)
    {
        if(n==-1)break;
        if(n==0){puts("0");continue;}
        else
        {
            ans=pow(a,n-1);
            cout<<(ans.a[0][1])%mod<<endl;
        }
    }
    return 0;
}

HDU3306

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

题意:Fibonacci : A(0) = 1 , A(1) = 1 , A(N) = X * A(N - 1) + Y * A(N - 2) (N >= 2).
计算A(0)^2+……A(N)^2

思路:构造矩阵  矩阵如下
|1 x^2 y^2 2xy|   |  S(N-1)    |   |  S(N)    |
|0 x^2 y^2 2xy| * |  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)|
*************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define mod 10007
using namespace std;

int t,x,y;
struct matrix
{
    int n,m;
    int a[5][5];

    void clear()
    {
        m=n=0;
        memset(a,0,sizeof(a));
    }

    matrix operator +(const matrix &b)const
    {
        matrix c;
        c.clear();
        c.n=n,c.m=m;

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

    matrix operator *(const matrix &b)const
    {
        matrix c;
        c.clear();
        c.n=n,c.m=b.m;

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

matrix pow(matrix a,int b)
{
    matrix ans;
    ans.clear();
    ans.n=ans.m=a.n;
    for(int i=0; i<a.n; i++)
    {
        ans.a[i][i]=1;
    }

    while(b)
    {
        if(b&1)
        {
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}

matrix a,b;
__int64 ans;
int main()
{
    while(~scanf("%d%d%d",&t,&x,&y))
    {
        x%=mod,y%=mod;
        if(t==0||t==1)
        {
            printf("1\n");
            continue;
        }
        a.clear();
        a.n=a.m=4;
        a.a[0][0]=a.a[2][1]=1;
        a.a[0][1]=a.a[1][1]=x*x%mod;
        a.a[0][2]=a.a[1][2]=y*y%mod;
        a.a[0][3]=a.a[1][3]=2*x*y%mod;
        a.a[3][1]=x;
        a.a[3][3]=y;

        b.clear();
        b.n=4,b.m=1;
        b.a[0][0]=2;
        b.a[1][0]=1;
        b.a[2][0]=1;
        b.a[3][0]=1;

        a=pow(a,t-1);
        a=a*b;
        ans=0;
        for(int i=0;i<4;i++)
        {
            ans+=a.a[0][i];
        }
        printf("%d\n",ans%mod);
    }
    return 0;
}
HDU4549

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

题意:
F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )计算F[n]%1000000007

思路:矩阵构造+欧拉函数+整数快速幂+矩阵快速幂
通过对表达式的求解可以得到F[]的最终形式是对ab的斐波拉切数的乘积,
即F[i]=a^f[i-1]*b^f[i]
在这儿f[]表示最基本的菲波拉契数列,而关于菲波拉契数可以通过矩阵构造得到
此后可以通过整数快速幂来求解答案,只是注意矩阵乘法会溢出,即使%mod也会,因此要用到欧拉函数来优化
在欧拉函数中有这么一个定理

A^B%C=A^(B%phi(C)+phi(C))%C    B>=phi(C)
在这儿phi表示欧拉函数,而mod为素数,因此phi(C)=mod-1

这题贡献了无数次WA---主要数关于mod的问题

*************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define mod 1000000007
using namespace std;

__int64 x,y,t;
struct matrix
{
    int n,m;
    __int64 a[5][5];

    void clear()
    {
        m=n=0;
        memset(a,0,sizeof(a));
    }

    matrix operator +(const matrix &b)const
    {
        matrix c;
        c.clear();
        c.n=n,c.m=m;

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

    matrix operator *(const matrix &b)const
    {
        matrix c;
        c.clear();
        c.n=n,c.m=b.m;

        for(int i=0; i<n; i++)
        {
            for(int j=0; j<b.m; j++)
            {
                for(int k=0; k<m; k++)
                {
                    c.a[i][j]+=a[i][k]*b.a[k][j];
                }
                c.a[i][j]%=(mod-1);
            }
        }
        return c;
    }
};
matrix mpow(matrix a,__int64 b)
{
    matrix ans;
    ans.clear();
    ans.n=ans.m=a.n;
    for(int i=0; i<a.n; i++)
    {
        ans.a[i][i]=1;
    }

    while(b)
    {
        if(b&1)
        {
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}

__int64 pow(__int64 a,__int64 b)
{
    __int64 ans=1;
    a=a%mod;
    while(b)
    {
        if(b&1)
        {
            ans=ans*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

void print(matrix a)
{
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            cout<<a.a[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<"-----"<<endl;
}

matrix a;
__int64 ans;
__int64 t1,t2;
int main()
{
    while(~scanf("%I64d%I64d%I64d",&x,&y,&t))
    {
        if(t==0)
        {
            printf("%I64d\n",x);
            continue;
        }
        else if(t==1)
        {
            printf("%I64d\n",y);
            continue;
        }
        else
        {
            a.clear();
            a.n=a.m=2;
            a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
            a.a[1][1]=0;
            a=mpow(a,t);
            //print(a);

            t1=a.a[1][1];
            t2=a.a[0][1];
            ans=0;
            ans=(pow(x,t1)*pow(y,t2))%mod;
            printf("%I64d\n",ans);
        }
    }
    return 0;
}

HDU3936
/************************
http://acm.hdu.edu.cn/showproblem.php?pid=3936

题意:设定p[i]=f[i*4-1],给定一个区间,球在这个区间的p[i]的总和

思路:p[1] + p[2] + ... + p[n] = f[1]^2 + f[2]^2 + ... + f[2*n-1]^2 + f[2*n]^2 = f[2*n] * f[2*n+1]
这个题目比较蛋疼,谁会知道这么多的公式啊 ,不过知道这个公式后就简单了 

Fibonacci数列通项公式∴F(n)=(1/√5)*{[(1+√5)/2]^(n+1) - [(1-√5)/2]^(n+1)}
性质:
  1.f(0)+f(1)+f(2)+…+f(n)=f(n+2)-1。 
  2.f(1)+f(3)+f(5)+…+f(2n-1)=f(2n)。 
  3.f(2)+f(4)+f(6)+…+f(2n) =f(2n+1)-1。 
  4.[f(0)]^2+[f(1)]^2+…+[f(n)]^2=f(n)·f(n+1)。 
  5.f(0)-f(1)+f(2)-…+(-1)^n·f(n)=(-1)^n·[f(n+1)-f(n)]+1。 
  6.f(m+n-1)=f(m-1)·f(n-1)+f(m)·f(n)。 
        利用这一点,可以用程序编出时间复杂度仅为O(log n)的程序。 
  7.[f(n)]^2=(-1)^(n-1)+f(n-1)·f(n+1)。 
  8.f(2n-1)=[f(n)]^2-[f(n-2)]^2。 
  9.3f(n)=f(n+2)+f(n-2)。 
  10.f(2n-2m-2)[f(2n)+f(2n+2)]=f(2m+2)+f(4n-2m) [ n〉m≥-1,且n≥1] 
    11.f(2n+1)=[f(n)]^2+[f(n+1)]^2.
斐波那契数列的整除性与素数生成性
  每3个数有且只有一个被2整除, 
  每4个数有且只有一个被3整除, 
  每5个数有且只有一个被5整除, 
  每6个数有且只有一个被8整除, 
  每7个数有且只有一个被13整除, 
  每8个数有且只有一个被21整除, 
  每9个数有且只有一个被34整除
************************/

#include<iostream>
#include<cstring>
#include<cstdio>
#define mod 1000000007
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

struct matrix
{
    int n,m;
    __int64 a[5][5];

    void clear()
    {
        memset(a,0,sizeof(a));
    }

    matrix operator +(const matrix &b)const
    {
        matrix c;
        c.clear();
        c.n=n,c.m=m;

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

    matrix operator *(const matrix &b)const
    {
        matrix c;
        c.clear();
        c.n=n,c.m=b.m;

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

matrix pow(matrix a,__int64 b)
{
    matrix ans;
    ans.clear();
    ans.n=ans.m=a.n;
    for(int i=0; i<a.n; i++)
    {
        ans.a[i][i]=1;
    }

    while(b)
    {
        if(b&1)
        {
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}

int t;
__int64 l,r;
matrix a;
__int64 ans1,ans2;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d",&l,&r);
        a.clear();
        a.n=a.m=2;
        a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
        a.a[1][1]=0;
        
        ans1=(pow(a,2*r).a[0][1]*pow(a,2*r+1).a[0][1])%mod;
        ans2=(pow(a,2*l-2).a[0][1]*pow(a,2*l-1).a[0][1])%mod;
        printf("%I64d\n",(ans1-ans2+mod)%mod);
    }
    return 0;
}

HDU1568

这不是矩阵的题目,但是是斐波拉契的题目,在这儿列出主要原因是因为它和HDU3177有相似点,都是取菲波拉契数的前几位或者后几位,对候几位数,直接可以取模运算,对于前几位就回归到斐波拉切的本质上来 ,通过位数公式就可以求得

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define  mod 10000
using namespace std;

__int64 fib[50];
__int64 solve(__int64 n)
{
    double ans = -0.5 * log10(5.0) + n * log10((sqrt(5.0) + 1) / 2);
    __int64 d = (__int64)ans;
    ans -= d;
    ans = pow(10.0, ans);
    while(ans < 1000)
        ans *= 10;
    return (__int64)ans;
}

int main()
{
    freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
    int n;
    fib[0]=0;
    fib[1]=1;
    for(int i=2; i<40; i++)
    {
        fib[i]=fib[i-1]+fib[i-2];
    }
    while(~scanf("%I64d",&n))
    {
        if(n<=20)
        {
            cout<<fib[n]<<endl;
            continue;
        }
        printf("%I64d\n",solve(n));

    }
    return 0;
}

HDU3177

/************************
G++交
************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define  mod 10000
using namespace std;


__int64 fib[50];

struct matrix
{
    __int64 a[2][2];

    void clear()
    {
        memset(a,0,sizeof(a));
    }

    matrix operator +(const matrix &b)const
    {
        matrix c;
        c.clear();
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
            {
                c.a[i][j]=(a[i][j]+b.a[i][j])%mod;
            }
        }
        return c;
    }

    matrix operator *(const matrix &b)const
    {
        matrix c;
        c.clear();
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
            {
                for(int k=0; k<2; k++)
                {
                    c.a[i][j]+=a[i][k]*b.a[k][j];
                }
                c.a[i][j]%=mod;
            }
        }
        return c;
    }
};

matrix power(matrix a,int b)
{
    matrix ans;
    for(int i=0; i<2; i++)
    {
        for(int j=0; j<2; j++)
        {
            ans.a[i][j]=(i==j);
        }
    }

    while(b)
    {
        if(b&1)
            ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}

__int64 solve(__int64 n)
{
    double ans = -0.5 * log10(5.0) + n * log10((sqrt(5.0) + 1) / 2);
    __int64 d = (__int64)ans;
    ans -= d;
    ans = pow(10.0, ans);
    while(ans < 1000)
        ans *= 10;
    return (__int64)ans;
}

int main()
{
   // freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
    int n;
    fib[0]=0;
    fib[1]=1;
    for(int i=2; i<40; i++)
    {
        fib[i]=fib[i-1]+fib[i-2];
    }
    while(~scanf("%I64d",&n))
    {
        if(n<40)
        {
            cout<<fib[n]<<endl;
            continue;
        }
        else
        {
            printf("%I64d...",solve(n));
            matrix a,b;
            a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
            a.a[1][1]=0;
            b=power(a,n);
            printf("%04d\n",b.a[0][1]%mod);
        }
    }
    return 0;
}

 

这是关于求位数的公式,在具体实现上面可以参考这个博客它里面讲解的比较好:http://hi.baidu.com/aekdycoin/item/a4407c37850e5b9db80c03a6

HDU1588

这个题目比较有意思,对于g(i)=k*i+b,,那么在【0,n-1】之内求f(g(i)),有前面这些题目的铺垫可知:f(i)=A^i,那么就有sum=f(g(0))+……f(g(n-1))

展开就有sum=f(b)+f(k+b)+……f((n-1)*k+b)

                        =A^b+A^(k+b)……A^((n-1)*k+b)

                        =A^b(A^0+A^k+A^2k+……A^((n-1)*k))  在这儿就是把A^b提取公因数,记做AA

                        =A^b((A^0+(A^k)+(A^k)^2+……(A^k)^n-1)    把A^k作为一个公因式再提出来,记做K

                        =AA*(A^0+K^1+K^2+……K^(n-1))

这样就比较容易做出来了  只是要注意还有一个A^0要加上去

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

__int64 mod;

struct matrix
{
    __int64 a[2][2];

    void init()
    {
        a[0][0]=a[1][1]=1;
        a[0][1]=a[1][0]=0;
    }

    void clear()
    {
        memset(a,0,sizeof(a));
    }

    matrix operator +(const matrix &b)const
    {
        matrix c;
        c.clear();
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
            {
                c.a[i][j]=(a[i][j]+b.a[i][j])%mod;
            }
        }
        return c;
    }

    matrix operator *(const matrix &b)const
    {
        matrix c;
        c.clear();
        for(int i=0; i<2; i++)
        {
            for(int j=0; j<2; j++)
            {
                for(int k=0; k<2; k++)
                {
                    c.a[i][j]+=(a[i][k]*b.a[k][j]);
                }
                c.a[i][j]=c.a[i][j]%mod;
            }
        }
        return c;
    }
};

matrix pow(matrix a,int b)
{
    matrix ans;
    ans.init();
    while(b)
    {
        if(b&1)
        {
            ans=ans*a;
        }
        a=a*a;
        b>>=1;
    }
    return ans;
}

matrix pow_sum(matrix a,int k)
{
    matrix ans,temp;
    if(k==1)return a;
    temp=pow_sum(a,k>>1);
    ans=temp+temp*pow(a,k>>1);
    if(k&1)
    {
        ans=ans+pow(a,k);
    }
    return ans;
}

__int64 k,b,n;
int main()
{
    //freopen("C:\\Users\\Administrator\\Desktop\\in.txt" , "r" , stdin);
   // freopen("C:\\Users\\Administrator\\Desktop\\out.txt" , "w" , stdout);
    matrix a,e,ab,ak,sum,ans;
    while(~scanf("%I64d%I64d%I64d%I64d",&k,&b,&n,&mod))
    {
        a.a[0][0]=a.a[0][1]=a.a[1][0]=1;
        a.a[1][1]=0;
        e.init();
        ab=pow(a,b);
        ak=pow(a,k);
        sum=pow_sum(ak,n-1)+e;
        ans=ab*sum;
        printf("%d\n",ans.a[0][1]%mod);
    }
    return 0;
}




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值