首先注意到题目中 \(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. hadoop 部署在centos 7 上

    一.准备工作  (文章写于 2019-6) 根据官方文档而来,请注意时间,官方可能有更新,以官方文档为准 1. 配置网站参考: http://hadoop.apache.org/docs/r1.0.4 ...

  2. javaScript(Date与Math的API)

    目录 Math Math的两个属性值 E PI abs(); ceil(); floor(); round(); max(); min (); pow(); random sin(); cos(); ...

  3. Java selenium下拉滚动页面

    Selenium强大之处在于,可以操作模拟键盘和点击页面的任何结构,本文对于Selenium的视图滚动操作方法进行解释. 1.可以滑动页面到最底端: //设置本地ChromDrive驱动路径,改成你自 ...

  4. 题解【AcWing176】装满的油箱

    题面 一开始拿到这个问题并不好做,于是考虑拆点. 考虑将一个点拆成 \(c+1\) 个,每个点表示(编号,剩余油量). 然后 \(\text{Dijkstra}\) 最短路即可. 每次跑 \(\tex ...

  5. 题解【洛谷P1352】没有上司的舞会

    题面 题解 树形\(\text{DP}\)入门题. 我们设\(dp[i][0/1]\)表示第\(i\)个节点选\(/\)不选的最大快乐指数. 状态转移方程: \(dp[i][0]=a[i]+\sum_ ...

  6. linq和匿名方法、委托、匿名委托、lambda

    委托相当于JavaScript中的闭包,c++中的函数指针. c#为了引进这个函数指针,将其进行包装成“委托”,同时将非托管的变成托管的. 1.最初的委托该怎么用 弊端:写的代码量过多,还要写一个显示 ...

  7. python面试的100题(3)

    3.输入日期, 判断这一天是这一年的第几天? import datetime def dayofyear(): year = input("请输入年份: ") month = in ...

  8. HTML的列表标签和表格标签

    网页的列表和表格 列表的分类 无序列表 有序列表 自定义列表 有序列表 <!--有序列表--><ol>    <li>辽宁</li>    <li ...

  9. 2.10 webdriver中 js 使用

    来源: 使用Webdriver执行JS小结  http://lijingshou.iteye.com/blog/2018929 selenium常用的js总结  http://www.cnblogs. ...

  10. python 操作 word 图片 消失

    问题描述修改word中文本,如下代码,保存时会导致word中的部分图片消失 from docx import Document path1 = 'test_in.docx' path2 = 'test ...