暂时没有补题链接,等重现赛
定义了 f ( x ) = a 0 + a 1 x 1 + a 2 x 2 + ⋯ + a n x n f_{(x)}=a_{0}+a_{1} x^{1}+a_{2} x^{2}+\cdots+a_{n} x^{n} f(x)=a0+a1x1+a2x2+⋯+anxn,数字可能会非常大,所以对9999991取模。对于一个多项式,XH不知道任意一个 a i a_i ai,但是他知道 f ( 0 ) , f ( 1 ) , f ( 2 ) ⋯ f ( n ) f_{(0)}, f_{(1)}, f_{(2)} \cdots f_{(n)} f(0),f(1),f(2)⋯f(n) 的值,他想要计算 ∑ i = L R f i   m o d   9999991 \sum_{i=L}^{R} f_{i} \bmod 9999991 i=L∑Rfimod9999991
裸的拉格朗日插值,但是要变形一下。
首先根据 n + 1 n+1 n+1 个点,可以用拉格朗日插值法插出一个 n n n 次的多项式,题目给出了 0 到 n, n + 1 n+1 n+1 个点,那么我们可以插出 f ( x ) f(x) f(x),
但是注意:题目让求的是 f ( x ) f(x) f(x) 的区间和,
那么很自然可以想到求出预处理求出前缀和,那么区间和就是 O ( 1 ) O(1) O(1)了。定义前缀和 S ( x ) = ∑ i = 0 x f ( i ) S(x)=\sum_{i=0}^{x} f(i) S(x)=i=0∑xf(i)
这里有个常识,n次多项式的前缀和是 n+1 次的多项式,也就是说 S ( x ) S(x) S(x) 要通过 n+2 个点来求出,然而题目只给出了n+1 个点。
少的那一个点可以先通过 n+1 个点将 f ( x ) f(x) f(x)求出,之后得到 f ( n + 1 ) f(n+1) f(n+1) ,之后就可以对 S ( x ) S(x) S(x) 插值了。
关于代码方面,插值的函数我重载成了一个,传入的参数不同功能也不一样,但是本题求 f ( x ) , S ( x ) f(x), S(x) f(x),S(x) 的函数是一样的。
赛后打的仅过了样例,
#include
using namespace std;
typedef long long ll;
const ll mod = 9999991;
const int N = 1e3 + 10;
ll t, n, m, l, r;
ll a[N], sum[N], pre[N], suf[N], fac[N];
ll qpow(ll x, ll y){
ll ans = 1;
while(y){
if(y&1)
ans = ans * x % mod;
x = x * x % mod, y >>= 1;
}
return ans;
}
/* cal 函数,用从 0 到 up,一共 up+1 个数,
传入的 a 数组代表 yi
插值出原来的 up+2 次方的多项式
并返回 原来的多项式在 x 出的取值。
*/
ll cal(ll x, ll *a, ll up) //计算 a(n+1)
{
ll ans = 0;
pre[0] = x, suf[up+1] = 1;
for(int i = 1; i <= up; i++){
pre[i] = pre[i-1] * (x-i) % mod;
}
for(int i = up; i >= 0; i--){
suf[i] = suf[i+1] * (x-i) % mod;
}
for(int i = 0; i <= up; i++){
ll f = fac[up - i] * fac[i] % mod;
f = (up - i) & 1 ? -f : f;
(ans += a[i] * f % mod * (i == 0 ? 1 : pre[i - 1]) % mod * suf[i + 1]) %= mod;
}
ans += ans < 0 ? mod : 0;
return ans;
}
void init()
{
fac[0] = 1;
for (int i = 1; i < N; i++){
fac[i] = fac[i - 1] * i % mod;
}
for(int i = 0; i < N; i++){
fac[i] = qpow(fac[i], mod - 2);
}
}
int main()
{
init();
scanf("%d", &t);
while(t--){
scanf("%d%d", &n, &m);
for(int i = 0; i <= n; i++){
scanf("%d", &a[i]);
}
a[n+1] = cal(n+1, a, n); //插出 f(n+1)
// d(a[n + 1]);
sum[0] = a[0];
for(int i = 1; i <= n+1; i++){
sum[i] = sum[i - 1] + a[i] % mod;
}
while(m--){
scanf("%d%d", &l, &r);
ll cnt = cal(r, sum, n+1) - cal(l - 1, sum, n+1);
cnt += cnt < 0 ? mod : 0;
printf("%lld\n", cnt);
}
}
return 0;
}