2019ICPC邀请赛南昌B Polynomial 拉格朗日插值

让你求f(L)到f(R)的和。

我们考虑前缀和,F(x)必定是比f(x)次数高1的多项式,所以我们先插值插出f(n+1)。然后求出n+1个前缀和,插值出前缀和即可。

 1 #include <cstdio>
 2 using namespace std;
 3 typedef long long ll;
 4 const int mo = 9999991;
 5 int n,m,T;
 6 ll y1[1100],y2[1100],pre[1100],suf[1100],inv[1100];
 7 ll fpow(ll x,int k)
 8 {
 9     if (k == 0)
10         return 1;
11     ll t = fpow(x,k >> 1);
12     if (k & 1)
13         return t * t % mo * x % mo;
14     return t * t % mo; 
15 }
16 ll calc(ll y[],int n,int x)
17 {
18     if (x <= n)
19         return y[x];
20     pre[0] = x;
21     suf[n] = x - n;
22     for (int i = 1;i <= n;i++)
23         pre[i] = pre[i - 1] * (x - i) % mo;
24     for (int i = n - 1;i >= 0;i--)
25         suf[i] = suf[i + 1] * (x - i) % mo;
26     ll ans = 0; 
27     for (int i = 0;i <= n;i++)
28     {
29         ll tans = (n - i) & 1 ? -y[i] : y[i];
30         if (i >= 1)
31             tans = (tans * pre[i - 1] % mo + mo) % mo;
32         if (i <= n - 1)
33             tans = (tans * suf[i + 1] % mo + mo) % mo;
34         tans = (tans * inv[n - i] % mo * inv[i] % mo + mo) % mo;
35         ans = (ans + tans) % mo;
36     }
37     return ans;
38 }
39 int main()
40 {
41     ll t = 1;
42     for (int i = 1;i <= 1000;i++)
43         t = t * i % mo;
44     inv[1000] = fpow(t,mo - 2);
45     for (int i = 999;i >= 0;i--)
46         inv[i] = inv[i + 1] * (i + 1) % mo;
47     for (scanf("%d",&T);T;T--)
48     {
49         scanf("%d%d",&n,&m);
50         for (int i = 0;i <= n;i++)
51             scanf("%lld",&y1[i]);
52         y1[n + 1] = calc(y1,n,n + 1);
53         for (int i = 1;i <= n + 1;i++)
54             y2[i] = y2[i - 1] + y1[i]; 
55         int tl,tr;
56         for (int i = 1;i <= m;i++)
57         {
58             scanf("%d%d",&tl,&tr);
59             printf("%lld\n",((calc(y2,n + 1,tr) - calc(y2,n + 1,tl - 1)) % mo + mo) % mo);
60         }
61     }
62     return 0;
63 }

 

posted @ 2020-03-09 16:22  IAT14  阅读(206)  评论(0编辑  收藏  举报