loj6017/bzoj4161 线性齐次递推多项式取模优化

版权声明:这篇文章的作者是个蒟蒻,没有转载价值,如果要转说一下好了 https://blog.csdn.net/litble/article/details/81783267

显然强大的Rayment已经讲得很清楚了:这里
因为这东西我可能明天就忘了,所以写一下。
大概就是构造一个多项式 g ( x ) = x k i = 1 k a i x k i a 是美丽的转移系数)。对于线性齐次递推的转移矩阵 A ,设有 A n k + 1 = g ( A ) p ( A ) + r ( A ) ,又由于 g ( A ) = 0 所以 A n k + 1 = r ( A )
然后用类似快速幂的方法搞这个东西,得到多项式 r 的系数。
那么有 A n k + 1 = i = 0 k 1 r i A i ,两边同时乘初始向量 H k 1 (下标代表该向量代表的每一项里最大项是 h k 1 )得到: H n = i = 0 k 1 r i H i + k 1 ,即 h n = i = 0 k 1 r i h i + k 1
然后多项式乘法和取模都暴力搞即可。多项式取模的暴力搞就是竖式除法,由于 g 的最高次项为1,所以这个竖式除法还是很好写的。

#include<bits/stdc++.h>
using namespace std;
#define RI register int
const int N=4005,mod=1000000007;
int a[N],h[N],r[N],ans[N],g[N],c[N];
int n,K,res;
int qm(int x) {return x>=mod?x-mod:x;}
void mul(int *a,int *b) {
    for(RI i=0;i<=2*K-2;++i) c[i]=0;
    for(RI i=0;i<K;++i)
        for(RI j=0;j<K;++j)
            c[i+j]=qm(c[i+j]+1LL*a[i]*b[j]%mod);
    for(RI i=2*K-2;i>=K;--i)
        for(RI j=K-1;j>=0;--j)
            c[i-K+j]=qm(c[i-K+j]-1LL*c[i]*g[j]%mod+mod);
            //直接乘以c[i]是因为g的最高次项系数为1
    for(RI i=0;i<K;++i) a[i]=c[i];
}
int main()
{
    scanf("%d%d",&n,&K);
    for(RI i=1;i<=K;++i) scanf("%d",&a[i]),a[i]=qm(a[i]+mod);
    for(RI i=0;i<K;++i) scanf("%d",&h[i]),h[i]=qm(h[i]+mod);
    g[K]=1;for(RI i=1;i<=K;++i) g[K-i]=mod-a[i];
    for(RI i=K;i<=2*K-1;++i)
        for(RI j=1;j<=K;++j) h[i]=qm(h[i]+1LL*h[i-j]*a[j]%mod);
    if(n<=2*K-1) {printf("%d\n",h[n]);return 0;}
    r[1]=ans[0]=1;
    for(RI i=n-K+1;i;i>>=1,mul(r,r)) if(i&1) mul(ans,r);
    for(RI i=0;i<K;++i) res=qm(res+1LL*ans[i]*h[K-1+i]%mod);
    printf("%d\n",res);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/litble/article/details/81783267