@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. 2019-8-31-dotnet-Framework-源代码-类库的意思

    title author date CreateTime categories dotnet Framework 源代码 类库的意思 lindexi 2019-08-31 16:55:58 +0800 ...

  2. 【CodeVS】2750 心系南方灾区

    2750 心系南方灾区 时间限制: 1 s 空间限制: 2000 KB 题目等级 : 青铜 Bronze 题目描述 Description 现在我国南方正在承受百年不遇的大雪.冻雨灾害.北京市已经开始 ...

  3. 洛谷P1774 最接近神的人_NOI导刊2010提高(02) [2017年6月计划 线段树03]

    P1774 最接近神的人_NOI导刊2010提高(02) 题目描述 破解了符文之语,小FF开启了通往地下的道路.当他走到最底层时,发现正前方有一扇巨石门,门上雕刻着一幅古代人进行某种活动的图案.而石门 ...

  4. Codeforces 1150E(树、线段树)

    要点 括号序列平衡度即树深度的性质 相当于中序遍历,则两点间最浅的地方即是LCA的性质 线段树维护\(d(a) + d(c) - 2*d(lca(a,c))\),一层层剥,思考维护这个量需要什么,结果 ...

  5. 【CRT相关配置】

    1.选项——会话选项 2.回话调整如下: 3.日志文件记录保存,即保存所有输入的命令 文件名:%S-%T-%M-%D.txt,表示每天会存放到一个文件 选择:在连接上启动记录 和  追加到文件

  6. Nginx 对访问量的控制

    目的 了解 Nginx 的 ngx_http_limit_conn_module 和 ngx_http_limit_req_module 模块,对请求访问量进行控制. Nginx 模块化 nginx ...

  7. Python 使用BeautifulSoup模块抽取数据

  8. delete records in table A not in table B

    转)A.B两表,找出ID字段中,存在A表,但是不存在B表的数据.A表总共13w数据,去重后大约3W条数据,B表有2W条数据,且B表的ID字段有索引. 方法一 使用 not in ,容易理解,效率低  ...

  9. C++:参数

    一.基础 实参是形参的初始值,对每个形参都需要穿一个能转换为它的实参 形参列表中的形参通常用逗号隔开,其中每个形参都含有一个声明符的声明 二.main(int argc, char *argv[]) ...

  10. NodeJS基础之Express路由和中间件

    路由 路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求. 路由是由一个 URI.HTTP 请求(GET.POST等)和若干个句柄组成,它的结构如下: app.method(path, [ ...