首先注意到题目中 \(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. MySql 存储大量长字节 Text报错处理办法

    今天线上版本的错误: Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Row size too large ...

  2. 我的翻译--针对Outernet卫星信号的逆向工程

    前言 Outernet[1]是一家旨在让访问国际互联网更加方便自由的公司,他们使用卫星来广播维基百科或者其他网站.目前,他们的广播主要使用三颗国际海事卫星[3]的L波段[2],使其广播覆盖全球,大多数 ...

  3. C++11 新用法

    基于哈希的 map 和 set 简述 基于哈希的 map 和 set ,它们分别叫做 unordered_map, unordered_set .数据分布越平均,性能相较 map 和 set 来说提升 ...

  4. javascript当中的构造函数的用法

    5)构造函数的用法: 例 3.5.1 <head>    <meta http-equiv="content-type" content="text/h ...

  5. SpringBoot--SSM框架整合

    方式一 1 建立一个Spring Starter 2.在available中找到要用的包,配置mybatis 3.建立file,application.yml 文件 spring: datasourc ...

  6. Django | mysql修改个别表后save()报错

    报错内容: elasticsearch.exceptions.ConnectionError: ConnectionError(<urllib3.connection.HTTPConnectio ...

  7. CodeForces - 645 C.Enduring Exodus

    快乐二分 用前缀和随便搞一下 #include <cstdio> using namespace std; ; int p[N]; ; inline int msum(int a, int ...

  8. SQLserver各种时间取值格式

    叫大哥 SQLServer提取日期中的年月日及其他格式 SQLServer提取日期中的年月日及其他格式   提取年:datepart(yy,getdate())提取月:datepart(mm,getd ...

  9. JAVA 注解教程(二)元注解

    简介 元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面 元注解有 @Retention.@Documented.@Target.@Inherited.@Rep ...

  10. Tomcat创建项目

    查看项目信息 index.jsp默认首页 更新资源自动部署不用重启服务器,要用debug的方式启动 更新java代码和更新资源自动部署不用重启服务器,要用debug的方式启动