題目連接: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; }