Polynomial
题意:给出一个n次多项式F(x),给出F(0),F(1)…F(n),m个询问给出l,r,求F[l]+F[l+1]+…+F[r-1]+F[r]。
n<=1000,m<=2000,1<=l<=r<=9999990。
思路:暴力肯定不行,需要求一共1e7的F[]数组,只要不是o(1)的求法就一定会爆,所有转化思路,猜测一个n次式的前缀和是n+1次式,为了证明这个假设,我弄了个3次的式子然后求出他的前缀和的四次式,符合猜想,所以假设猜测成立,然后就拉格朗日求出F[n+1],然后用sum[i]求出F[i]的前缀和,然后用拉格朗日求值法可以利用拉格朗日求值法的第二种方法o(n)的得到sum[i],然后对每个询问sum[r]-sum[l-1]即可,因为某个地方忘%了WA成shi了。数论的题实现真恶心。
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX_N=1010;
const long long MOD=9999991;
long long f[MAX_N];
long long sum[MAX_N];
long long F[MAX_N];
long long pre[MAX_N],suf[MAX_N],Inv[10000100];
long long C(long long x){
if(x%2==0)
return 1;
else
return -1;
}
long long ask(long long k,long long n){
if(k<=n)
return sum[k];
long long i;
pre[0]=k;
for(i=1;i<=n;i++){
pre[i]=pre[i-1]*(k-i)%MOD;
}
suf[n]=k-n;
for(i=n-1;i>=0;i--){
suf[i]=suf[i+1]*(k-i)%MOD;
}
long long ans=0;
ans=(ans+sum[0]*suf[1]%MOD*Inv[(F[n]*C(n)+MOD)%MOD]%MOD)%MOD;
ans=(ans+sum[n]*pre[n-1]%MOD*Inv[F[n]]%MOD)%MOD;
for(i=1;i<n;i++){
ans=(ans+sum[i]*pre[i-1]%MOD*suf[i+1]%MOD*Inv[(F[i]*C(n-i)+MOD)%MOD*F[n-i]%MOD]%MOD)%MOD;
}
return ans;
}
int main(void){
int T;
long long n,m;
long long i,j;
cin>>T;
F[0]=1;
for(i=1;i<=1005;i++)
F[i]=F[i-1]*i%MOD;
long long p=MOD;
Inv[1]=1;
for(i=2;i<p;i++)
Inv[i]=(p-p/i)*Inv[p%i]%p;
while(T--){
scanf("%lld%lld",&n,&m);
for(i=0;i<=n;i++)
scanf("%lld",&f[i]);
f[n+1]=0;
for(i=0;i<=n;i++){
long long res=1;
long long fact=1;
for(j=0;j<=n;j++){
if(i==j)
continue;
res=res*(n+1-j)%MOD;
fact=fact*((i-j+MOD)%MOD)%MOD;
}
res=res*Inv[fact]%MOD;
f[n+1]=(f[n+1]+f[i]*res%MOD)%MOD;
}
sum[0]=f[0];
for(i=1;i<=n+1;i++){
sum[i]=(sum[i-1]+f[i])%MOD;
}
long long l,r;
for(i=0;i<m;i++){
scanf("%lld%lld",&l,&r);
printf("%lld\n",(ask(r,n+1)-ask(l-1,n+1)+MOD)%MOD);
}
}
return 0;
}