传送门: https://nanti.jisuanke.com/t/40254
题意
f
(
x
)
=
a
0
+
a
1
x
+
.
.
.
+
a
n
x
n
,
没
有
给
出
a
0
,
a
1
.
.
.
a
n
,
只
知
道
f
(
0
)
,
f
(
1
)
.
.
.
f
(
n
)
,
求
f(x)=a_0+a_1x+...+a_nx^n,没有给出a_0,a_1...a_n,只知道f(0),f(1)...f(n),求
f(x)=a0+a1x+...+anxn,没有给出a0,a1...an,只知道f(0),f(1)...f(n),求
∑
i
=
L
R
f
(
i
)
m
o
d
9999991
\sum_{i=L}^Rf(i)\;\;mod\;\;9999991
i=L∑Rf(i)mod9999991
思路
看 到 这 个 形 式 , 就 知 道 用 拉 格 朗 日 插 值 法 了 , 即 看到这个形式,就知道用拉格朗日插值法了,即 看到这个形式,就知道用拉格朗日插值法了,即
f [ k ] = ∑ i = 0 n y i ∏ i ≠ j k − x [ j ] x [ i ] − x [ j ] f[k]=\sum_{i=0}^ny_i\prod_{i\ne j}\frac{k-x[j]}{x[i]-x[j]} f[k]=i=0∑nyii=j∏x[i]−x[j]k−x[j]
但
是
题
目
中
给
出
的
点
都
是
连
续
的
,
(
0
,
f
(
0
)
)
、
(
1
,
f
(
1
)
)
.
.
.
(
n
,
f
(
n
)
)
,
也
就
是
x
连
续
,
所
以
插
值
式
变
为
但是题目中给出的点都是连续的,(0,f(0))、(1,f(1))...(n,f(n)),也就是x连续,所以插值式变为
但是题目中给出的点都是连续的,(0,f(0))、(1,f(1))...(n,f(n)),也就是x连续,所以插值式变为
f
[
k
]
=
∑
i
=
0
n
y
i
∏
i
≠
j
k
−
j
i
−
j
f[k]=\sum_{i=0}^ny_i\prod_{i\ne j}\frac{k-j}{i-j}
f[k]=i=0∑nyii=j∏i−jk−j
所 以 一 般 的 拉 格 朗 日 插 值 的 复 杂 度 为 O ( n 2 ) , 而 当 x 连 续 的 时 候 , 复 杂 度 一 度 降 为 O ( n ) 。 所以一般的拉格朗日插值的复杂度为O(n^2),而当x连续的时候,复杂度一度降为O(n)。 所以一般的拉格朗日插值的复杂度为O(n2),而当x连续的时候,复杂度一度降为O(n)。
将 上 式 展 开 : 将上式展开: 将上式展开:
f [ k ] = ∑ i = 0 n y i k ( k − 1 ) ( k − 2 ) . . . ( k − n ) [ i ( i − 1 ) ( i − 2 ) . . . 1 ] ∗ [ ( − 1 ) ∗ ( − 2 ) ∗ . . . ∗ ( i − n ) ] f[k]=\sum_{i=0}^ny_i\frac{k(k-1)(k-2)...(k-n)}{[i(i-1)(i-2)...1]*[(-1)*(-2)*...*(i-n)]} f[k]=i=0∑nyi[i(i−1)(i−2)...1]∗[(−1)∗(−2)∗...∗(i−n)]k(k−1)(k−2)...(k−n)
f [ k ] = ∑ i = 0 n y i ∏ j = 0 i − 1 ( k − j ) ∏ j = i + 1 n ( k − j ) i ! ∗ ( i − n ) ! f[k]=\sum_{i=0}^ny_i\frac{\prod_{j=0}^{i-1}(k-j)\prod_{j=i+1}^n(k-j)}{i!*(i-n)!} f[k]=i=0∑nyii!∗(i−n)!∏j=0i−1(k−j)∏j=i+1n(k−j)
f [ k ] = ∑ i = 0 n y i p r e [ i − 1 ] ∗ s u f [ i + 1 ] f a c [ i ] ∗ f a c [ n − i ] [ ( n − i ) & 1 ? − 1 : 1 ] f[k]=\sum_{i=0}^ny_i\frac{pre[i-1]*suf[i+1]}{fac[i]*fac[n-i]}[(n-i) \&1 ?-1:1] f[k]=i=0∑nyifac[i]∗fac[n−i]pre[i−1]∗suf[i+1][(n−i)&1?−1:1]
对
于
分
母
,
可
以
预
处
理
阶
乘
和
阶
乘
逆
元
。
对于分母,可以预处理阶乘和阶乘逆元。
对于分母,可以预处理阶乘和阶乘逆元。
对
于
分
子
,
做
一
个
前
缀
积
和
一
个
后
缀
积
。
对于分子,做一个前缀积和一个后缀积。
对于分子,做一个前缀积和一个后缀积。
所 以 首 先 , 先 插 出 一 个 f ( n + 1 ) , 在 对 f 进 行 一 个 前 缀 和 s u m 数 组 , 然 后 直 接 对 s u m 数 组 进 行 插 值 , 计 算 s u m [ R ] − s u m [ l − 1 ] 即 可 。 所以首先,先插出一个f(n+1),在对f进行一个前缀和sum数组,然后直接对sum数组进行插值,计算sum[R]-sum[l-1]即可。 所以首先,先插出一个f(n+1),在对f进行一个前缀和sum数组,然后直接对sum数组进行插值,计算sum[R]−sum[l−1]即可。
注 意 : 为 什 么 要 插 出 一 个 f ( n + 1 ) , 是 因 为 要 先 对 s u m 数 组 有 插 值 这 个 影 响 , 而 s u m 又 是 f 的 前 缀 和 , 所 以 要 先 插 出 一 个 f ( n + 1 ) 来 , 所 以 也 可 以 插 f ( n + 2 ) 、 f ( n + 3 ) 都 可 以 , 只 要 有 这 个 影 响 就 行 。 注意:为什么要插出一个f(n+1),是因为要先对sum数组有插值这个影响,而sum又是f的前缀和,所以要先插出一个f(n+1)来,所以也可以插f(n+2)、f(n+3)都可以,只要有这个影响就行。 注意:为什么要插出一个f(n+1),是因为要先对sum数组有插值这个影响,而sum又是f的前缀和,所以要先插出一个f(n+1)来,所以也可以插f(n+2)、f(n+3)都可以,只要有这个影响就行。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pdd;
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)
#define mem(a, b) memset(a , b , sizeof(a))
#define FOR(i, x, n) for(int i = x;i <= n; i++)
// const ll mod = 998244353;
// const ll mod = 1e9 + 7;
// const double eps = 1e-6;
// const double PI = acos(-1);
// const double R = 0.57721566490153286060651209;
const int N = 1005;
const int MAXN = 1e7 + 10;
const ll mod = 9999991;
ll F[N];
ll pre[N], suf[N];
ll fac[N], invf[N];
ll sum[MAXN];
ll quick_pow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void init() {
fac[0] = 1;
for(int i = 1;i < N; i++) fac[i] = fac[i - 1] * i % mod;
invf[N - 1] = quick_pow(fac[N - 1], mod - 2);
for(int i = N - 1;i >= 1; i--) invf[i - 1] = invf[i] * i % mod;
}
ll Lagrange(ll *f, int k, int n) {
if(k <= n) return f[k];
pre[0] = suf[n] = 1;
for(int i = 1;i <= n; i++) pre[i] = pre[i - 1] * (k - i + 1) % mod;
for(int i = n;i >= 1; i--) suf[i - 1] = suf[i] * (k - i) % mod;
ll ans = 0;
for(int i = 0;i <= n; i++) {
int opt = (n - i) & 1 ? -1 : 1;
ans = (ans + 1ll * opt * pre[i] % mod * suf[i] % mod * invf[i] % mod * invf[n - i] % mod * f[i] % mod + mod) % mod;
}
return f[k] = ans;
}
void solve()
{
init();
int T;
cin >> T;
while(T--) {
int n, q;
cin >> n >> q;
for (int i = 0; i <= n; i++) cin >> F[i];
F[n + 1] = Lagrange(F, n + 1, n);
sum[0] = F[0];
for (int i = 1; i <= n + 1; i++) sum[i] = (sum[i - 1] + F[i]) % mod;
while (q--) {
int l, r;
cin >> l >> r;
cout << (Lagrange(sum, r, n + 1) - Lagrange(sum, l - 1, n + 1) + mod) % mod << endl;
}
}
}
signed main() {
ios_base::sync_with_stdio(false);
//cin.tie(nullptr);
//cout.tie(nullptr);
#ifdef FZT_ACM_LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
signed test_index_for_debug = 1;
char acm_local_for_debug = 0;
do {
if (acm_local_for_debug == '$') exit(0);
if (test_index_for_debug > 20)
throw runtime_error("Check the stdin!!!");
auto start_clock_for_debug = clock();
solve();
auto end_clock_for_debug = clock();
cout << "Test " << test_index_for_debug << " successful" << endl;
cerr << "Test " << test_index_for_debug++ << " Run Time: "
<< double(end_clock_for_debug - start_clock_for_debug) / CLOCKS_PER_SEC << "s" << endl;
cout << "--------------------------------------------------" << endl;
} while (cin >> acm_local_for_debug && cin.putback(acm_local_for_debug));
#else
solve();
#endif
return 0;
}