【JZOJ 5395】【NOIP2017提高A组模拟10.6】Count

Descrption

这里写图片描述

Solution

Ans=i=lrik

也就是求出 Ans=ni=1ik 即可,

这个Ans肯定可以表示成一个k+1的多项式,

——(以下为证明,大佬跳过)——-
设多项式 L(x)=ni=1ik
那么, L(x+1)=(x+1)k+L(x)
我们发现,只有当L为k+1的多项式时,才可以化简出一个 (x+1)k
——(好辣鸡的证明啊~)——

那么用拉格朗日插值法即可直接做,预处理前k+2个数,在最后的式子你会发现其只是一堆连续的数求积,直接预处理即可,

复杂度: O(m)

Code

#include 
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=1000010,mo=998244353;
int m,n,n1,M;
bool prz[N];
int pr[N/5];
int Ans[N];
LL ALLc,Pi[N];
LL ksm(LL q,int w)
{
    LL ans=1;
    for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
    return ans;
}
LL LIP(int n)
{
    if(n<1)return 0;
    if(n<=m)return Ans[n];
    ALLc=1;
    fo(i,n-m,n-1)ALLc=ALLc*(LL)i%mo;
    LL ans=0;
    fo(i,1,m)
    {
        LL t1=Pi[i-1]*Pi[m-i]%mo*(LL)(n-i)%mo;
        if((m-i+2)&1)t1=-t1;
        ans=(ans+Ans[i]*ksm(t1,mo-2)%mo)%mo;
    }
    if(ans<0)ans+=mo;
    return ans*ALLc%mo;
}
int main()
{
    scanf("%d%d%d",&n,&n1,&m);
    M=m;m+=2;
    Ans[1]=Pi[0]=Pi[1]=1;
    fo(i,2,m)
    {
        if(!prz[i])pr[++pr[0]]=i,Ans[i]=ksm(i,M);
        fo(j,1,pr[0])
        {
            int t=pr[j]*i;
            if(t>m||t<1)break;
            prz[t]=1;
            Ans[t]=Ans[i]*(LL)Ans[pr[j]]%mo;
            if(i%pr[j]==0)break;
        }
        Pi[i]=Pi[i-1]*(LL)i%mo;
    }
    fo(i,2,m+2)Ans[i]=(Ans[i]+Ans[i-1])%mo;
    printf("%lld\n",((n<2?(n=2,ksm(2,M)):0)+LIP(n1)-LIP(n-1)+mo)%mo);
    return 0;
}

你可能感兴趣的:(数论,拉格朗日插值法)