JZOJ 5395. 【NOIP2017提高A组模拟10.6】Count(拉格朗日插值)
JZOJ 5395. 【NOIP2017提高A组模拟10.6】Count
题目大意
- 令 f ( x ) f(x) f(x)表示 ≤ x \le x ≤x的正整数中与 x x x互质的数的平均数的两倍,求 ∑ i = L R f k ( i ) \sum_{i=L}^{R}{f^k(i)} ∑i=LRfk(i)。
- L , R ≤ 1 0 8 L,R\le 10^8 L,R≤108, k ≤ 1 0 6 k\le 10^6 k≤106.
题解
- 当 x ≤ 2 x\le 2 x≤2时, f ( x ) = x f(x)=x f(x)=x,因为一旦有 r ≤ x r\le x r≤x与 x x x互质,则一定也有 x − r ≤ x x-r\le x x−r≤x与 x x x互质,所以与 x x x互质的数可以两两匹配,它们之和恰为 x x x,特殊地, f ( 1 ) = 2 f(1)=2 f(1)=2。
- 那么题目转化为求 ∑ i = L R i k = ∑ i = 1 R i k − ∑ i = 1 L − 1 i k \sum_{i=L}^{R}i^k=\sum_{i=1}^{R}i^k-\sum_{i=1}^{L-1}i^k ∑i=LRik=∑i=1Rik−∑i=1L−1ik。
- 而任何 ∑ i = 1 n i k \sum_{i=1}^n i^k ∑i=1nik(简单称之为 k k k次方和 S k S_k Sk)都是关于 n n n的一个 k + 1 k+1 k+1次多项式,具体可以考虑归纳,
- 当 k = 0 k=0 k=0时, S 0 = n S_0=n S0=n,是一个一次多项式,这显然成立;
- 当 k > 0 k>0 k>0时,可以构造
- ( n + 1 ) k + 1 − n k + 1 = . . . {(n+1)^{k+1}}-{n^{k+1}}=... (n+1)k+1−nk+1=...
- n k + 1 − ( n − 1 ) k + 1 = . . . n^{k+1}-(n-1)^{k+1}=... nk+1−(n−1)k+1=...
- . . . ... ...
- 2 k + 1 − 1 k + 1 = . . . 2^{k+1}-1^{k+1}=... 2k+1−1k+1=...
- 把所有式子相加,左边是 ( n + 1 ) k + 1 − 1 (n+1)^{k+1}-1 (n+1)k+1−1,右边的最高次是 k k k(因为相减时 k + 1 k+1 k+1次项都会消掉),且一定是 ∑ i = 0 k a i S i \sum_{i=0}^{k}a_iS_i ∑i=0kaiSi,其中 a i a_i ai是某个系数,除了 S k S_k Sk都可以用 k k k次以下的多项式来表示,那么移项后 S k S_k Sk自然可以用 ( n + 1 ) k + 1 − 1 − ∑ i = 0 k − 1 a i S i a k \dfrac{(n+1)^{k+1}-1-\sum_{i=0}^{k-1}a_iS_i}{a_k} ak(n+1)k+1−1−∑i=0k−1aiSi来表示,故 S k S_k Sk可以用一个 k + 1 k+1 k+1次多项式表示。
- 得证。
- 现在要求的是 x = R x=R x=R和 x = L − 1 x=L-1 x=L−1时的函数值,而 L , R L,R L,R都过不便计算,那么自然可以使用拉格朗日插值法,只需求出 i = 1 , 2 , 3 , . . . , k , k + 1 , k + 2 i=1,2,3,...,k,k+1,k+2 i=1,2,3,...,k,k+1,k+2时的 k + 2 k+2 k+2个不同的函数值,便可以确定一个 k + 1 k+1 k+1次的函数。
- 此时 A n s n = ∑ i = 1 k + 2 A n s i Π j ≠ i n − j i − j Ans_n=\sum_{i=1}^{k+2}Ans_i\Pi_{j\not=i}\dfrac{n-j}{i-j} Ansn=∑i=1k+2AnsiΠj=ii−jn−j。
- 复杂度仍然是 k 2 k^2 k2的,可以简单优化。
- 对于任意的 i i i,分子都是 Π n − j \Pi n-j Πn−j中少了 j = i j=i j=i的一项,那么提前预处理好 T = Π n − j T=\Pi n-j T=Πn−j,每次分子 t = T n − i t=\dfrac{T}{n-i} t=n−iT;
- 对于任意 i i i,分母都是从 − 1 -1 −1开始依次递降的一段数相乘与从 1 1 1开始依次递增的一段数相乘,记录左右分别乘到了多少,每次乘上或除去即可。
- 注意 L = 1 L=1 L=1时要把 f ( 1 ) f(1) f(1)当成 2 2 2加上 2 k − 1 2^k-1 2k−1才是真正的答案。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000010
#define md 998244353
#define ll long long
ll a[N];
int K;
ll ksm(ll x, ll y) {
if(!y) return 1;
ll l = ksm(x, y / 2);
if(y % 2) return l * l % md * x % md;
return l * l % md;
}
ll solve(int x) {
if(x <= K + 2) return a[x];
if(!x) return 0;
ll ans = 0, t = 1, s = 1;
for(int i = 2; i <= K + 2; i++) s = s * (1 - i + md) % md;
for(int i = 1; i <= K + 2; i++) t = t * (x - i + md) % md;
ll s0 = 1, s1 = md - K - 1;
for(int i = 1; i <= K + 2; i++) {
ans = (ans + a[i] * t % md * ksm(s * (x - i) % md, md - 2) % md) % md;
s = s * ksm(s1, md - 2) % md * s0 % md;
s0++, s1++;
}
return ans;
}
int main() {
int i, l, r;
scanf("%d%d%d", &l, &r, &K);
for(i = 1; i <= K + 2; i++) a[i] = (a[i - 1] + ksm(i, K)) % md;
printf("%lld", (solve(r) - solve(l - 1) + md + (l == 1) * (ksm(2, K) - 1)) % md);
return 0;
}
哈哈哈哈哈哈哈哈哈哈

浙公网安备 33010602011771号