@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. FreeMarker 对null值的处理技巧

    以下引用官方描述: ? The FreeMarker template language doesn't know the Java language null at all. It doesn't ...

  2. Elasticsearch入门学习重点笔记

    原文:Elasticsearch入门学习重点笔记 必记知识点 Elasticsearch可以接近实时的搜索和存储大量数据.Elasticsearch是一个近实时的搜索平台.这意味着当你导入一个文档并把 ...

  3. Linux监听的网络服务$ netstat -ntlp$ netstat -nulp$ netstat -nxlp

    我一般都分开运行这三个命令,不想一下子看到列出一大堆所有的服务.netstat -nalp倒也可以.不过我绝不会用 numeric 选项 (鄙人一点浅薄的看法:IP 地址看起来更方便). 找到所有正在 ...

  4. Leetcode617.Merge Two Binary Trees合并二叉树

    给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠. 你需要将他们合并为一个新的二叉树.合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 ...

  5. 将Factory-boy生成的复杂对象转成dict的方法

    最近在做接口测试,使用Factory-boy来生成接口对象实例,接着将对象转成dict,最后通过requests发送请求. 对象转成dict,目前知道的方法就是object.__dict__ .这个方 ...

  6. agc015F Kenus the Ancient Greek

    题意: 有$Q$次询问,每次给定$X_i$和$Y_i$,求对于$1\leq x \leq X_i , 1 \leq y \leq Y_i$,$(x,y)$进行辗转相除法的步数的最大值以及取到最大值的方 ...

  7. PHP配置环境中如何开启伪静态

    1.在httpd.conf中引入httpd-vhosts.conf 2.在httpd.conf中开启mod_rewrite.so 3.在httpd-vhosts.conf中配置虚拟主机 AllowOv ...

  8. Java.控制层.响应工具类.

    Java.控制层.响应工具类. package cn.com.spdbccc.cds.index.web.base; public class ApiResponse { private int co ...

  9. typeof与js数据类型

    js有6种数据类型有null.undefied.string.number.boolean.object. 然而我之前的[误区]: typeof的返回值和JS的数据类型是一样的.但是并不是(⊙o⊙)哦 ...

  10. 利用Eclipse进行远程Debug

    这项功能真的十分赞,当我不想写junit test,又想调试在实际环境中才能起作用的Java程序,远程debug真的是太好用了. 参数:java -jar -Xdebug -Xrunjdwp:tran ...