zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    linux权限及ntfs文件系统权限的知识
    传入字符串,计算字符串长度(用指针实现)
    第一话-简单工厂模式
    Java 多字段排序Comparator(兼容Date,Integer,Doubel,Long)
    关于退运美国转基因玉米含有MRI 162转基因成分的质疑
    Oracle Directory文件夹的知识
    ggplot ggplot2 画图
    Linux Shell文件差集
    linux ps aux 结果解释
    perl常用字符串函数
  • 原文地址:https://www.cnblogs.com/LZA119/p/14279496.html
Copyright © 2011-2022 走看看