题目连接:https://nanti.jisuanke.com/t/40254html
题意:app
思路:spa
这题要用到拉格朗日插值法,网上查了一下,找到一份讲得特别好的:.net
--------------------------------------------------------code
以上关于拉格朗日插值法的理论转载自:https://blog.csdn.net/ftx456789/article/details/90750508xml
关于这道题的作法:
这题给了x从0~n的n+1种取值,那么能够用O(n)来插值,可是它所要求的是。可以想到要用前缀来预处理,咱们令:htm
,则答案为
。blog
直接预处理S(x)确定会T,咱们再用一次拉格朗日插值法。ip
先知道一个常识:n次多项式的前缀和是 n+1 次的多项式,也就是说 SS(x) 要经过 n+2 个点来求出,然而题目只给出了n+1 个点。咱们利用前面的插值法求出f(n+1),这样就有了n+2个点。以后就能够对S(x) 进行插值了。总复杂度为O(T*m*n)it
要注意的是要线性求逆元,若是用费马小定理会T。
AC代码:
#include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const int maxn=1005; const int MOD=9999991; int T,n,m; LL a[maxn],inv[MOD+5],finv[maxn]; LL sum[maxn],ans; LL qpow(LL a,LL b){ LL res=1; while(b){ if(b&1) res=res*a%MOD; a=a*a%MOD; b>>=1; } return res; } void init(){ inv[1]=1; for(int i=2;i<=MOD+5;++i) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD; finv[0]=1; for(int i=1;i<=1000;++i) finv[i]=finv[i-1]*inv[i]%MOD; } LL cal(LL x,LL *a,LL up){ LL res=0; LL p=1; for(LL i=0;i<=up;++i) p=p*(x-i)%MOD; for(LL i=0;i<=up;++i){ int f=(up-i)&1?-1:1; res=(res+MOD+a[i]*f*p%MOD*inv[x-i]%MOD*finv[i]%MOD*finv[up-i]%MOD)%MOD; } return res; } int main(){ init(); scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=0;i<=n;++i){ scanf("%lld",&a[i]); a[i]%=MOD; } a[n+1]=cal(n+1,a,n); sum[0]=a[0]; for(int i=1;i<=n+1;++i) sum[i]=(sum[i-1]+a[i])%MOD; while(m--){ int l,r; scanf("%d%d",&l,&r); if(r<=n+1){ printf("%lld\n",(sum[r]-sum[l-1]+MOD)%MOD); continue; } if(l-1<=n+1) ans=(cal(r,sum,n+1)-sum[l-1]+MOD)%MOD; else ans=(cal(r,sum,n+1)-cal(l-1,sum,n+1)+MOD)%MOD; printf("%lld\n",ans); } } return 0; }