BZOJ 4162 shlw loves matrix II 拉格朗日插值+Cayley-Hamilton定理

題目大意:給定一個nn 的矩陣A ,求Ak mod 1000000007
n50,k210000

首先先介紹一下特徵值的相關內容……

對於矩陣A ,若存在常數λ 以及非零列向量x ,使得Ax=λx ,則稱λ 爲矩陣A 的一個特徵值,x 爲矩陣A 的一個特徵向量。

Ax=λx
Ax=λIx
(AλI)x=0
|AλI|=0
A11λA21An1A12A22λAn2A1nA2nAnnλ=0
A 的特徵多項式f(λ)=|AλI| 爲關於λn 次多項式,則f(λ)n 個零點即爲An 個特徵值。

如何求特徵多項式?
拉格朗日插值法,分別帶入λ=x0,x1,...,xn ,求行列式得到y0,y1,...,yn ,則f(x)=ni=0ji(xxj)(xixj)yi ,時間複雜度O(n4)

特徵多項式有啥用?
Cayley-Hamilton定理:f(A)=0
故有Ak=Ak mod f(A)
xk mod f(x) 是一個n1 次多項式,快速冪求出,然後代入矩陣A 即可。

總時間複雜度O(n4+n2logk)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 55
#define MOD 1000000007
using namespace std;

char s[10100];
int n;

int a[M][M],b[M][M],ans[M][M];
int y[M];
long long Quick_Power(long long x,int y)
{
    long long re=1;
    while(y)
    {
        if(y&1) (re*=x)%=MOD;
        (x*=x)%=MOD; y>>=1;
    }
    return re;
}
int Det(int a[M][M])
{
    int k;
    long long re=1;
    for(int i=1;i<=n;i++)
    {
        for(k=i;k<=n;k++)
            if(a[k][i])
                break;
        if(k==n+1)
            return 0;
        if(k!=i)
        {
            (re*=MOD-1)%=MOD;
            for(int j=1;j<=n;j++)
                swap(a[i][j],a[k][j]);
        }
        (re*=a[i][i])%=MOD;
        long long temp=Quick_Power(a[i][i],MOD-2);
        for(int j=1;j<=n;j++)
            a[i][j]=a[i][j]*temp%MOD;
        for(k=1;k<=n;k++)
            if(k!=i)
            {
                long long temp=(MOD-a[k][i])%MOD;
                for(int j=1;j<=n;j++)
                    (a[k][j]+=a[i][j]*temp%MOD)%=MOD;
            }
    }
    return re;
}

struct Polynomial{
    int a[M<<1];
    Polynomial(int x)
    {
        memset(a,0,sizeof a);
        a[0]=x;
    }
    int& operator [] (int x)
    {
        return a[x];
    }
    friend Polynomial operator + (Polynomial x,Polynomial y)
    {
        Polynomial z(0);
        for(int i=0;i<=n<<1;i++)
            z[i]=(x[i]+y[i])%MOD;
        return z;
    }
    friend Polynomial operator * (Polynomial x,Polynomial y)
    {
        Polynomial z(0);
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                (z[i+j]+=(long long)x[i]*y[j]%MOD)%=MOD;
        return z;
    }
    Polynomial operator * (long long x)//f(x)*a;
    {
        Polynomial re(0);
        for(int i=0;i<=n<<1;i++)
            re[i]=(a[i]*x)%MOD;
        return re;
    }
    Polynomial Times(long long x,long long y) //f(x)*(ax+b)
    {
        Polynomial re(a[0]*y%MOD);
        for(int i=1;i<=n<<1;i++)
            re[i]=(a[i-1]*x+a[i]*y)%MOD;
        return re;
    }
    friend Polynomial operator % (Polynomial a,Polynomial b) // a%b
    {
        for(int i=n;~i;i--)
        {
            long long temp=(MOD-a[i+n]*Quick_Power(b[n],MOD-2)%MOD)%MOD;
            for(int j=0;j<=n;j++)
                (a[i+j]+=b[j]*temp%MOD)%=MOD;
        }
        return a;
    }
};

int main()
{
    scanf("%s",s);
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&a[i][j]);
    for(int x=0;x<=n;x++)
    {
        memcpy(b,a,sizeof a);
        for(int i=1;i<=n;i++)
            (b[i][i]+=MOD-x)%=MOD;
        y[x]=Det(b);
    }
    Polynomial p(0);
    for(int x=0;x<=n;x++)
    {
        Polynomial temp(1);
        for(int i=0;i<=n;i++)
            if(i!=x)
            {
                temp=temp.Times(1,MOD-i);
                temp=temp*Quick_Power((x-i+MOD)%MOD,MOD-2);
            }
        temp=temp*y[x];
        p=p+temp;
    }
    Polynomial x(0);x[1]=1;
    Polynomial re(1);
    for(int i=strlen(s)-1;~i;i--)
    {
        if(s[i]=='1')
            re=re*x%p;
        x=x*x%p;
    }
    memset(b,0,sizeof b);
    for(int i=1;i<=n;i++)
        b[i][i]=1;
    for(int k=0;k<n;k++)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                (ans[i][j]+=(long long)b[i][j]*re[k]%MOD)%=MOD;
        static int c[M][M];
        memset(c,0,sizeof c);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                for(int k=1;k<=n;k++)
                    (c[i][j]+=(long long)a[i][k]*b[k][j]%MOD)%=MOD;
        memcpy(b,c,sizeof b);
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            printf("%d%c",ans[i][j],j==n?'\n':' ');
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章