zoukankan      html  css  js  c++  java
  • [bzoj4162]shlw loves matrix II

    来自FallDream的博客,未经允许,请勿转载,谢谢


    给定矩阵k*k的矩阵M,请计算 M^n,并将其中每一个元素对 1000000007 取模输出。 k<=50 n<=2^10000

    考虑求出矩阵的特征多项式,这点我们可以通过带入$lambda=x0..xk$,求出矩阵的行列式,然后通过插值求出多项式。

    然后搬出一个很厉害的定理:f(A)=0 其中f(x)是特征多项式,A是矩阵,所以我们可以把所求的$x^{n}$对f(x)取膜,从而让答案变成一个k-1次多项式。然后我们把原矩阵带进去就行了。

    插值的复杂度是$O(n^{4})$,然后后面那部分的复杂度是$k^{2}logn$ 

    然后做了这道题好像懂了怎么在O(klogklogn)内做完"常系数线性递推",貌似还要nlogn的多项式取余 真麻烦TAT

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define mod 1000000007
    using namespace std;
    inline int read()
    {
        int x = 0; char ch = getchar();
        while(ch < '0' || ch > '9')ch = getchar();
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x;
    }
    
    char st[10001];
    int y[51],k;
    
    int pow(int x,int k)
    {
        int sum=1;
        for(;k;k>>=1,x=1LL*x*x%mod)
            if(k&1) sum=1LL*sum*x%mod;
        return sum;
    }
    struct Matrix
    {
        int s[51][51];
        Matrix operator*(Matrix b)
        {
            Matrix c;memset(c.s,0,sizeof(c.s));
            for(int i=1;i<=k;i++)
                for(int l=1;l<=k;l++) if(s[i][l])
                    for(int j=1;j<=k;j++)
                        c.s[i][j]=(c.s[i][j]+1LL*s[i][l]*b.s[l][j])%mod;
            return c;
        }
        int calc()
        {
            int sum=1,j;
            for(int i=1;i<=k;i++)
            {
                for(j=i;j<=k;j++)
                    if(s[j][i])
                    {
                        if(j!=i)
                        {
                            sum=mod-sum;
                            for(int l=1;l<=k;l++)
                                swap(s[j][l],s[i][l]);
                        }
                        break;
                    }
                if(j==k+1) return 0;
                for(int j=i+1;j<=k;j++)
                {
                    int inv=1LL*pow(s[i][i],mod-2)*s[j][i]%mod;
                    for(int l=i;l<=k;l++)
                        s[j][l]=(1LL*s[i][l]*inv%mod-s[j][l]+mod)%mod;
                }
            }
            for(int i=1;i<=k;i++) sum=1LL*sum*s[i][i]%mod;
            return sum;
        }
    }a,b,ans;
    
    struct poly
    {
        int s[101];
        poly(int x=0){memset(s,0,sizeof(s));s[0]=x;}
        poly operator^(int x)
        {
            poly c;
            for(int i=k<<1;i;i--)
                c.s[i]=(s[i-1]+1LL*x*s[i])%mod;
            c.s[0]=(1LL*s[0]*x)%mod;
            return c;
        }
        poly operator*(int x)
        {
            poly c(0);
            for(int i=0;i<=k<<1;i++)
                c.s[i]=1LL*s[i]*x%mod;
            return c;
        }
        poly operator+(poly b)
        {
            poly c(0);
            for(int i=0;i<=k<<1;i++)
                c.s[i]=(s[i]+b.s[i])%mod;
            return c;
        }
        poly operator*(poly b)
        {
            poly c(0);
            for(int i=0;i<=k;i++)
                for(int j=0;j<=k;j++)
                    c.s[i+j]=(c.s[i+j]+1LL*s[i]*b.s[j])%mod;
            return c;
        }
        friend poly operator%(poly a,poly b)
        {
            for(int i=k;i>=0;i--)
            {
                int t=1LL*a.s[i+k]*pow(b.s[k],mod-2)%mod;
                for(int j=0;j<=k;j++)
                    a.s[i+j]=(a.s[i+j]-1LL*b.s[j]*t%mod+mod)%mod;
            }
            return a;
        }
    }F(0),Ans(1);
    
    int main()
    {
        scanf("%s",st+1);k=read();
        for(register int i=1;i<=k;i++)
            for(register int j=1;j<=k;j++)
                b.s[i][j]=a.s[i][j]=read();
        for(register int t=0;t<=k;t++)
        {
            memcpy(b.s,a.s,sizeof(b.s));
            for(int i=1;i<=k;i++)
                b.s[i][i]=(b.s[i][i]-t+mod)%mod;
            y[t]=b.calc();
        }
        for(register int t=0;t<=k;t++)
        {
            poly tmp(1);
            for(register int i=0;i<=k;i++) if(i!=t)
                tmp=tmp^(mod-i),tmp=tmp*pow((t-i+mod)%mod,mod-2);
            tmp=tmp*y[t];F=F+tmp;
        }
        poly x(0);x.s[1]=1;
        for(int i=strlen(st+1);i;i--)
        {
            if(st[i]=='1') Ans=Ans*x%F;
            x=x*x%F;
        }
        memset(b.s,0,sizeof(b.s));
        for(int i=1;i<=k;i++) b.s[i][i]=1;
        for(int t=0;t<k;t++,b=a*b)
            for(int i=1;i<=k;i++)
                for(int j=1;j<=k;j++)
                    ans.s[i][j]=(ans.s[i][j]+1LL*Ans.s[t]*b.s[i][j])%mod;
        for(register int i=1;i<=k;i++)
            for(register int j=1;j<=k;j++)
                printf("%d%c",ans.s[i][j],j!=k?' ':'
    ');
        return 0;
    } 
  • 相关阅读:
    固定思维的可怕(转)
    Javascript模块化编程:require.js的用法
    js中将字符串转为JSON的三种方式
    cf 55D 数位dp 好题
    fzu 2113 数位dp
    uestc 250 数位dp(水)
    hdu 3652数位dp
    数位dp 3943 二分法
    hdu 3943 经典数位dp好题
    hdu 4871 树的分治+最短路记录路径
  • 原文地址:https://www.cnblogs.com/FallDream/p/bzoj4162.html
Copyright © 2011-2022 走看看