【CodeChef RNG】Random Number Generator(多项式取模)

题目大意

给定数组 A 的前 K 位,和一个 K 位的数组 C 1 K 30000 ),

A i = j = 1 K A i j × C j

A N 1 N 10 18 )。

subtask 1: 1 K 3000
subtask 2: 1 K 30000

题解

本来要用 Cayley-Hamilton定理 ,奇怪的玩意儿,但我看不懂X﹏X。。。于是尝试避开这个东西来理解。

最后的结果一定是从A的前k位转移过来的,设结果:

a n s = f 1 A 1 + f 2 A 2 + f 3 A 3 + . . . + f K A K

N = 1 时:
f : 1 0 0 . . . 0

N = 2 时:
f : 0 1 0 . . . 0

相当于每次都右移1位。
直到 N = K + 1
f : C K C K 1 C K 2 . . . C 1

如果把 f 看作多项式:
f ( x ) = f 1 + f 2 x + f 3 x 2 + . . . + f K x K 1
右移操作就相当于将 f ( x ) 变为 x f ( x )
如果出现了第 x K 项,需要把它化为 x 0 ~ x K 1
x K = C K + C K 1 x + C K 2 x 2 + . . . + C 1 x K 1

p ( x ) = x K C K C K 1 x C K 2 x 2 . . . C 1 x K 1

实际上就是把多项式 f ( x )   m o d   p ( x ) ,就可以把 x K 及以后的项全部化为 x 0 ~ x K 1
因为:
f K + 1 x K 取模相当于把 f ( x ) 变为
f ( x ) f K + 1 x K + f K + 1 C K + f K + 1 C K 1 x + . . . + f K + 1 C 1 x K 1

令转移多项式 t ( x ) = x
最终结果即为 f = t N   m o d   p ;
利用多项式快速幂,多项式取模可以做到 O ( K log 2 K log 2 N )

推广

凡是第 i 项可以由前面 k 项通过常数系数得到的递推(实际上就是可以使用矩阵加速的递推),都可以转为多项式取模,若

A i = j = 1 k f j A i j

则可以通过取模
p ( x ) = x k j = 1 k f j x k j

进行递推。

代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXK=30005,MOD=104857601,ROOT=3;
typedef int Poly[MAXK*5];

int PowMod(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=(1LL*res*a)%MOD;
        a=(1LL*a*a)%MOD;
        b>>=1;
    }
    return res;
}

void NTT(Poly &a,int n,int mode)
{
    for(int i=0,j=0;i<n;i++)
    {
        if(i<j)
            swap(a[i],a[j]);
        int k=n>>1;
        while(k&&(k&j))
            j^=k,k>>=1;
        j^=k;
    }
    for(int i=1;i<n;i<<=1)
    {
        int w1=PowMod(ROOT,(MOD-1)/(i<<1)),w=1;
        if(mode==-1)
            w1=PowMod(w1,MOD-2);
        for(int j=0;j<i;j++,w=(1LL*w*w1)%MOD)
            for(int l=j,r=l+i;l<n;l+=(i<<1),r=l+i)
            {
                int temp=(1LL*a[r]*w)%MOD;
                a[r]=(a[l]-temp+MOD)%MOD;
                a[l]=(a[l]+temp)%MOD;
            }
    }
    if(mode==-1)
    {
        int inv=PowMod(n,MOD-2);
        for(int i=0;i<n;i++)
            a[i]=(1LL*a[i]*inv)%MOD;
    }
}
void Inv(Poly &a,Poly &i,int n)
{
    static Poly temp;
    if(n==1)
    {
        i[0]=PowMod(a[0],MOD-2);
        return;
    }
    Inv(a,i,(n+1)/2);
    int len=1;
    while(len<n*2-1)
        len<<=1;
    copy(a,a+n,temp);
    fill(temp+n,temp+len,0);
    NTT(temp,len,1);
    fill(i+n,i+len,0);
    NTT(i,len,1);
    for(int j=0;j<len;j++)
        i[j]=1LL*i[j]*((2LL-1LL*temp[j]*i[j]%MOD+MOD)%MOD)%MOD;
    NTT(i,len,-1);
    fill(i+n,i+len,0);
}
void Mod(Poly &a,const Poly &p,int n,int m)
{
    static Poly temp,p0,p1,c;
    copy(a,a+n,temp);
    reverse(temp,temp+n);
    copy(p,p+m,p0);
    reverse(p0,p0+m);
    Inv(p0,p1,n-m+1);
    int len=1;
    while(len<(n-m+1)*2-1)
        len<<=1;
    fill(temp+n-m+1,temp+len,0);
    NTT(temp,len,1);
    fill(p1+n-m+1,p1+len,0);
    NTT(p1,len,1);
    for(int i=0;i<len;i++)
        c[i]=(1LL*temp[i]*p1[i])%MOD;
    NTT(c,len,-1);
    fill(c+n-m+1,c+len,0);
    reverse(c,c+n-m+1);
    len=1;
    while(len<n)
        len<<=1;
    NTT(c,len,1);
    fill(p0+m,p0+len,0);
    reverse(p0,p0+m);
    NTT(p0,len,1);
    for(int i=0;i<len;i++)
        c[i]=(1LL*c[i]*p0[i])%MOD;
    NTT(c,len,-1);
    for(int i=0;i<n;i++)
        a[i]=(a[i]-c[i]+MOD)%MOD;
}
void MulMod(Poly &a,const Poly &b,const Poly &p,int n)
{
    static Poly temp;
    copy(b,b+n,temp);
    int len=1;
    while(len<n*2)
        len<<=1;
    fill(a+n,a+len,0);
    fill(temp+n,temp+len,0);
    NTT(a,len,1);
    NTT(temp,len,1);
    for(int i=0;i<len;i++)
        a[i]=(1LL*a[i]*temp[i])%MOD;
    NTT(a,len,-1);
    Mod(a,p,n*2-1,n);
}
void PowMod(Poly &res,Poly &a,long long b,const Poly &p,int n)
{
    fill(res,res+n,0);
    res[0]=1;
    while(b)
    {
        if(b&1LL)
            MulMod(res,a,p,n);
        MulMod(a,a,p,n);
        b>>=1LL;
    }
}

Poly A,C,p,t,f;
int main()
{
    long long N;
    int K;
    scanf("%d%lld",&K,&N);
    for(int i=0;i<K;i++)
        scanf("%d",&A[i]);
    for(int i=0;i<K;i++)
        scanf("%d",&C[i]);

    p[K]=1;
    for(int i=0;i<K;i++)
        p[i]=(MOD-C[K-i-1])%MOD;
    t[1]=1;
    PowMod(f,t,N-1,p,K+1);

    int ans=0;
    for(int i=0;i<K;i++)
        ans=(ans+(1LL*A[i]*f[i])%MOD)%MOD;
    printf("%d\n",ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/can919/article/details/79809221