[JZOJ5395]Count

来源:互联网 发布:linux tail f 退出 编辑:程序博客网 时间:2024/06/01 07:56

题目描述

这里写图片描述
一行三个正整数 ,表示L,R,K,含义如题所示。
这里写图片描述

分析

这道题实际上就是逗你玩的,求的就是自然数幂和ri=lik,当然,如果l=1,你还要给答案加上2k1
我们新学习一个插值法…

拉格朗日插值法

背诵吧…反正用处也不广,记证明没什么用。
我们如果知道函数有多项式解析式,若是K+1次,那么我们用K+2个函数点,用插值法,就可以唯一确定解析式。而拉格朗日插值法由于式子长得好看,别的方法弄自然数幂和都要O(K2),他只要O(KKlogK)
对于K+2个函数点(xi,yi),我们知道通项公式是K+1次的话:
我们如果要求自变量x的函数值,那么
y(x)=K+2i=1yiK+2j=1,jixxjxixj.
对于一次代入,可以发现后面的累乘可以预处理,因为分子和分母都是一段连续的数,挖掉一个数再相乘的积。
要预处理每个数的逆元,求函数值,用快速幂就带log了,有不用的方法。

代码

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<set>using namespace std;#define fo(i,j,k) for(i=j;i<=k;i++)#define fd(i,j,k) for(i=j;i>=k;i--)#define cmax(a,b) (a=(a>b)?a:b)typedef long long ll;typedef double db;const int N=1e6+50,mo=998244353;int rev[N],y[N],prev[N],nrev[N],a[N],b[N],c[N],l,r,K,i,j,k,ans;int ksm(int x,int y){    int ret=1;    while (y)    {        if (y&1) ret=1ll*ret*x%mo;        x=1ll*x*x%mo;        y>>=1;    }    return ret;}void predo(){    fo(i,1,K+2) rev[i]=ksm(i,mo-2);    fo(i,1,K+2) y[i]=(y[i-1]+ksm(i,K))%mo;    prev[0]=nrev[0]=1;    fo(i,1,K+2)     {        prev[i]=1ll*prev[i-1]*rev[i]%mo;        nrev[i]=1ll*nrev[i-1]*(-rev[i])%mo;    }}int get(int x){    if (x<=K+2) return y[x];    b[0]=1;    fo(i,1,K+2) a[i]=x-i,b[i]=1ll*b[i-1]*a[i]%mo;    c[K+3]=1;    fd(i,K+2,1) c[i]=1ll*c[i+1]*a[i]%mo;    int ret=0;    fo(i,1,K+2)        ret=(ret+1ll*y[i]*b[i-1]%mo*c[i+1]%mo*prev[i-1]%mo*nrev[K+2-i])%mo;    return ret;}int main(){    freopen("t1.in","r",stdin);//  freopen("count.out","w",stdout);    scanf("%d %d %d",&l,&r,&K);    predo();    ans=(get(r)-get(l-1)+mo)%mo;    if (l==1) ans=(ans+ksm(2,K)-1)%mo;    printf("%d\n",ans);}
原创粉丝点击