数学基础 5
前言
因为 (3) 写不出来了 (4) 现在还空着 但是计划被打乱 所以来写 (5) (大雾
目前还没写完 后面先咕着 学了之后再写
拉格朗日插值
拉格朗日插值法
众所周知 给定 (n + 1) 个点 可以确定一个 (n) 次的多项式
[f(x) = sum_{i = 0}^{n}y_iprod_{i
e j}frac{x-x_j}{x_i - x_j}
]
求其中某个点对应函数值时 将其代入即可
证明? 没有证明(我并不会
代码
/*
Time: 6.27
Worker: Blank_space
Source: P4781 【模板】拉格朗日插值
*/
/*--------------------------------------------*/
#include<cstdio>
#define int long long
/*--------------------------------------头文件*/
const int mod = 998244353;
int n, k, X[2010], Y[2010], ans;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % mod, _b >>= 1) if(_b & 1) res = res * _a % mod; return res;}
/*----------------------------------------函数*/
signed main() {
n = read(); k = read();
for(int i = 1; i <= n; i++) X[i] = read(), Y[i] = read();
for(int i = 1; i <= n; i++)
{
int tmp1 = Y[i], tmp2 = 1;
for(int j = 1; j <= n; j++) if(i != j)
tmp1 = (tmp1 * (k - X[j]) % mod + mod) % mod, tmp2 = (tmp2 * (X[i] - X[j]) % mod + mod) % mod;
ans = (ans + tmp1 * power(tmp2, mod - 2) % mod) % mod;
}
printf("%lld", ans);
return 0;
}
在 (x) 值连续的时候
将 (x_i) 换成 (i) 有:
[f(k) = sum_{i = 0}^ny_iprod_{i
e j}frac{k - j}{i - j}
]
考虑优化后面那一坨东西
分子维护关于 (k) 的前缀积和后缀积 分母直接用阶乘来表示 式子为:
[f(k) = sum_{i = 0}^nleft(-1
ight)^{n - i}y_ifrac{pre_{i - 1} imes suf_{i + 1}}{fac_i imes fac_{n - i}}
]
重心拉格朗日插值法
[egin{array}\
f(x) & = & sum_{i = 1}^ny_iprod_{i
e j}frac{x - x_j}{x_i - x_j} \
& = & sum_{i = 1}^ny_ifrac{prod_{j
e i}left(x - x_j
ight)}{prod_{i
e j}left(x_i - x_j
ight)}\
& = & sum_{i = 1}^ny_ifrac{prod_{j = 1}^nleft(x - x_j
ight)}{left(x - x_i
ight)prod_{j
e i}left(x_i - x_j
ight) }\
& = & prod_{i = 1}^nleft(x - x_i
ight)sum_{i = 1}^nfrac{y_i}{left(x - x_i
ight)prod_{i
e j}left(x_i - x_i
ight)}
end{array}
]
令 (g = prod_{i = 1}^nleft(x - x_i ight), w(i) = prod_{j e i}left(x_i - x_j ight)) 有:
[f(x) = gsum_{i = 1}^nfrac{y_i}{left(x - x_i
ight)w(i)}
]
对于每一个新增加的插值点 (O(n)) 的更新所有的 (w(i))
代码
/*
Time: 6.27
Worker: Blank_space
Source:
*/
/*--------------------------------------------*/
#include<cstdio>
#define int long long
/*--------------------------------------头文件*/
const int mod = 1e9 + 7;
int n, X[3010], Y[3010], W[3010], cnt;
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b) {int res = 1; for(; _b; _a = _a * _a % mod, _b >>= 1) if(_b & 1) res = res * _a % mod; return res;}
void insert(int x, int y) {
X[++cnt] = x; Y[cnt] = y; W[cnt] = 1;
for(int i = 1; i < cnt; i++) W[i] = W[i] * (X[i] - x) % mod, W[cnt] = W[cnt] * (x - X[i]) % mod;
}
void work(int x) {
int g = 1, ans = 0;
for(int i = 1; i <= cnt; i++)
if(X[i] == x) {printf("%lld
", Y[i]); return ;}
else g = g * (x - X[i]) % mod;
for(int i = 1; i <= cnt; i++)
ans = (ans + Y[i] * power((x - X[i]) * W[i], mod - 2) % mod + mod) % mod;
printf("%lld
", ans * g % mod);
}
/*----------------------------------------函数*/
signed main() {
n = read();
for(int i = 1; i <= n; i++)
{
int opt = read(), x = read();
if(opt == 1) insert(x, read());
else work(x);
}
return 0;
}
自然数幂和
定义
前 (n) 个自然数 (k) 次幂的和为
[S_k(n) = sum_{i = 1}^ni^k
]
性质
(S_k(n)) 为关于 (n) 的 (k + 1) 次的多项式
拉格朗日插值法
需要 (k + 2) 个点来计算 可以直接取点 (O(k^2)) 的计算
题目对于选择的点没有要求 当然可以选取连续的一段 按照上面那个直接带进去:
[S_k(n) = sum_{i = 1}^{k + 2}(-1)^{k + 2 - i}S_k(i)frac{pre_{i - 1} imes suf_{i + 1}}{fac_{i} imes fac_{k + 2 - i}}
]
复杂度: (O(klog k))
代码:
/*
Time: 6.27
Worker: Blank_space
Source: CF622F The Sum of the k-th Powers
*/
/*--------------------------------------------*/
#include<cstdio>
#define int long long
/*--------------------------------------头文件*/
const int C = 1e6 + 7;
const int mod = 1e9 + 7;
/*------------------------------------常量定义*/
int n, k, ans, tmp, pre[C], suf[C], fac[C];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % mod, _b >>= 1) if(_b & 1) res = res * _a % mod; return res;}
/*----------------------------------------函数*/
signed main() {
n = read(); k = read(); pre[0] = suf[k + 3] = fac[0] = 1;
for(int i = 1; i <= k + 2; i++) pre[i] = pre[i - 1] * (n - i) % mod;
for(int i = k + 2; i >= 1; i--) suf[i] = suf[i + 1] * (n - i) % mod;
for(int i = 1; i <= k + 2; i++) fac[i] = fac[i - 1] * i % mod;
for(int i = 1; i <= k + 2; i++)
{
tmp = (tmp + power(i, k) % mod) % mod;
int x = pre[i - 1] * suf[i + 1] % mod;
int y = ((k - i & 1) ? -1 : 1) * fac[i - 1] * fac[k + 2 - i] % mod;
ans = (ans + tmp * x % mod * power(y, mod - 2) % mod + mod) % mod;
}
printf("%lld", ans);
return 0;
}
其他方法
然而我并不会其他方法(巨雾
题目
首先 由题:
[ans = sum_{i = 0}^mleft(sum_{j = 1}^{n - a_i}j^{m + 1} - sum_{j = i + 1}^mleft(a_j - a_i
ight)^{m + 1}
ight)
]
然而这个式子我并没有推出来
然后? 然后就没有然后了 直接算就好了
代码
/*
Time: 6.27
Worker: Blank_space
Source: P4593 [TJOI2018]教科书般的亵渎
*/
/*--------------------------------------------*/
#include<cstdio>
#include<algorithm>
#define int long long
/*--------------------------------------头文件*/
const int mod = 1e9 + 7;
/*------------------------------------常量定义*/
int T, n, m, k, a[60], ans, tmp, pre[60], suf[60], fac[60];
/*------------------------------------变量定义*/
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
/*----------------------------------------快读*/
int power(int _a, int _b, int res = 1) {for(; _b; _a = _a * _a % mod, _b >>= 1) if(_b & 1) res = res * _a % mod; return res;}
int Sum(int t) {
pre[0] = suf[k + 3] = fac[0] = 1; tmp = 0; int res = 0;
for(int i = 1; i <= k + 2; i++) pre[i] = pre[i - 1] * (t - i) % mod;
for(int i = k + 2; i >= 1; i--) suf[i] = suf[i + 1] * (t - i) % mod;
for(int i = 1; i <= k + 2; i++) fac[i] = fac[i - 1] * i % mod;
for(int i = 1; i <= k + 2; i++)
{
tmp = (tmp + power(i, k) % mod) % mod;
int x = pre[i - 1] * suf[i + 1] % mod;
int y = ((k - i & 1) ? -1 : 1) * fac[i - 1] * fac[k + 2 - i] % mod;
res = (res + tmp * x % mod * power(y, mod - 2) % mod + mod) % mod;
}
return res;
}
void work() {
n = read(); m = read(); ans = 0; k = m + 1;
for(int i = 1; i <= m; i++) a[i] = read();
std::sort(a + 1, a + 1 + m);
for(int i = 0; i <= m; i++)
{
int sum = Sum(n - a[i]) % mod;
for(int j = i + 1; j <= m; j++) sum = ((sum - power(a[j] - a[i], k) % mod) % mod + mod) % mod;
ans = (ans + sum) % mod;
}
printf("%lld
", (ans + mod) % mod);
}
/*----------------------------------------函数*/
signed main() {
T = read(); while(T--) work();
return 0;
}
待填