@description@

给定 N 个整数 a1,a2,...,aN,定义函数 f 和 g:

f(x,k) = (x + a1)^k + (x + a2)^k +···+ (x + aN)^k

g(t,k) = f(0,k) + f(1,k) +···+ f(t,k)

给定整数 T 和 K,对于每个 0 ∼ K 之间的 i,请计算 g(T,i) 对 10^9 + 7 取模的结果。

输入格式

输入的第一行包含三个整数 N,K,T。第二行包含 N 个整数 a1,a2,...,aN。

输出格式

输出一行,包含 K + 1 个整数,代表 g(T,0),g(T,1),...,g(T,K) 对 10^9 + 7 取模的结果。

数据范围与子任务

• 1 ≤ N ≤ 10^5 • 1 ≤ K ≤ 5·10^4

• 1 ≤ T ≤ 10^18 • 0 ≤ ai < 10^9 + 7

样例输入

2 3 4

0 1

样例输出

10 25 85 325

@solution@

@part - 1@

先写式子:

\[g(T, k) = \sum_{i=0}^{T}f(i, k) = \sum_{i=0}^{T}\sum_{j=1}^{N}(i + a_j)^k = \sum_{i=0}^{T}\sum_{j=1}^{N}\sum_{p=0}^{k}C_k^p*i^p*a_j^{k-p}
\]

通过将组合数拆成阶乘形式,并作适当地变形,可以得到:

\[g(T, k) = k!*\sum_{p=0}^{k}((\frac{\sum_{i=0}^{T}i^p}{p!})*(\frac{\sum_{j=1}^{N}a_j^{k-p}}{(k-p)!}))
\]

令 \(P(x) = \frac{\sum_{i=0}^{T}i^x}{x!}, Q(x) = \frac{\sum_{i=1}^{N}a_i^x}{x!}\),则有 \(g(T, k) = k!*\sum_{p=0}^{k}P(p)*Q(k-p)\)。

显然是一个卷积,可以使用 fft(但是这里因为模数的原因,要使用神奇的 mtt)。

我们接下来的问题转为求解 P 和 Q。

@part - 2@

先考虑 P,发现它是一个很裸的自然数幂和,可以使用伯努利数求解。

所以以下介绍使用伯努利数求解自然数幂和的过程,熟悉的人可以直接跳过。

虽然以前写过一点,不过感觉不大详细。

记 \(S(n, k) = \sum_{i=0}^{n}i^k\)。先考虑一种使用裂项相消求解自然数幂和的方法:

首先由二项式定理得到 \((n+1)^{k+1} - n^{k+1} = \sum_{i=0}^{k}C_{k+1}^{i}*n^i\)。

于是:

\[\sum_{i=0}^{n}((i+1)^{k+1} - i^{k+1}) = \sum_{i=0}^{n}\sum_{j=0}^{k}C_{k+1}^{j}*i^j
\]

\[(n+1)^{k+1} = \sum_{j=0}^{k}C_{k+1}^{j}*S(n, j)
\]

\[\frac{(n+1)^{k+1}}{(k+1)!} = \sum_{j=0}^{k}\frac{S(n, j)}{j!}*\frac{1}{(k+1-j)!}
\]

这个式子感觉非常卷积,而且感觉非常指数型生成函数,所以我们就往这个方向思考。

令 \(F_n(x) = \sum_{i=0}\frac{S(n, k)}{k!}x^k\),即 S(n, k) 的指数型生成函数。

则有:\(e^{(n+1)x} - 1 = (e^x - 1)*F_n\),于是就有 \(F_n = \frac{e^{(n+1)x} - 1}{e^x - 1}\)。

因为 \(e^x - 1\) 的常数项为 0,使用牛顿迭代找不出逆元,所以我们可以找 \(\frac{e^x - 1}{x}\) 的逆元(即伯努利数的生成函数)。

于是:

\[F_n = \frac{e^{(n+1)x} - 1}{x}*\frac{x}{e^x - 1} = (\sum_{i=0}\frac{(n+1)^{i+1}}{(i+1)!}*x^i)*(\frac{1}{\sum_{i=0}\frac{1}{(i+1)!}*x^i})
\]

写一个多项式求逆即可。一样,因为模数原因要使用 mtt。

@part - 3@

考虑怎么求解 Q。这应该算是本题最关键的部分。

我们令 R(x) 表示从序列 a 中不重复地选出 x 个数相乘的结果之和。或者说,R 是多项式 \(\prod_{i=1}^{N}(a_i + 1)\) 的系数。

可以使用分治 fft 简单地求出 R。

通过容斥可以求出 Q(x) 的递推式:

\[Q(x) = \sum_{i=1}^{x-1}(-1)^{i-1}*Q(x-i)*R(i) + (-1)^{x-1}*R(x)*x
\]

怎么理解呢?

首先:

\[Q(x-1)*R(1) = \sum_{i=1}^{N}a_i^x + \sum_{i=1}^{N}\sum_{j=1,i\not =j}^{N}a_i^{x-1}*a_j
\]

前一半是我们需要的,后一半是我们想要容斥掉的。

然后:

\[Q(x-2)*R(2) = \sum_{i=1}^{N}\sum_{j=1,i\not =j}^{N}a_i^{x-1}*a_j + \sum_{i=1}^{N}\sum_{j=1,i\not =j}^{N}\sum_{k=1,i\not =k,j\not =k}^{N}a_i^{x-2}*a_j*a_k
\]

同上面一样,前一半是我们想要的,后一半是我们想要容斥掉的。

于是容斥到最后,所有 ai 的指数都为 1 时(不难发现此时项数为 x),可以发现一组 (ai, aj, ak, ...) 的贡献被重复计算了 x 次(在每一项都被计算了一次)。

于是在最后消掉这些贡献即可,即 \((-1)^{x-1}*R(x)*x\) 一项的含义。

怎么想出来的呢?我怎么知道,这是人类的智慧。

然后就是套路一般的生成函数了。

令 \(G(x) = \sum_{i=1}(-1)^{i-1}*R(i)*x^i, H(x) = \sum_{i=1}(-1)^{i-1}*R(i)*i*x^i\)。

则 \(Q = Q*G + H\),于是 \(Q = \frac{H}{1-G}\)。

要考虑 Q 的边界情况,即 \(a_1^0 + a_2^0 + ... + a_N^0\) 的情况。

@accepted code@

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
typedef long double ld;
struct complex{
ld r, i;
complex(ld _r=0, ld _i=0):r(_r), i(_i) {}
friend complex operator + (complex a, complex b) {
return complex(a.r + b.r, a.i + b.i);
}
friend complex operator - (complex a, complex b) {
return complex(a.r - b.r, a.i - b.i);
}
friend complex operator * (complex a, complex b) {
return complex(a.r*b.r - a.i*b.i, a.i*b.r + b.i*a.r);
}
friend complex operator / (complex a, ld k) {
return complex(a.r / k, a.i / k);
}
friend complex conj(complex a) {
return complex(a.r, -a.i);
}
};
typedef complex comp;
const int MAXN = 200000;
const int MOD = int(1E9) + 7;
const int SQ = sqrt(MOD);
const ld PI = acos(-1);
int pow_mod(int b, int p) {
int ret = 1;
while( p ) {
if( p & 1 ) ret = 1LL*ret*b%MOD;
b = 1LL*b*b%MOD;
p >>= 1;
}
return ret;
}
struct poly{
comp w[20];
poly() {
for(int i=0;i<20;i++)
w[i] = comp(cos(2*PI/(1<<i)), sin(2*PI/(1<<i)));
}
void clear(comp *A, int l, int r) {
for(int i=l;i<r;i++)
A[i] = comp(0, 0);
}
void copy(comp *A, comp *B, int n) {
for(int i=0;i<n;i++)
A[i] = B[i];
}
void debug(comp *A, int n) {
for(int i=0;i<n;i++)
cout << A[i].r << " " << A[i].i << endl;
puts("");
}
void debug(int *A, int n) {
for(int i=0;i<n;i++)
cout << A[i] << endl;
puts("");
}
int length(int n) {
int len; for(len = 1; len < n; len <<= 1) ;
return len;
}
void fft(comp *A, int n, int type) {
for(int i=0,j=0;i<n;i++) {
if( i < j ) swap(A[i], A[j]);
for(int k=(n>>1);(j^=k)<k;k>>=1);
}
for(int i=1;(1<<i)<=n;i++) {
int s = (1<<i), t = (s>>1);
comp u = comp(w[i].r, type*w[i].i);
for(int j=0;j<n;j+=s) {
comp p = complex(1, 0);
for(int k=0;k<t;k++,p=p*u) {
comp x = A[j+k], y = p*A[j+k+t];
A[j+k] = x + y, A[j+k+t] = x - y;
}
}
}
if( type == -1 ) {
for(int i=0;i<n;i++)
A[i] = A[i] / n;
}
}
comp tmp2[MAXN + 5], tmp3[MAXN + 5];
void poly_mul(int *A, int *B, int *C, int n, int m, int k) {
int len = length(n + m - 1);
clear(tmp2, 0, len), clear(tmp3, 0, len);
for(int i=0;i<n;i++) tmp2[i] = comp(A[i]/SQ, A[i]%SQ);
for(int i=0;i<m;i++) tmp3[i] = comp(B[i]/SQ, B[i]%SQ);
fft(tmp2, len, 1), fft(tmp3, len, 1);
for(int i=0;i<=len/2;i++) {
comp x0 = tmp2[i], y0 = tmp2[(len-i)%len];
comp x1 = tmp3[i], y1 = tmp3[(len-i)%len];
comp a0 = (x0 + conj(y0))/2, a1 = (conj(y0) - x0)/2*comp(0, 1);
comp b0 = (x1 + conj(y1))/2, b1 = (conj(y1) - x1)/2*comp(0, 1);
tmp2[i] = a0*b0 + comp(0, 1)*a1*b1, tmp3[i] = a0*b1 + a1*b0;
a0 = (y0 + conj(x0))/2, a1 = (conj(x0) - y0)/2*comp(0, 1);
b0 = (y1 + conj(x1))/2, b1 = (conj(x1) - y1)/2*comp(0, 1);
tmp2[(len-i)%len] = a0*b0 + comp(0, 1)*a1*b1, tmp3[(len-i)%len] = a0*b1 + a1*b0;
}
fft(tmp2, len, -1), fft(tmp3, len, -1);
for(int i=0;i<len;i++)
C[i] = (ll(tmp2[i].r+0.5)%MOD*SQ%MOD*SQ%MOD + ll(tmp3[i].r+0.5)%MOD*SQ%MOD + ll(tmp2[i].i+0.5)%MOD)%MOD;
}
int tmp1[MAXN + 5];
void poly_inv(int *A, int *B, int n) {
if( n == 1 ) {
B[0] = pow_mod(A[0], MOD - 2);
return ;
}
poly_inv(A, B, (n + 1) >> 1);
poly_mul(A, B, tmp1, n, (n+1)>>1, n);
for(int i=0;i<n;i++)
tmp1[i] = (MOD - tmp1[i])%MOD;
tmp1[0] = (tmp1[0] + 2)%MOD;
poly_mul(tmp1, B, B, n, (n+1)>>1, n);
}
}oper;
int fct[MAXN + 5], ifct[MAXN + 5];
void init() {
fct[0] = 1;
for(int i=1;i<=MAXN;i++)
fct[i] = 1LL*fct[i-1]*i%MOD;
ifct[MAXN] = pow_mod(fct[MAXN], MOD-2);
for(int i=MAXN-1;i>=0;i--)
ifct[i] = 1LL*ifct[i+1]*(i+1)%MOD;
}
int a[MAXN + 5], N, K; ll T;
int f[MAXN + 5], B[MAXN + 5], tmp[MAXN + 5];
void func1() {
for(int i=0;i<K;i++)
tmp[i] = ifct[i+1];
oper.poly_inv(tmp, B, K);
for(int i=0,p=T;i<K;i++,p=1LL*p*T%MOD)
tmp[i] = 1LL*p*ifct[i+1]%MOD;
oper.poly_mul(tmp, B, f, K, K, K);
}
int g[MAXN + 5], h[MAXN + 5], hl[20][MAXN + 5], hr[20][MAXN + 5];
void func3(int le, int ri, int dep, int *A) {
if( le + 1 == ri ) {
A[0] = 1, A[1] = a[le];
return ;
}
int mid = (le + ri) >> 1;
func3(le, mid, dep + 1, &hl[dep][le]);
func3(mid, ri, dep + 1, &hr[dep][le]);
oper.poly_mul(&hl[dep][le], &hr[dep][le], A, mid-le+1, ri-mid+1, ri-le+1);
}
void func2() {
func3(0, N, 0, h);
for(int i=0,f=1;i<K;i++,f=1LL*f*(MOD-1)%MOD)
h[i] = 1LL*f*h[i]%MOD;
oper.poly_inv(h, g, K);
for(int i=0;i<K;i++)
h[i] = 1LL*(MOD-1)*h[i]%MOD*i%MOD;
oper.poly_mul(h, g, g, K, K, K);
g[0] = N;
for(int i=0;i<K;i++)
g[i] = 1LL*g[i]*ifct[i]%MOD;
}
int ans[MAXN + 5];
int main() {
init();
scanf("%d%d%lld", &N, &K, &T), K++, T++, T %= MOD;
for(int i=0;i<N;i++)
scanf("%d", &a[i]);
func1(); func2(); oper.poly_mul(f, g, ans, K, K, K);
for(int i=0;i<K;i++)
printf("%lld\n", 1LL*fct[i]*ans[i]%MOD);
}

@details@

因为 fft 时我们需要的是 2 的幂的长度,如果不另外建 temp 来存储而是直接在原数组上存的话,需要注意两个数组之间不会互相影响。

所以我也不知道为什么我不建个temp就好了

@codechef - SERSUM@ Series Sum的更多相关文章

  1. MOOCULUS微积分-2: 数列与级数学习笔记 3. Convergence tests

    此课程(MOOCULUS-2 "Sequences and Series")由Ohio State University于2014年在Coursera平台讲授. PDF格式教材下载 ...

  2. 8--Python入门--函数

    函数基本框架如下([]中的内容表示是或选的,可以不写):def 函数名(参数): ['''函数说明文档'''] 函数主体 [return 返回对象] 函数小例子 #我们先定义一个函数 def find ...

  3. Pandas v0.23.4手册汉化

    Pandas手册汉化 此页面概述了所有公共pandas对象,函数和方法.pandas.*命名空间中公开的所有类和函数都是公共的. 一些子包是公共的,其中包括pandas.errors, pandas. ...

  4. Python数据科学手册-Pandas:累计与分组

    简单累计功能 Series sum() 返回一个 统计值 DataFrame sum.默认对每列进行统计 设置axis参数,对每一行 进行统计 describe()可以计算每一列的若干常用统计值. 获 ...

  5. Sum of AP series——AP系列之和

    A series with same common difference is known as arithmetic series. The first term of series is 'a' ...

  6. 深入理解无穷级数和的定义(the sum of the series)

    Given an infinite sequence (a1, a2, a3, ...), a series is informally the form of adding all those te ...

  7. codewars-7kyu:Sum of the first nth term of Series

    Task: Your task is to write a function which returns the sum of following series upto nth term(param ...

  8. CodeChef Sum of distances(分治)

    CodeChef Sum of distances(分治) 题目大意 有一排点,每个点 i 向 \(i + 1, i + 2, i + 3\) 分别连价值为 \(a_i,b_i,c_i\) 的有向边, ...

  9. [LeetCode] #112 #113 #437 Path Sum Series

    首先要说明二叉树的问题就是用递归来做,基本没有其他方法,因为这数据结构基本只能用递归遍历,不要把事情想复杂了. #112 Path Sum 原题链接:https://leetcode.com/prob ...

随机推荐

  1. IO流10 --- 缓冲流(字节型)实现非文本文件的复制 --- 技术搬运工(尚硅谷)

    字节型缓冲流,BufferedOutputStream默认缓冲区大小 8192字节byte,满了自动flush() @Test public void test6(){ File srcFile = ...

  2. 2019-10-18-WPF-解决-StylusPlugIn-点击穿透问题

    title author date CreateTime categories WPF 解决 StylusPlugIn 点击穿透问题 lindexi 2019-10-18 20:55:35 +0800 ...

  3. js中index()的四种经典用法111

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. Django用户登陆以及跳转后台管理页面2

    请先写好以下,再来替换文件 Django用户登陆以及跳转后台管理页面1http://www.cnblogs.com/ujq3/p/7891774.html from django.shortcuts ...

  5. SQL Server导入数据报错"无法在只读列“Id”中插入数据"

    使用sql server 导入数据报错:无法在只读列'id'中插入数据.如下图所示: 查找出现该问题的原因是表中id为自动增长的标识列,需要在[编辑映射]中勾选"启用标识插入": ...

  6. laravel-admin 安装(总结)

    https://www.jianshu.com/p/844b05e4c45a laravel-admin 是一个可以快速帮你构建后台管理的工具,它提供的页面组件和表单元素等功能,能帮助你使用很少的代码 ...

  7. Latex 出现编辑公式,出现错误 !pdfTex error: Font rntxmi7 at 438 not found

    http://docs.miktex.org/manual/advanced.html http://www.cl-projects.de/projects/misc/miktex-fonts.pht ...

  8. vue常用操作及学习笔记(路由跳转及路由传参篇)

    路由跳转 - 超链接方式跳转 html: <div id="app"> <h1>Hello App!</h1> <p> <!- ...

  9. java 操作CLOB类型数据

    clob类型,但对于这个类型处理起来还是比较麻烦的,varchar2长度为4000bytes,如果varchar2能满足楼主的需求,建议使用varchar2,下面提供了在Java 中读取clob类型的 ...

  10. python正则表达式应用 重组分词