zoukankan      html  css  js  c++  java
  • 【POJ2118】Firepersons-递推+矩阵乘法

    测试地址:Firepersons
    题目大意:求解常系数线性递推关系:an=i=1kanibi的第i项(ai),其中a0,...,ak1b1,...,bk已给出。
    做法:本题需要用到递推+矩阵乘法。
    这题i109,k100,很容易想到用矩阵乘法做到O(k3logi)的复杂度,那么这题就做完了。
    ……但是有没有更好的做法呢?
    令转移矩阵为M,我们最后要求的是Mik+1X(其中X为列向量,从下往上排列着a0,...,ak1)。根据一些奇妙的线性代数结论,由特征多项式以及一些奇妙定理可以得到:
    对于i0,有Mi+k=j=1kbjMi+kj
    有了这个东西,有什么用呢?我们可以得到一个重要的结论:所有Mi都可以表示成M0,...,Mk1的线性组合。这个可以用数学归纳法简单证明。
    于是我们在原先矩阵快速幂的基础上,将两个M的幂乘起来的过程原先是需要O(k3)的,但现在我们只需要做一个多项式乘法即可,时间复杂度为O(k2)。但这样得出来的是M0,...,M2k2的线性组合,那么只要用上面那个结论把高于k1次的项往下规约即可,也是O(k2)的,因此整个算法的时间复杂度为O(k2logi),可以做到k=2000左右的水平。
    据说用FFT优化多项式乘法等可以优化到O(klogklogi)……有待学习。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=10000;
    int k;
    ll a[210],b[110],n;
    ll tmp[210],s[110],ss[110];
    
    void mult(ll *A,ll *B,ll *C)
    {
        memset(tmp,0,sizeof(tmp));
        for(int i=0;i<k;i++)
            for(int j=0;j<k;j++)
                tmp[i+j]=(tmp[i+j]+A[i]*B[j])%mod;
        for(int i=2*k-2;i>=k;i--)
        {
            for(int j=1;j<=k;j++)
                tmp[i-j]=(tmp[i-j]+tmp[i]*b[j])%mod;
        }
        for(int i=0;i<k;i++)
            C[i]=tmp[i];
    }
    
    void solve(ll n)
    {
        int nowx=1;
        memset(s,0,sizeof(s));
        s[0]=1;
        memset(ss,0,sizeof(ss));
        if (k>1) ss[1]=1;
        else ss[0]=b[1];
    
        n=n-k+1;
        while(n)
        {
            if (n&1) mult(s,ss,s);
            n>>=1;nowx<<=1; 
            if (nowx<k)
            {
                for(int i=0;i<k;i++)
                    ss[i]=(i==nowx);
            }
            else mult(ss,ss,ss);
        }
    
        for(int i=k;i<=2*k-2;i++)
        {
            a[i]=0;
            for(int j=1;j<=k;j++)
                a[i]=(a[i]+a[i-j]*b[j])%mod;
        }
        ll ans=0;
        for(int i=0;i<k;i++)
            ans=(ans+a[i+k-1]*s[i])%mod;
        printf("%lld
    ",ans);
    }
    
    int main()
    {
        while(scanf("%d",&k)&&k)
        {
            for(int i=0;i<k;i++)
                scanf("%lld",&a[i]);
            for(int i=1;i<=k;i++)
                scanf("%lld",&b[i]);
            scanf("%lld",&n);
    
            if (n<k) printf("%lld
    ",a[n]);
            else solve(n);
        }
    
        return 0;
    }
  • 相关阅读:
    我的java学习之路--Reflect专题
    jQuery——动态给表格添加序号
    jQuery操作表格(table)的常用方法、技巧汇总
    Jquery如何删除table里面checkbox选中的多个行
    Mybatis问题:There is no getter for property named 'unitId' in 'class java.lang.String'
    jquery 遍历表格,需要表格中每个td的内容
    用jquery怎么删除<table>的一行
    xml报错 Parse Fatal Error :在实体引用中,实体名称必须紧跟在'&'后面
    mybatis做like模糊查询
    javascript eval和JSON之间的联系
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793301.html
Copyright © 2011-2022 走看看