[题解] CF622F The Sum of the k-th Powers

CF622F The Sum of the k-th Powers

题意:给\(n\)和\(k\),让你求\(\sum\limits_{i = 1} ^ n i^k \ mod \ 10^9 + 7\)。\((1 \le n \le 10^9,0 \le k \le 10^6)\)



好,我们先不看题,来补一些数学。

考虑这样一个序列
\[
h_0,h_1,\dots,h_n,\dots
\]
我们定义它的一个差分序列(一阶)
\[
\Delta h_0, \Delta h_1, \dots , \Delta h_n, \dots
\]

满足\(\Delta h_n = h_{n+1} - h_n \ (n \ge 0)\),换句话说(一阶)差分序列就是原序列相邻两项的差。

同样的,我们还能在原序列的一阶差分序列上再做一次差分,得到二阶差分序列
\[
\Delta(\Delta h_0), \Delta(\Delta h_1),\dots , \Delta(\Delta h_n), \dots
\]
可以把前面的\(\Delta\)写成\(\Delta ^2\),就是\(\Delta^2 h_0, \Delta^2 h_1,\dots , \Delta^2 h_n, \dots\)

根据定义,有\(\Delta^2 h_n = \Delta(\Delta h_n) = \Delta h_{n+1} - \Delta h_n\)

推广一下,我们还能得到原序列的\(p\)阶差分序列
\[
\Delta^p h_0, \Delta^p h_1, \dots , \Delta^p h_n, \dots
\]
其中\(\Delta^p h_n = \Delta(\Delta^{p-1} h_n) = \Delta^{p-1} h_{n+1} - \Delta^{p-1} h_n\)。

特别的\(p = 0\)时,\(\Delta^0 h_n = h_n\)。

其中,\(p\)阶差分在第\(p\)行上(从第\(0\)行开始)。

考虑一个序列\(h\),通项是一个关于\(n\)的\(p\)次多项式,即\(h_n = a_{p}n^{p} + a_{p-1}n^{p-1} + \cdots + a_0n^0\)。

那么这个序列的一阶差分$\Delta h $通项就变为了
\[
\begin{aligned}\Delta h_n &= h_{n+1} - h_{n} \\&= (a_p (n+1)^p + a_{p-1} (n+1)^{p-1} + \cdots + a_0 (n+1)^0) - (a_pn^p + a_{p-1}n^{p-1} + \cdots + a_0 n^0)\end{aligned}
\]
观察$ \Delta h_n\(的\)p\(次项:\)a_p(n+1)^p - a_p n^p\(,把\)(n+1)^p$用二项式定理展开后
\[
\begin{aligned}a_p(n+1)^p - a_p n^p &= a_p(n^p + \binom{p}{1} n^{p-1} + \binom{p}{2}n^{p-2} + \cdots + 1) - a_pn^p\end{aligned}
\]
发现了什么?\(n^p\)和\(n^p\)刚好抵消!即
\[
a_p(n+1)^p - a_p n^p = \binom{p}{1} a_pn^{p-1} + \binom{p}{2}a_pn^{p-2} + \cdots + 1
\]
换句话说,每做一次差分,原序列的通项多项式的次数至少会减少\(1\)



好了来看题吧。

题目让我们求\(\sum\limits_{i = 1} ^ n i^k\),我们不妨设\(h_n = \sum\limits_{i = 1} ^ n i^k\),那把这样的序列\(h\),做一次差分得到的\(\Delta h\)长啥样呢?

根据定义\(\Delta h_n = h_{n+1} - h_{n} = \sum\limits_{i = 1}^{n+1} i^k - \sum\limits_{i = 1}^{n} i^k = (n+1)^k\)。显然他的差分序列的通项是一个\(k\)次多项式,那么\(h_n\)就是一个\(k+1\)次多项式。

我们不设\(h\)序列的通项是一个\(k+1\)次多项式\(f(x)\),满足\(f(n) = \sum\limits_{i = 1}^{n} i^{k}\),现在我们要求\(f(n)\)(这里是题目的\(n\),上面懒得改了。。。)

观察到\(k\)只有\(10^6\),所以我们可以算出\(f(1), f(2), f(3), \cdots, f(k+2)\),然后拉格朗日差值求出\(f(n)\)就可以了。

但拉格朗日的复杂度是\(O(k^2)\)的。。。还要加一些优化。

我们有公式
\[
f(x) = \sum\limits_{i = 1}^{k+2} y_i \prod\limits_{j \not= i} \frac{x - x_j}{x_i - x_j}
\]
(这里的\(x_i = i, y_i = f(x_i)\))。

考虑化简后面的乘法。

我们先看分母。\(\prod\limits_{j \not= i} \frac{1}{x_i - x_j}\)这个显然是\((-1)^{k+2-i} \frac{1}{(i-1)!(k+2-i)!}\),(后半段是\(-1,-2,...,-(k+2-i)\)的积,直接把\(-1\)提到前面就好了)题目说了对\(10^9 + 7\)取模,预处理阶乘逆元就好了。

分子\(\prod\limits_{j \not= i} x - x_j\)。写开来后就是\((x-1)(x-2)(x-3)\cdots(x-(i-1)) \cdot (x-(k+2))(x-(k+1))\cdots(x-(i+1))\)。

维护两个数组\(pre[i] = (x-1)(x-2)(x-3)\cdots(x-i),suf[i]=(x-(k+2))(x-(k+1))\cdots(x-i)\)就好了。

前面\(y_i\)的话可以在枚举\(i\)的时候带着算,用快速幂。

总复杂度\(O(k \ log \ k)\)(快速幂还要\(log\)啊。。。)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int P=1e9+7;
const int N=1e6+10;
void update(int &x,int y){
    x+=y; if (x>=P) x-=P;
}
int fpow(int a,int b){
    int ret=1; for (;b;b>>=1,a=1ll*a*a%P) if (b&1)ret=1ll*ret*a%P;
    return ret;
}
#define normal(x) (((x)%P+P)%P)
int pre[N],suf[N],ifac[N],inv[N];
int main(){
    int n,K; scanf("%d%d",&n,&K);
    if (K==0){printf("%d\n",n);return 0;} // 特判一下吧,很稳。
    ifac[0]=1,inv[1]=1,ifac[1]=1; // 阶乘的定义,注意0!=1
    for (int i=2;i<=K+2;i++){
        inv[i]=1ll*inv[P%i]*(P-P/i)%P;
        ifac[i]=1ll*ifac[i-1]*inv[i]%P;
    }
    pre[0]=1; // 特殊处理i==0的时候
    for (int i=1;i<=K+2;i++) pre[i]=1ll*pre[i-1]*normal(n-i)%P;
    suf[K+3]=1; // 同上,特殊对待
    for (int i=K+2;i>=0;i--) suf[i]=1ll*suf[i+1]*normal(n-i)%P;
    int yi=0,ans=0; for (int i=1;i<=K+2;i++){
        update(yi,fpow(i,K));
        ll tmp=1ll*yi*ifac[i-1]%P*ifac[K+2-i]%P*pre[i-1]%P*suf[i+1]%P;
        if ((K+2-i)%2==0) update(ans,tmp); else update(ans,P-tmp);
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/wxq1229/p/12233878.html

时间: 2024-08-30 18:31:03

[题解] CF622F The Sum of the k-th Powers的相关文章

leetcode 862 shorest subarray with sum at least K

https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/ 首先回顾一下求max子数组的值的方法是:记录一个前缀min值,然后扫一遍sum数组. 1.首先这里不需要最大,因为刚好够k就好了 2.这里需要距离最短.就是数组的长度最短. 这里的思路也一样,不过保存很多个min值,就是用一个队列,保存前缀的min值,不需要最min,只不过有更小的就更好. 也就是如果sum数组的值是: ..... 60, 40.....Y..

862. Shortest Subarray with Sum at Least K

Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K. If there is no non-empty subarray with sum at least K, return -1. Example 1: Input: A = [1], K = 1 Output: 1 Example 2: Input: A = [1,2], K = 4 Output: -1 Exa

[Swift]LeetCode862. 和至少为 K 的最短子数组 | Shortest Subarray with Sum at Least K

Return the length of the shortest, non-empty, contiguous subarray of A with sum at least K. If there is no non-empty subarray with sum at least K, return -1. Example 1: Input: A = [1], K = 1 Output: 1 Example 2: Input: A = [1,2], K = 4 Output: -1 Exa

lc 862. Shortest Subarray with Sum at Least K

断网导致原来写的那么多答案全没了,博客园能不能实时保存草稿,醉. https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/ 给一个数组a,找和大于k的所有子数组中的最短的那个. 最近二分有点上头,因为的确很强大,两个考虑二分的情况(其实需要刻意去想想能不能使用二分才会想到,这会是个好习惯): 1.最优问题变判断问题.比如:行递增列递增的矩阵中找某个元素->行递增列递增的矩阵中找第k大元素 2.有相应的简单孪生问题.比

CF622F:The Sum of the k-th Powers

CF622F:The Sum of the k-th Powers 题意: 求\(\sum_{i=1}^ni^k\),结果模\(1e9+7\). 思路: 拉格朗日插值法. 看大部分题解发现说是\(\sum_{i=1}^ni^k\)是一个\(k+1\)次多项式,可是我实在是看不出来,所以接下来证明一下. 首先看一个等差数列: \(1,2,3,...,n\). 之后做差分操作: \(2-1,3-2,...,n-(n-1)\). \(1,1,1,...,1\). 对于这样一个数列,我们称之为常数数列.

LeetCode 1099. Two Sum Less Than K

原题链接在这里:https://leetcode.com/problems/two-sum-less-than-k/ 题目: Given an array A of integers and integer K, return the maximum S such that there exists i < j with A[i] + A[j] = S and S < K. If no i, jexist satisfying this equation, return -1. Example

[LC] 1099. Two Sum Less Than K

Given an array A of integers and integer K, return the maximum S such that there exists i < j with A[i] + A[j] = S and S < K. If no i, j exist satisfying this equation, return -1. Example 1: Input: A = [34,23,1,24,75,33,54,8], K = 60 Output: 58 Expl

题解 CF920F 【SUM and REPLACE】

可以事先打表观察每个数的约数个数,观察到如果进行替换,若干次后这个数便会被替换成1. 所以我们可以直接暴力的进行区间修改,若这个数已经到达1或2,则以后就不再修改,用并查集和树状数组进行维护. 这个方法用了P2391 白雪皑皑的思想处理,用并查集标记该点已经不再用替换. code: #include<bits/stdc++.h> #include<cctype> #define maxn 300010 #define lowbit(x) (x&(-x)) typedef l

[LeetCode]题解(python):023-Merge k Sorted Lists

题目来源: https://leetcode.com/problems/merge-k-sorted-lists/ 题意分析: 给定k个有序的链表,将这些链表整合成一个新的有序链表. 题目思路: 前面我们已经给出了两个有序链表整合的做法.这里,我们不妨用归并排序的想法,把n个链表看成 n/2 和n - n/2的整合,直到n/2 <= 1.时间复杂度是 O(n * (2^log k)) = O(n * k). 代码(python): 1 # Definition for singly-linked