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,Rle 10^8 L,R108 k ≤ 1 0 6 kle 10^6 k106.

题解

  • x ≤ 2 xle 2 x2时, f ( x ) = x f(x)=x f(x)=x,因为一旦有 r ≤ x rle x rx x x x互质,则一定也有 x − r ≤ x x-rle x xrx 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=1Riki=1L1ik
  • 而任何 ∑ 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+1nk+1=...
  • n k + 1 − ( n − 1 ) k + 1 = . . . n^{k+1}-(n-1)^{k+1}=... nk+1(n1)k+1=...
  • . . . ... ...
  • 2 k + 1 − 1 k + 1 = . . . 2^{k+1}-1^{k+1}=... 2k+11k+1=...
  • 把所有式子相加,左边是 ( n + 1 ) k + 1 − 1 (n+1)^{k+1}-1 (n+1)k+11,右边的最高次是 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+11i=0k1aiSi来表示,故 S k S_k Sk可以用一个 k + 1 k+1 k+1次多项式表示。
  • 得证。
  • 现在要求的是 x = R x=R x=R x = L − 1 x=L-1 x=L1时的函数值,而 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_iPi_{j ot=i}dfrac{n-j}{i-j} Ansn=i=1k+2AnsiΠj=iijnj
  • 复杂度仍然是 k 2 k^2 k2的,可以简单优化。
  • 对于任意的 i i i,分子都是 Π n − j Pi n-j Πnj中少了 j = i j=i j=i的一项,那么提前预处理好 T = Π n − j T=Pi n-j T=Πnj,每次分子 t = T n − i t=dfrac{T}{n-i} t=niT
  • 对于任意 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 2k1才是真正的答案。

代码

#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;
}
原文地址:https://www.cnblogs.com/LZA119/p/14279496.html