矩陣經典操作(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;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章