首先注意到题目中 \(a\) 数组是有序的,那我们只用算有序的方案乘上 \(n!\) 即可。

而此时的答案显然

\[Ans=[x^n](1+x)(1+2x)\dots (1+Ax)=\prod_{i=1}^A(1+ix)
\]

取对数把乘法变加法,即

\[\prod_{i=1}^A(1+ix)=\exp(\sum_{i=1}^A\ln(1+ix))
\]

这里有 \(\ln\) 的展开式

\[-\ln(1-x)=\sum_{i=1}^\infty\frac{x^i}{i}
\]

故有

\[\ln(1+ix)\\=\ln(1-(-ix))\\=-\sum_{k=1}^\infty \frac{(-ix)^k}{k}\\=\sum_{k=1}^\infty \frac{(-1)^{k+1}i^k}{k}x^k
\]

\[\sum_{i=1}^A \ln(1+ix)\\
=\sum_{k=1}^\infty \frac{(-1)^{k+1}\sum_{i=1}^Ai^k}{k}x^k
\]

自然数幂和可以用某种方法(插值、伯努利数之类)算出来。

最后还要多项式 exp,直接 \(O(n^2)\) 算。

#include<bits/stdc++.h>
using namespace std; typedef long long ll;
const int N = 505; int n, M, P, inv[N], Bo[N], C[N][N], a[N], b[N]; typedef vector<int> poly; poly F[N]; int calc(const poly&a, int x)
{
int y = 0;
for(int i = a.size() - 1; i >= 0; i --)
y = (1LL * y * x + a[i]) % P;
return y;
} int main()
{
scanf("%d%d%d",&M,&n,&P);
for(int i = 0; i <= n + 1; i ++)
{
C[i][0] = 1;
for(int j = 1; j <= i; j ++)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % P;
}
inv[1] = 1;
for(int i = 2; i <= n + 1; i ++)
inv[i] = (ll) inv[P % i] * (P - P / i) % P;
Bo[0] = 1;
for(int i = 1; i <= n; i ++)
{
int t = 0;
for(int j = 0; j < i; j ++)
t = (t + (ll)Bo[j] * C[i + 1][j]) % P;
Bo[i] = (ll)(P - inv[i + 1]) * t % P;
}
F[0] = poly{0, 1};
for(int i = 1; i <= n; i ++)
{
F[i].resize(i + 2);
for(int j = 1; j <= i + 1; j ++)
{
F[i][j] = (ll) Bo[i + 1 - j] * C[i + 1][j] % P * inv[i + 1] % P;
if((i + 1 - j) & 1)
F[i][j] = (P - F[i][j]) % P;
}
}
for(int i = 1; i <= n; i ++)
{
a[i] = (ll)inv[i] * calc(F[i], M) % P;
if(~i&1) a[i] = (P - a[i]) % P;
}
for(int i = 1; i <= n; i ++)
a[i - 1] = (ll)i * a[i] % P;
b[0] = 1;
for(int i = 1; i <= n; i ++)
{
for(int j = 0; j < i; j ++)
b[i] = (b[i] + (ll)b[j] * a[i - j - 1]) % P;
b[i] = (ll)b[i] * inv[i] % P;
}
int ans = b[n];
for(int i = 2; i <= n; i ++) ans = (ll)ans * i % P;
printf("%d", ans);
return 0;
}

注意到复杂度瓶颈在于对所有 \(k\in [1,n]\) 预处理自然数幂和。

这东西的EGF

\[\sum_{k=0}^\infty \sum_{i=0}^A i^k \frac{x^k}{k!}\\ =\sum_{i=0}^A \sum_{k=0}^\infty \frac{(ix)^k}{k!}\\ = \sum_{i=0}^A e^{ix}\\= \frac{e^{(A+1)x}-1}{e^x-1}
\]

多项式求逆即可,整个复杂度也是 \(O(nlogn)\)。

下面是模数 \(998244353\) 的代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<functional>
using namespace std; typedef long long ll;
const int N = 1 << 20 | 3, P = 998244353; int fpow(int a, int b)
{
ll x = 1, o = a;
for(; b; b >>= 1, o = o * o % P)
if(b & 1) x = x * o % P;
return x;
} int V, n, fac[N], ifac[N], inv[N], a[N], b[N], c[N]; namespace poly
{ int Len, sz, rev[N], w[N]; void prepare(int n)
{
for(Len = 1, sz = 0; Len <= n; Len <<= 1, sz ++);
for(int i = 0; i < Len; i ++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (sz - 1));
int wn = fpow(3, (P - 1) / Len);
w[Len / 2] = 1;
for(int i = Len / 2 + 1; i < Len; i ++)
w[i] = 1LL * w[i - 1] * wn % P;
for(int i = Len / 2 - 1; i >= 0; i --)
w[i] = w[i << 1];
} void DFT(int n, int *a, int T)
{
static unsigned long long F[N];
int shift = sz - __builtin_ctz(n), x;
for(int i = 0; i < n; i ++)
F[rev[i] >> shift] = a[i];
for(int l = 1; l < n; l <<= 1)
for(int i = 0; i < n; i += l << 1)
for(int j = 0; j < l; j ++)
{
x = F[i + j + l] * w[j + l] % P;
F[i + j + l] = F[i + j] + P - x;
F[i + j] += x;
}
for(int i = 0; i < n; i ++)
a[i] = F[i] % P;
if(T)
{
x = fpow(n, P - 2);
for(int i = 0; i < n; i ++)
a[i] = (ll) a[i] * x % P;
reverse(a + 1, a + n);
}
} void Inverse(int n, int *a, int *b)
{
if(n == 1)
{
*b = fpow(*a, P - 2);
return;
}
Inverse((n + 1) >> 1, a, b);
static int c[N], len;
for(len = 1; len < n << 1; len <<= 1);
for(int i = 0; i < len; i ++)
i < n ? c[i] = a[i] : c[i] = b[i] = 0;
DFT(len, b, 0);
DFT(len, c, 0);
for(int i = 0; i < len; i ++)
b[i] = 1LL * b[i] * (P + 2 - 1LL * b[i] * c[i] % P) % P;
DFT(len, b, 1);
for(int i = n; i < len; i ++) b[i] = 0;
} void Exp(int n, int *a, int *b)
{
static int c[N], d[N];
for(int i = 1; i < n; i ++)
c[i - 1] = (ll) a[i] * i % P;
c[n - 1] = 0;
for(int i = 0; i < n; i ++)
d[i] = 0;
function<void(int,int)> solve = [&](int l, int r)
{
if(l == r)
{
if(!l)
d[l] = 1;
else
d[l] = (ll)d[l] * inv[l] % P;
return;
}
int mid = (l + r) / 2;
solve(l, mid);
static int A[N], B[N];
int L = 1;
while(L <= r - l) L <<= 1;
memset(A, 0, L << 2);
memset(B, 0, L << 2);
memcpy(A, d + l, (mid - l + 1) << 2);
memcpy(B, c, (r - l) << 2);
DFT(L, A, 0);
DFT(L, B, 0);
for(int i = 0; i < L; i ++)
A[i] = (ll) A[i] * B[i] % P;
DFT(L, A, 1);
for(int i = mid + 1; i <= r; i ++)
d[i] = (d[i] + A[i - l - 1]) % P;
solve(mid + 1, r);
};
solve(0, n - 1);
memcpy(b, d, n << 2);
} } int main()
{
scanf("%d %d", &V, &n);
poly::prepare(n + n);
fac[0] = ifac[0] = 1;
for(int i = 1; i <= n + 1; i ++)
{
fac[i] = (ll)fac[i - 1] * i % P;
inv[i] = (i != 1 ?
(ll)inv[P % i] * (P - P / i) % P : 1);
ifac[i] = (ll)ifac[i - 1] * inv[i] % P;
}
// (e^x)^(V+1)-1 / e^x-1
for(int i = 0, e = V + 1; i <= n; i ++, e = 1LL * e * (V + 1) % P)
{
a[i] = 1LL * e * ifac[i + 1] % P;
b[i] = ifac[i + 1];
}
poly::Inverse(n + 1, b, c);
int L = poly::Len;
poly::DFT(L, a, 0);
poly::DFT(L, c, 0);
for(int i = 0; i != L; i ++) a[i] = 1LL * a[i] * c[i] % P;
poly::DFT(L, a, 1);
a[0] = 0;
for(int i = 1; i <= n; i ++)
{
a[i] = (ll)a[i] * fac[i] % P * inv[i] % P;
if((i + 1) & 1) a[i] = (P - a[i]) % P;
}
poly::Exp(n + 1, a, b);
for(int i = 1; i <= n; i ++)
printf("%d\n", int(1LL * b[i] * fac[i] % P));
return 0;
}

[洛谷P4463] calc (生成函数)的更多相关文章

  1. 洛谷 P4463 - [集训队互测 2012] calc(多项式)

    题面传送门 & 加强版题面传送门 竟然能独立做出 jxd 互测的题(及其加强版),震撼震撼(((故写题解以祭之 首先由于 \(a_1,a_2,\cdots,a_n\) 互不相同,故可以考虑求出 ...

  2. 洛谷P4841 城市规划 [生成函数,NTT]

    传送门 题意简述:求\(n​\)个点的简单无向连通图的数量\(\mod \;1004535809​\),\(n \leq 130000​\) 经典好题呀!这里介绍两种做法:多项式求逆.多项式求对数 先 ...

  3. 洛谷P4841 城市规划(生成函数 多项式求逆)

    题意 链接 Sol Orz yyb 一开始想的是直接设\(f_i\)表示\(i\)个点的无向联通图个数,枚举最后一个联通块转移,发现有一种情况转移不到... 正解是先设\(g(n)\)表示\(n\)个 ...

  4. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  5. 洛谷4451 整数的lqp拆分(生成函数)

    比较水的一题.居然是一道没看题解就会做的黑题…… 题目链接:洛谷 题目大意:定义一个长度为 $m$ 的正整数序列 $a$ 的价值为 $\prod f_{a_i}$.($f$ 是斐波那契数)对于每一个 ...

  6. 【洛谷5月月赛】玩游戏(NTT,生成函数)

    [洛谷5月月赛]玩游戏(NTT,生成函数) 题面 Luogu 题解 看一下要求的是什么东西 \((a_x+b_y)^i\)的期望.期望显然是所有答案和的平均数. 所以求出所有的答案就在乘一个逆元就好了 ...

  7. 洛谷 P6295 - 有标号 DAG 计数(生成函数+容斥+NTT)

    洛谷题面传送门 看到图计数的题就条件反射地认为是不可做题并点开了题解--实际上这题以我现在的水平还是有可能能独立解决的( 首先连通这个条件有点棘手,我们尝试把它去掉.考虑这题的套路,我们设 \(f_n ...

  8. 洛谷 P4548 - [CTSC2006]歌唱王国(概率生成函数)

    洛谷题面传送门 PGF 入门好题. 首先介绍一下 PGF 的基本概念.对于随机变量 \(X\),满足 \(X\) 的取值总是非负整数,我们即 \(P(v)\) 表示 \(X=v\) 的概率,那么我们定 ...

  9. 洛谷 P5853 - [USACO19DEC]Tree Depth P(生成函数+背包)

    洛谷题面传送门 神仙题. 首先考虑一个点的深度是什么,注意到对于笛卡尔树而言直接从序列的角度计算一个点的深度是不容易的,因为这样会牵扯到序列中多个元素,需要 fixed 的东西太多,计算起来太复杂了. ...

随机推荐

  1. 关于Oracle内存分配-解决实际运行时最大Session数不一致远小于系统配置最大的Session数目

    一.相关的技术准备 1. 关于内存的介绍:https://blog.csdn.net/u013641333/article/details/82732526 2. PGA_AGGREGATE_TARG ...

  2. 为什么要使用NoSQL数据库

    NoSQL概念 随着web2.0的快速发展,非关系型.分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性(原子性.一致性.隔离性.持久性,一个支持事务的数据库,必需要具有这四种特性,否则 ...

  3. Xlrd模块读取Excel文件数据

    Xlrd模块使用 excel文件样例:

  4. ubuntu 安装 lnmp 参考

    暂时参考 https://blog.csdn.net/weixin_36025897/article/details/81417458 https://www.jianshu.com/p/37cacd ...

  5. python接口自动化测试之根据excel中的期望结果是否存在于请求返回的响应值中来判断用例是否执行成功

    1.首先在excel中填写好预期结果的值 这里判断接口成功的依据是预期结果值是否存在于接口的返回数据中. 一般接口的返回值都是json对象,我们需要将json对象转换为json格式的字符串 如下图,进 ...

  6. itext操作表单域导出PDF,俗称扣模板

    /** * templateUrl 模板文件路径,包含文件名 * targetUrl 目标路径 * dateMap 填充数据 */public class CreatePdfUtil { public ...

  7. 7.Springboot之web开发

    自用 要解决的问题: 1.导入静态资源(html之类的(webapp)) 2.首页 3.没有写Jsp的地方-------->所以要学模板引擎Thymeleaf 4.装配扩展springmvc 5 ...

  8. g++运行c++程序提示main()找不到

    /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function `_start': (.text+0x20) ...

  9. 在已部署好的docker环境下配置nginx项目路径

    第一步:申请一个docker连接账号,可以借用putty工具,如果使用sublime,可以下载sftp插件,上传.下载来同步你线上线下的文件: 第二步:修改nginx区域配置文件,在conf文件夹里放 ...

  10. 新建表需要原表的数据,mysql 如何把查询到的结果插入到新表中

    项目运用情景:新建表需要原表的数据 1. 如果两张张表(导出表和目标表)的字段一致,并且希望插入全部数据,可以用这种方法: INSERT INTO  目标表  SELECT  * FROM  来源表 ...