专题:数学

欧拉函数

定义

\[\varphi(n) = \sum_{i = 1}^n [(i, n) = 1] \]

公式

对于所有质数,显然有 \(\phi(n) = n - 1\)

对于 \(n = p_1^{a_1}p_2^{a_2}\cdots p_k^{a_k}\)

\[\phi(n) = n(1 - \dfrac{1}{p_1})(1 - \dfrac{1}{p_2})\cdots(1 - \dfrac{1}{p_k}) \]

证明

  • 如何求 \(p_i \mid x\) 的个数?\(\lfloor \dfrac{n}{p_i} \rfloor\)
  • 是否 \(\phi(n) = \sum \lfloor \dfrac{n}{p_i} \rfloor\)?重复计算了 \(p_1p_2 \mid x\) 的数量。
    因此,我们对上式做一个容斥,得到

\[\begin{aligned} \phi(n) &= \sum\limits_{i = 0}^n (-1)^i \sum\limits_{1 \le j_1 < j_2 < \dots < j_i \le k} \lfloor \dfrac{n}{p_{j_1}p_{j_2} \cdots p_{j_i}} \rfloor \\ &= n(1 - \dfrac{1}{p_1})(1 - \dfrac{1}{p_2}) \ldots (1 - \dfrac{1}{p_k}) \\ &= \prod p_i^{a_i - 1}(p_i - 1) \end{aligned} \]

\(O(\sqrt n)\) 内求 \(\phi(n)\)

将质因数分解的过程与求 \(\phi\) 结合,直接套用公式。
结束循环时,\(n\) 一定是一个大于 \(\sqrt n\) 的质数,指数不可能超过 \(1\),因此直接乘 \(n - 1\)

ll get_phi(ll n) {
	ll phi = 1;
	for(int i = 2; i <= n / i; ++ i) {
		if(n % i == 0) {
			phi *= (i - 1);
			n /= i;
			while(n % i == 0) n /= i, phi *= i;	
		}
	}
	if(n > 1) phi *= (n - 1);
	return phi;
}

\(O(n)\)\([1, n]\) 的欧拉函数

与欧拉筛相结合。
任意 \(n = p_1^{\alpha_1} \times p_2^{\alpha_2} \ldots \times p_k^{\alpha_k}\),只会被 \(i = p_1^{\alpha_1 - 1} \times p_2^{\alpha_2} \ldots \times p_k^{\alpha_k}\)\(p_1\) 筛到。

  • \(p_1 > 1\)\(\phi(n) = \phi(i) \times p_1\)
  • \(p_1 = 1\)\(\phi(n) = \phi(i) \times (p_1 - 1)\)
int not_prime[N], prime[N], idx, phi[N];

void get_phi(int n) {
    phi[1] = 1;
	for(int i = 2; i <= n; ++ i) {
		if(!not_prime[i]) prime[++ idx] = i, phi[i] = i - 1;
		for(int j = 1; j <= idx && prime[j] * i <= n; ++ j) {
			not_prime[prime[j] * i] = 1;
			if(i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * (prime[j] - 1);		
		}
	}
}


欧拉定理

  • 如果 \(\gcd(n, P) = 1\),那么 \(n^{\phi(P)} \equiv 1(\bmod P)\)

费马小定理

\(P\) 本身即为质数时,得到欧拉定理的特殊形式,

\[a \cdot a^{m - 2} \equiv 1 \pmod m \]

求逆元

整数 \(n\) 在模 \(P\) 意义上存在逆元,当且仅当 \(\gcd(n, P) = 1\)

proof:方程 \(nx = Py + 1\) 有解的充要条件为 \(\gcd(n, P) = 1\)

\(O(\log n)\)\(n^{-1}\)

在满足 \((n, P) = 1\) 的前提下,求解方程 \(nx = Py + 1\)
\(x\) 即为 \(n^{-1}\)

特别的,当 \(P\) 为质数时,\(n^{-1} = n^{P - 2}\),此时更常用的解法是快速幂。

\(O(n)\)\([1, n]\) 的逆元

对于整数 \(i\),有 \(\lfloor \dfrac{P}{i} \rfloor \cdot i + P \% i = P\)
所以

\[\lfloor \dfrac{P}{i} \rfloor \cdot i + P \% i = 0 \pmod P \]

两边同乘 \(i^{-1} \cdot (P \% i)^{-1}\),得到

\[i^{-1} = -\lfloor \dfrac{P}{i} \rfloor \cdot (P \% i)^{-1} \]

由于 \(P \% i < i\),可在 \(O(n)\) 时间内递推求得。

int inv[N];

void get_inv(int n, int P) {
	inv[1] = 1;
	for(int i = 2; i <= n; ++ i) {
		inv[i] = -(P / i) * inv[P % i] % P; 
	}
}

例题

CF963A

题意:求 \(\sum \limits_{i=0}^{n} s_{i} a^{n - i} b^{i}\)
把式子化成 \(a^n\sum \limits_{i=0}^{n} s_{i} a^{- i} b^{i}\)
后面的部分可以进一步表示为首项为 \(\sum \limits_{i=0}^{k - 1} s_{i} a^{- i} b^{i}\),公比为 \(a^{-k}b^k\),项数为 \(\lfloor \dfrac{n + 1}{k} \rfloor\) 的等比数列。
最后处理余数。
submission


同余方程组的一般解

拓展中国剩余定理(EXCRT)

\[\begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \\ \vdots \\ x \equiv a_k \pmod {m_k} \\ \end{cases} \]

先考虑 \(k = 2\) 的情况。

\[x = y_1m_1 + a_1 = y_2m_2 + a_2 \]

\((y_{1_0}, y_{2_0})\) 是满足 \(y_1m_1 - y_2m_2 = a_2 - a_1\) 的一组解。
\(y_1 = y_{1_0} + k\dfrac{m_2}{(m_1, m_2)}\)
所以

\[\begin{aligned} x &= (y_{1_0}m_1 + a_1) + k\dfrac{m_1m_2}{(m_1, m_2)} \\ x & \equiv x_0 \pmod {[m_1, m_2]} \end{aligned} \]

联立

\[\begin{cases} x & \equiv x_0 \pmod {[m_1, m_2]} \\ x & \equiv a_3 \pmod {m_3} \end{cases} \]

推广到 \(k > 2\)

\[x \equiv x_0 \pmod {[m_1, m_2, \dots , m_k]} \]

给出合并两组方程的实现,其中 mul 是龟速乘。

auto merge(ll a1, ll m1, ll a2, ll m2) {
	ll y1, y2;
	ll r = exgcd(m1, m2, y1, y2);
	
	if((a2 - a1) % r != 0) {
		cout << "NO";
		exit(0);
	}
	ll m = m1 / r * m2;
	y1 = mul(y1, (a2 - a1) / r, m);
	ll a = (mul(y1, m1, m) + a1) % m;
	return make_pair(a, m);
}

例题

POJ2891

submission

POJ1006

submission

CF338D

题意:给定 \(n\)\(m\) 和长度为 \(k\) 的序列,询问是否存在 \(1 \le x \le n\)\(1 \le y \le m - k + 1\),使得 \(\forall a[i] = \gcd(x, y + i - 1)\) 成立。
根据题意,一定有 \(\forall a_i \mid x,a_i \mid y + i - 1\),列出同余方程。

\[\left\{ \begin{array}{l} x \equiv 0 \pmod {a_1}\\ x \equiv 0 \pmod {a_2}\\ \vdots\\ x \equiv 0 \pmod {a_k}\\ \end{array} \right. \quad\quad\quad\quad \left\{ \begin{array}{l} y \equiv 0 \pmod {a_1}\\ y \equiv -1 \pmod {a_2}\\ \vdots\\ y\equiv - k + 1 \pmod {a_k}\\ \end{array} \right. \]

\(L = [a_1, a_2, \dots, a_k]\),显然有

\[\begin{aligned} x &= \lambda \cdot L \\ y &= y_0 + \mu \cdot L \end{aligned} \]

对于 \(x = \lambda \cdot L\),必须满足 \(\gcd(\lambda, y) = 1\),否则 \(\gcd(x, y) > a_1\)
\(x\) 钦定的情况下,我们要最小化 \(y\),否则会越界。
\(\lambda> 1\) 只会对 \(y\) 造成限制。
\(\rightarrow x = L\) 最优。
此时

\[\gcd(x, y_0 + \mu \cdot L + i - 1) = \gcd(x, y_0 + i - 1) \]

所以只需检验 \(x = L\)\(y\) 等于满足 \(y \equiv y_0\) 的最小正整数解即可。
submission


同余方程组的构造解

中国剩余定理(CRT)

\[\begin{cases} x \equiv a_1 \pmod {m_1} \\ x \equiv a_2 \pmod {m_2} \\ \vdots \\ x \equiv a_k \pmod {m_k} \\ \end{cases} \]

适用范围:模数两两互质。

\(M = [m_1, m_2, \cdots, m_k] = \prod m_i\)
根据一般解的结论,\(x \equiv x_0 \pmod M\)

待定系数:\(x \equiv \lambda_1a_1 + \lambda_2a_2 + \cdots + \lambda_ka_k \quad \pmod M\)
满足第 \(i\) 个方程的充分条件是:

\[\begin{cases} m_i \mid \lambda_j \quad j \neq i \\ \lambda_i \equiv 1 \quad \pmod {m_i} \end{cases} \]

\(M_i = \dfrac{M}{m_i}\)\(M_i'M_i \equiv 1 \pmod {m_i}\)

\[x \equiv \sum\limits_{i = 1}^{k} M_i'M_ia_i \pmod M) \]


拓展欧拉定理

\[a^c \equiv a^{c \% \phi(m) + \phi(m)} \pmod m \quad c \ge \phi(m) \]

欧拉降幂公式

\[a^c\equiv \begin{cases} a^{c\bmod\varphi(p)} \,&\gcd(a,\,m)=1\\ a^c &\gcd(a,\,m)\ne1,\,c<\varphi(m)\\ a^{c\bmod\varphi(m)+\varphi(m)} &\gcd(a,\,m)\ne1,\,c\ge\varphi(m) \end{cases} \pmod m \]

证明

yifusuyi's blog

例题

CF17D

题意:求 \((b - 1) b^{n - 1} \% c\)\(n, b \le 10^{10^6}\)\(c \le 10^9\)
讨论 \(n - 1\)\(\phi(c)\) 的关系,套用公式。
submission

CF906D

题意:给定数列 \(a_1,a_2,...,a_n\) 和模数 \(m\),每次询问一个区间 \([l,r]\),求 \(a_l^{a_{l+1}^{{...}^{a_r}}} mod m\) 的值。
考虑求 \(a_1^{a_2^{{...}^{a_k}}}\)
递归地降幂。
\(1\) 层:讨论 \(a_1^{a_2^{{...}^{a_k}}}\)\(\phi_1 = m\) 的关系,试图往 \(0\) 层降幂(实际没有)。
\(2\) 层:讨论 \(a_2^{a_3^{{...}^{a_k}}}\)\(\phi_2 = \phi(\phi_1)\) 的关系,往第 \(1\) 层降幂。
\(3\) 层:讨论 \(a_3^{a_4^{{...}^{a_k}}}\)\(\phi_3 = \phi(\phi_2)\) 的关系,往第 \(2\) 层降幂。
\(\vdots\)
\(k\) 层:讨论 \(a_k\)\(\phi_k = \phi(\phi_{k - 1})\) 的关系,往第 \(k - 1\) 层降幂。

直接做是 \(O(nq\log V)\) 的,(每层回溯算结果要一只 log)。
如何优化?

当第 \(i\) 层的 \(\phi_i = 1\) 时,始终满足 \(a_i^{a_{i + 1}^{{...}^{a_k}}} \ge 1\),因此直接返回 \(1\)
由于欧拉函数衰减很快,总复杂度 \(O(q\log^2V)\)
submission


威尔逊定理

\(p\) 为质数时,有

\[(p - 1) ! \equiv -1 \pmod p \]

证明

\(p = 2\) 时,\((2 - 1)! \equiv -1 \pmod 2\)

\(p > 2\) 时,即证 \(\prod\limits_{i = 2}^{p - 2} \equiv 1 \pmod p\)

方程 \(x^2 \equiv 1 \pmod p\) 成立当且仅当 \(x \equiv 1\)\(x \equiv p - 1\)

所以 \(\forall x \in [2, p - 2]\)\(x^{-1} \in [2, p - 2]\)\(x^{-1} \ne x\)

也就是 \(\dfrac{n - 3}{2}\) 对数两两匹配互为逆元。

推广

\[(n - 1)!\equiv \begin{cases} -1 \,&n = p_i\\ 4 \,& n = 4\\ 0 \,&n > 4, \ n \ne p_i \\ \end{cases} \pmod n \]

合数 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\)

\(n\) 不为完全平方数时,\(p_1 \ne \dfrac{n}{p_1}\)\(p_1, \ \dfrac{n}{p_1} < n\),所以 \(n \mid (n - 1)!\)

\(n = p^2 时\)

如果 \(2p < n\)\(2p^2 \mid (n - 1)!\)

否则 \(n = 4\)\((4 - 1)! \equiv 2 \pmod 4\)


简单排列组合

隔板法

引入

求不定方程 \(x_1 + x_2 + \dots + x_k = n\) 的解的数量,满足 \(x_i \in N^*\)\(x_i \ge 1\)

假想 \(n\) 个球,想要划分为不为空的 \(k\) 段。
这个问题等效于在 \(n - 1\) 个空隙中选出 \(k - 1\) 个并插入隔板。

所以解的数量为 \(C_{n - 1}^{k - 1}\)

推广

1.求 $ x_1 + x_2 + \dots + x_k \le n$ 的解的数量,\(\forall x_i \ge a_i\)

\(y_i = x_i - a_i + 1\),此时 \(y_i \ge 1\)
将问题化归为 \(\sum \limits_{i = 1}^k y_i = n - \sum\limits_{i = 1}^k a_i + k\) 的解的数量,即可用上述结论求解。

特别的,当 \(\forall a_i = 0\) 时,方案数为 \(C_{n + k - 1}^{k - 1}\)

2.求 $ x_1 + x_2 + \dots + x_k \le n$ 的解的数量。

增设 \(x_{k + 1} \ge 0\),满足 \(\sum \limits_{i = 1}^{k + 1} x_i = n\),用上述结论求解。

网格路径计数

问题引入:在 \(n \times m\) 的网格上,每次只能向右或向下,求 \((0, 0)\) 走到 \((n, m)\) 的路径数。

法1:\(O(nm)\) dp。
法2:组合意义。

把路径等效成长度为 \(n + m\) 的操作序列,只包括 '右' 和 '下' 两种元素。

一种方法是套用多重集不同排列的结论,方案为 \(\dfrac{(n + m)!}{n!m!}\)

另一种方法是先假设操作序列空白,从中选 \(n\) 个填入 '下',其余填 '右',方案为 \(C_{n + m}^{m}\)

例题

CF630C

题意:求有多少长度不大于 \(n\),只含 '7','8' 的数字, \(n \le 55\)

数据很小,暴力求 \(\sum \limits_{i = 1}^{n} 2_i\) 没问题,也可以直接算 \(2^{n + 1} - 2\)

submisson

CF629A

submisson

CF817B

submisson

CF131C

submisson

CF869C

题意:三种颜色岛屿各 \(a\)\(b\)\(c\) 座,相同颜色的岛屿的距离不小于 \(3\)(或不连通),求建桥的方案数。

  • 一座岛不能和相同颜色的连边。
  • 一座岛不能和两座颜色相同的岛连边。

所以对于岛 \(A_i\),最多向 \(B\) 连一条边,向 \(C\) 连一条边,且两边决策互不干扰。

枚举不同颜色的岛间连了几条边。
\((A, B)\) 连了 \(i\) 条边,则可选方案为 \(C_a^i \times C_b^i \times i!\)

分开计算两两间的合法方案,最后相乘。
submisson

CF300C

题意:只含 \(a\)\(b\) 的数是好数,数位之和也是 '好数' 的 '好数' 是 '极好的数',求长度为 \(n\) 的 '极好的数' 个数。

数位之和取决于数字中 \(a\)\(b\) 的个数。

枚举有 \(i\)\(a\)
\(i \times a + (n - i) \times b\) 是 '好数',则在答案中加上 \(\dfrac{n!}{i!(n - i)!}\)
submission

CF1312D

题意:求满足如下条件的长度为 \(n\) 的序列 \(a\) 的个数:

  • \(\forall 1 \leq i \leq n\),都有 \(1 \leq a_i \leq m\)
  • \(a\) 中存在且仅存在一对相同的元素
  • 存在一个位置 \(p\),使得 \(a_1 \sim a_p\) 为严格单增序列,\(a_p \sim a_n\) 为严格单减序列。

\(2 \leq n\le m \leq 2 \times 10^5\)

钦定一对相同的元素 \(v\),剩下 \(n - 2\) 个数互不相同,共 \(C_{m - 1}^{n - 2}\) 种。

由于 \(a_p\) 一定大于 \(v\),减去所有数都小于 \(v\)\(C_{v - 1}^{n - 2}\) 种情况。

至此,我们把整个序列划分为 【左 $\ \ \ v \ \ $ 左 $\ \ \ a_p \ \ $ 右 $\ \ \ v \ \ $ 右】。
还未分配的 \(n - 3\) 个元素要么在左,要么在右,与 \(2^{n - 3}\) 种合法方案一一对应。

所以答案为 \(2^{n - 3} \sum (C_{m - 1}^{n - 2} - C_{v - 1}^{n - 2})\)

submission

CF991E

题意:给定正整数 \(n \le 10^{18}\),求满足条件的 \(m\) 的个数:

  • \(m\) 没有前导零。
  • \(m\) 中的数字 \(n\) 中都出现过。
  • \(n\) 中的数字 \(m\) 中都出现过。

CF300C 相同,枚举每个数字的个数。

\(c_i\) 表示数字 \(i\) 出现的个数。
根据均值不等式,\(\prod \limits_{i = 0}^{9} c_i \le (\dfrac{\sum \limits_{i = 0}^{9} c_i}{10}) ^ {10} \le 613.11\),所以直接枚举的复杂的是正确的。

\(m = \sum \limits_{i = 0}^{9} c_i\),即当前数字位数。
讨论贡献:

  • \(c_0 = 0 \rightarrow \dfrac{m!}{\prod \limits_{i = 0}^{9} c_i ! }\)
  • \(c_0 \neq 0 \rightarrow \dfrac{m!}{\prod \limits_{i = 0}^{9} c_i ! } - \dfrac{(m - 1)!}{(c_0 - 1)!\prod \limits_{i = 1}^{9} c_i ! }\)

submission

CF140E

题意:一棵 \(n\) 层的树,每层由 \(l_i\) 个小球组成。

  • 同一层相邻的小球的颜色都不相同。

  • 相邻的两层的小球颜色集合不相同。

一共有多少种合法装饰方案,对 \(p\) 取模。

钦定颜色列表 \([c_1, c_2, c_3, \dots, c_i, \cdots]\),令 \(f_{i, j}\) 表示一层内前 \(i\) 个位置恰好用前 \(j\) 种颜色的方案。

  • 如果 \([1, i - 1]\) 用了 \(j - 1\) 种颜色,位置 \(i\) 只能放 \(c_j\)
  • 如果 \([1, i - 1]\) 用了 \(j\) 种颜色,位置 \(i\) 可以放 \(c_k\)\(c_k != a_{i - 1}\)

因此

\[f_{i, j} = f_{i - 1, j - 1} + f_{i - 1, j} \times (j - 1) \]

\(g_{i, j}\) 表示第 \(i\) 层,钦定颜色列表,且恰好用 \(j\) 种颜色的方案,
\(s_i\) 表示第 \(i\) 层的方案总数。

由于每层的颜色列表可以随意选择并排列:

\[s_i = \sum \limits_{j = 1}^{l_i} g_{i, j} \times A_m^j \]

\(g_{i, j}\) 不能从全部 \(s_{i - 1}\) 种前置状态转移过来,
如果 \(j \le l_{i - 1}\),则有 \(g_{i - 1, j} \times j!\) 个状态与当前钦定的颜色集合相同,所以

\[g_{i, j} = f_{l_i, j} \times (s_{i - 1} - [j \le l_{i - 1}]g_{i - 1, j} \times j!) \]

注意:

  • 本题的 \(p\) 不是特殊的,采用 \(A_m^i = \prod \limits_{j = 1}^{i} (m - j + 1)\) 计算。

submission

HDU7133

题意:长度为 \(n\) 的所有排列按字典序排序组成长度为 \(n!n\) 的新序列,有多少子串是 \(m\) 元排列?

完整排列的方案

\(\{1, 2, \dots, m - 1, m\}\) 看作整体,与剩余 \(n - m\) 个数进行排列。

算上内部顺序共 \(m!(n - m + 1)!\)

跨块方案

Hint 1:已知排列 \(\{p_i\}\),怎么构造下一个排列?

  • 找到最大的 \(k\) 使得 \(\{p_{k + 1}, \dots ,p_n\}\) 是最长下降后缀,即 \(p_k < p_{k + 1}\)\(\forall i \in [k + 1, n), p_i > p_{i + 1}\)
  • \(p_k\) 与后缀中第一个大于他的数字交换。
  • \(\{p_{k + 1}, \dots ,p_n\}\) 升序排序。

eg:13542 最长下降后缀为 542,前一位为 3,交换 3 和 4 得到 14532,重新排序得到 14235,即为下一个排列。

假设当前排列为 \(\{p_i\}\),下一个排列为 \(\{q_i\}\)

性质 1\(\{p_i\}\) 首尾元素 \(\le m\),大于 \(m\) 的都在中间。

\(A\) \(B\) \(C\)
\(\le m\) \(> m\) \(\le m\)

最终排列由 \(\{p_i\}\)\(C\)\(\{q_i\}\)\(A\) 构成。
所以 \(\forall i \in C, p_i \le m\)

把中间 \(n - m\) 个元素当成整体,插入剩下 \(m\) 个元素的 \(m - 1\) 个空隙中。

满足性质 1 的方案有 \(m!(n - m)!(m - 1)\)

假设存在 \(i \in A, p_i > m\),则存在 \(i \in B, p_i \le m\)
根据提示 1,最长后缀不存在于 \(A\)\(A\) 中元素不发生改变,\(\forall i \in A, p_i = q_i\)
\(\forall i \in A, q_i \le m\),矛盾。

性质 2\(\{p_i\}\) 的首部与 \(\{p_i\}\) 完全相同。

由性质 1 推出,\(A_p\)\(C_p\) 关于 \(\{1, 2, \dots, m\}\) 互补。

又因为 \(C_p\)\(A_q\) 互补,所以 \(A_p = A_q\)

不满足性质 2 当且仅当首部发生改变,也就是 \(BC\) 段严格递减。

枚举尾部长度,不满足性质的方案共 \((n - m)!\sum \limits_{i = 1}^{m - 1} C_m^i (m - i)! = m!(n - m)!\sum \limits_{i = 1}^{m - 1} \dfrac{1}{i!}\)

预处理 \(\dfrac{1}{i!}\) 前缀和,跨块总贡献为 \(m!(n - m)! (m - 1 - \sum \limits_{i = 1}^{m - 1} \dfrac{1}{i!})\)

submission


容斥原理

引入

  1. \(1\)\(n\) 中既不是 \(2\) 的倍数也不是 \(3\) 的倍数的个数。

\[|S| = n - \lfloor \dfrac{n}{2} \rfloor - \lfloor \dfrac{n}{3} \rfloor + - \lfloor \dfrac{n}{6} \rfloor \]

  1. 求 1 到 \(n\) 的全排列中 \(1\)\(2\)\(3\)\(4\) 都不相邻的方案。

    \(1\)\(2\) 绑定,\(1\)\(2\) 相邻的方案数为 \(2!(n - 1)!\),同理 \(3\)\(4\)

\[|S| = n! - 2!(n - 1)! - 2!(n - 1)! + 2!2!(n - 2)! \]

  1. \(n\) 件不同物品放入 \(3\) 个不同盒子,求方案数。
    • 无限制条件 \(\rightarrow 3^n\)
    • A(B,C)为空 \(\rightarrow 2^n\)
    • AB(AC,BC)为空 \(\rightarrow 1\)
    • ABC 为空 \(\rightarrow 0\)

\[|S| = 3^n - 3 \cdot 2^n + 3 - 0 \]

一般形式

\[|S - \bigcup\limits_{i = 1}^n A_i| = \sum\limits_{i = 0}^n (-1)^i \sum\limits_{1 \le j_1 < j_2 < \dots < j_i \le n} |\bigcap\limits_{k = 1}^{i} A_{j_k}| \]

贡献法证明。

\(\forall x \in S - \bigcup\limits_{i = 1}^n A_i\),都在 \(i = 0\) 时产生 \(1\) 的贡献。

如果 \(x \in A_1, A_2, A_3, \dots, A_k\),则产生 \(\sum\limits_{i = 1}^{k} (-1)^i C_k^i\) 的贡献。

\((1 + 1)^k\)\((1 - 1)^k\) 的二项式展开相加得到 \(C_k^i\) 的偶数项和,相减得到奇数项和。
可以证明 \(\sum\limits_{i = 1}^{k} (-1)^i C_k^i = 0\)

  1. \(m\) 个物品分配给 \(n\) 个人,每个人至少一件,求分配方案数。

\[|S| = \sum\limits_{i = 0}^n C_n^i (-1)^i(n - i)^m \]

  1. \(2n\) 个元素 \(a_1, a_2, \dots, a_n\)\(b_1, b_2, \dots, b_n\),求有多少个排列满足任意 \(a_i\) 不与 \(b_i\) 相邻。

\[|S| = \sum\limits_{i = 0}^n C_n^i (-1)^i(2n - i)! \cdot 2^i \]

  1. 欧拉函数证明。

不定方程的解的数量

求不定方程 \(x_1 + x_2 + \dots + x_k = n\) 的解的数量,满足 \(x_i \in N\)\(l_i \le x_i \le r_i\)

只有下界的情况在隔板法中讲过。
利用容斥原理,把问题转化为 \(\forall i, x_i \ge l_i\) 的方案减去 \(\exists i, x_i \ge r_i + 1\) 的方案。

\([x]\) 表示一组解。

  • \(S \leftarrow \{[x] \mid \forall i, \ x_i \ge l_i\}\)
  • \(A_i \leftarrow \{[x] \mid a_i \ge r_i + 1, \quad \forall j \ne i, \ x_j \ge l_j\}\)

\[|S - \bigcup\limits_{i = 1}^k A_i| = \sum\limits_{i = 0}^k (-1)^i \sum\limits_{1 \le j_1 < j_2 < \dots < j_i \le k} |\bigcap\limits_{l = 1}^{i} A_{j_l}| \]

其中

\[|\bigcap\limits_{i \in \{j\}} A_i| = \large C_{n + k - 1 - \sum\limits_{i} [i \in \{j\}](r_i + 1) + [i \notin \{j\}]l_i}^{k - 1} \]

等效于枚举 \(x_i\) 的下界是 \(l_i\) 还是 \(r_i + 1\),复杂度 \(O(2^k)\)

错排问题

\(\forall i \in [1, n], a_i \le i\) 的排列数。

  • \(S \leftarrow \{\{p\}\}\)
  • \(A_i \leftarrow \{\{p\} \mid a_i = i\}\)

\[\begin{aligned} d(n) = |S - \bigcup\limits_{i = 1}^k A_i| &= \sum\limits_{i = 0}^n (-1)^i C_n^i (n - i)! \\ &= \sum\limits_{i = 0}^n (-1)^i \dfrac{n!}{i!} \\ &= n!\sum\limits_{i = 0}^n (-1)^i \dfrac{1}{i!} \end{aligned} \]

性质:\(n \rightarrow +\infty,\quad d(n) \rightarrow \dfrac{1}{e}\)

容斥原理的符号形式

\(S\) 是一个有限集,\(a_1, a_2, \dots, a_n\)\(n\) 种性质。

  • \(N(a_i)\)\(S\) 中有 \(a_i\) 性质的元素的数量。特殊的,记 \(N(1) = |S|\)
  • \(N(1 - a_i)\)\(S\) 中没有 \(a_i\) 性质的元素的数量。
  • \(N(a_{i_1}a_{i_2}\dots a_{i_k})\)\(S\) 中同时有 \(a_{i_1}, a_{i_2},\dots, a_{i_k}\) 性质的元素的数量。
  • \(N(a \pm b) = N(a) \pm N(b)\)
  • 当且仅当 \(a\)\(b\) 独立时 \(N(ab) = N(a)N(b)\)

则容斥原理可以写成

\[N((1 - a_1)(1 - a_2)\dots(1 - a_n)) = \sum\limits_{i = 0}^n (-1)^i \sum\limits_{1 \le j_1 < j_2 < \dots < j_i \le n} N(a_{j_1}a_{j_2}\dots a_{j_i}) \]

公式中枚举的 \(i\) 表示不满足的性质数。

符号形式在集合关系与多项式运算之间建立了桥梁。

  • \((1 - A)(1 - B) = 1 - (A + B) + AB\)
  • \(|S - A \cup B| = |S| - (|A| + |B|) + |A \cap B|\)
  • \(N((1 - A)(1 - B)) = N(1 - (A + B) + AB) = |S| - (|A| + |B|) + |A \cap B|\)

容斥原理的推广

有了符号形式,我们可以方便在总方案中表示性质的有无,并通过多项式展开求解容斥关系。
因此可以解决有些性质有,有些性质没有的方案数。

\[N(a_1\dots a_x(1 - a_{x+1})\dots(1 - a_{x+n})) = \sum\limits_{i = 0}^n (-1)^i \sum\limits_{x \le j_1 < < \dots < j_i \le n + x} N(a_1\dots a_x a_{j_1}\dots a_{j_i}) \\ \]

  1. \(1\)\(n\) 中不是 \(2\) 也不是 \(3\) 的倍数,但是是 \(5\) 的倍数的数量。

\[\begin{aligned} N((1 - a_2)(1 - a_3)a_5) &= N(a_5 - a_2a_5 - a_3a_5 + a_2a_3a_5) \\ &= \lfloor \dfrac{n}{5} \rfloor - \lfloor \dfrac{n}{10} \rfloor - \lfloor \dfrac{n}{15} \rfloor + \lfloor \dfrac{n}{30} \rfloor \\ \end{aligned} \]

  1. 求刚好有 \(k\) 个位置使得 \(p_i = i\) 的排列数。

\[N(a_1\dots a_k(1 - a_{k + 1})\dots (1 - a_n)) = C_n^k \sum\limits_{i = 0}^{n - k} (-1)^i C_{n - k}^i (n - k - i)! \]

由于 \(a_1\dots a_k\)\((1 - a_{k + 1})\dots (1 - a_n)\) 独立,能够分开计算。

例题

NC15079

submission

NC16513

submission

NC19857

题意:\(n\) 对情侣围成一圈,求任意情侣不相邻的方案。

前置:长度为 \(n\) 的圆排列共 \((n - 1)!\)

将选出的 \(i\) 对情侣绑定,将原集合等效成 \(2n - i\) 个元素进行排列。

\[N((1 - a_1)(1 - a_2)\dots(1 - a_n)) = \sum\limits_{i = 0}^n (-1)^i C_n^i (2n - i - 1) 2^i \]

本题卡空间,在线算组合又卡时间,容斥做法拿到 70pts 就够了,时空复杂度更优的做法
submission

CF547C

题意:维护一个可重集,每次查询集合中互质数对的个数。

  • 两个数互质取决于是否有共同的质因子。
  • 小于 \(5\times 10^5\) 的数最多有 \(7\) 个不同质因子。

\(cnt_x\) 表示当前集合中能被 \(x\) 整除的数的个数。
考虑新增一个元素 \(cur = p_1^{\alpha_1}\dots p_k^{\alpha_k}\)

令性质 \(a_i\) 表示能被 \(p_i\) 整除。

\[\begin{aligned} \Delta N &= N((1 - a_1)\dots(1 - a_k)) \\ &= \sum\limits_{i = 0}^n (-1)^i \sum\limits_{1 \le j_1 < j_2 < \dots < j_i \le k} cnt_{p_{j_1}\dots p_{j_i}} \end{aligned} \]

删除同理。
submission

[CQOI2012] 局部极小值

题意:在 \(n \times m\) 的矩阵中,\(1\)\(n \times m\) 的每个整数恰好出现一次,\(n \le 4, m \le 7\)
一个数是局部最小值当前仅当小于所有周围的数。
给定局部最小值的位置和非局部最小值的位置,求满足此要求的矩阵个数。

令性质 \(a_{i, j}\) 表示 \((i, j)\) 是局部最小值。
则要求的方案为 \(N(a_{i_1, j_1} \dots a_{i_k, j_k} (1 - a_{i_{k + 1},j_{k + 1}})\dots (1 - a_{i_{nm},j_{nm}}))\)

于是转化为求解子问题 \(N(\prod a_{i, j})\)

\(4 \times 7\) 的矩阵中最多有 \(8\) 个局部最小值,所以子问题规模小于 \(\sum\limits_{i = 0}^{8} C_{28}^i\),大约在 \(10^4\),可以接受。

通过搜索枚举子问题。
当钦定某些位置是局部最小时,如何求方案数?

不妨从小到大填充矩阵。
\(f_{i, s}\) 表示当前填到 \(i\),且局部最小的状态(填/没填)为 \(s\) 时的方案。
\(cnt_s\) 表示状态为 \(s\) 时填了多少个钦定位置。

如果当前填的位置钦定了局部最小,那么 \(f_{i, s} = \sum\limits_{j \in s} f_{i - 1, s - j}\)

如果当前填的位置没有钦定,
\(nums_s\) 表示状态 \(s\) 下已经能填的非钦定位置个数。

\[\begin{array}{|c|*{3}{l|}} \hline \text{未填} & (1, 2) & \text{已填}\\ \hline (2, 1) & (2, 2) & (2, 3)\\ \hline \end{array} \]

此时只有 \((2, 3)\) 能填,否则会在后续产生矛盾。

则这部分的贡献为 \(\max(0, nums_s - (i - 1 - cnt_s)) \times f_{i - 1, s}\)
\(i - 1 - cnt_s\) 为前 \(i - 1\) 个数中已经用掉的位置。

submission


第二类斯特林数(Stirling Number)

第二类斯特林数(斯特林子集数)\(\begin{Bmatrix}n\\ k\end{Bmatrix}\),也可记做 \(S_2(n,k)\),表示将 \(n\) 个两两不同的元素,划分为 \(k\) 个互不区分的非空子集的方案数。

递推式

我们插入一个新元素时,有两种方案:

  • 将新元素放入一个现有的非空子集,有 \(k\begin{Bmatrix}n-1\\ k\end{Bmatrix}\) 种方案。
  • 将新元素单独放入一个子集,有 \(\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}\) 种方案;

\[\begin{Bmatrix}n\\ k\end{Bmatrix}=\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}+k\begin{Bmatrix}n-1\\ k\end{Bmatrix} \]

边界是 \(\begin{Bmatrix}n\\ 0\end{Bmatrix}=[n=0]\)

通项公式

不妨先认为 \(k\) 个集合互不相同,转化成经典容斥问题,最后乘上 \(\dfrac{1}{k!}\)

\[\begin{Bmatrix}n\\ k\end{Bmatrix} = \sum\limits_{i = 0}^k (-1)^i C_k^i (k - i)^n \]

重要公式

我们记下降阶乘幂 \(x^{\underline{n}}=\dfrac{x!}{(x-n)!}=\prod_{k=0}^{n-1} (x-k)\)

则可以利用下面的恒等式将普通幂转化为下降幂:

\[x^n =\sum\limits_{k = 0}^n \begin{Bmatrix}n\\ k\end{Bmatrix} \begin{pmatrix}x\\ k\end{pmatrix} k! =\sum\limits_{k = 0}^n \begin{Bmatrix}n\\ k\end{Bmatrix} x^{\underline{k}} \]

考虑各式组合意义。

  • \(x^n \rightarrow\) \(n\) 个不同的球放入 \(x\) 个不同的盒子。
  • \(\begin{pmatrix}x\\ k\end{pmatrix} \rightarrow\) \(x\) 个盒子中选出 \(k\) 个。
  • \(\begin{Bmatrix}n\\ k\end{Bmatrix} \rightarrow\) \(n\) 个不同的球放入 \(k\) 个相同的盒子且都不为空。
  • \(k! \rightarrow\) 将选出的 \(k\) 个盒子排列。

正确性显然。


积性函数

定义

若函数 \(f(n)\) 满足 \(f(1)=1\)\(\forall x,y\in\mathbf{N}^*,~(x,y)=1\) 都有 \(f(xy)=f(x)f(y)\),则 \(f(n)\)积性函数

若函数 \(f(n)\) 满足 \(f(1)=1\)\(\forall x,y\in\mathbf{N}^*\) 都有 \(f(xy)=f(x)f(y)\),则 \(f(n)\)完全积性函数

例如:

  • 单位函数:\(\varepsilon(n)=[n=1]\)。(完全积性)
  • 恒等函数:\(\operatorname{id}_k(n)=n^k\)\(\operatorname{id}_{1}(n)\) 通常简记作 \(\operatorname{id}(n)\)。(完全积性)
  • 常数函数:\(1(n)=1\)。(完全积性)
  • 除数函数:\(\sigma_{k}(n)=\sum_{d\mid n}d^{k}\)\(\sigma_{0}(n)\) 通常简记作 \(d(n)\)\(\tau(n)\)\(\sigma_{1}(n)\) 通常简记作 \(\sigma(n)\)
  • 欧拉函数:\(\varphi(n)=\sum_{i=1}^n[(i,n)=1]\)
  • 莫比乌斯函数:\(\mu(n)=\begin{cases}1&n=1\\0&\exists d>1,d^{2}\mid n\\(-1)^{\omega(n)}&\text{otherwise}\end{cases}\),其中 \(\omega(n)\) 表示 \(n\) 的本质不同质因子个数,它是一个加性函数。

"加性函数"
此处加性函数指数论上的加性函数 (Additive function)。对于加性函数 \(f\),当整数 \(a,b\) 互质时,均有 \(f(ab)=f(a)+f(b)\)
应与代数中的加性函数 (Additive map) 区分。

性质

\(f(x)\)\(g(x)\) 均为积性函数,则以下函数也为积性函数:

\[\begin{aligned} h(x)&=f(x^p)\\ h(x)&=f^p(x)\\ h(x)&=f(x)g(x)\\ h(x)&=\sum_{d\mid x}f(d)g\left(\dfrac{x}{d}\right) \end{aligned} \]

\(x=\prod p_i^{k_i}\)

\(F(x)\) 为积性函数,则有 \(F(x)=\prod F(p_i^{k_i})\)

\(F(x)\) 为完全积性函数,则有 \(F(x)=\prod F(p_i)^{k_i}\)

质因数分解求 \(f(n)\)

\(f(n) = f(p_1^{\alpha_1})\dots f(p_k^{\alpha_k})\)

\(f(p_1^{\alpha_1})\) 依次求解然后相乘即可。

ll get_f(int n) {
	ll ret = 1;
	for(int i = 2; i <= n / i; ++ i) {
		if(n % i == 0) {
			int cnt = 0;
			while(n % i == 0) {
				++ cnt;
				n /= i;
			}
			ret = ret * calc_f(i, cnt);
		}
	}
	
	if(n > 1) {
		ret = ret * calc_f(n, 1);
	}
	return ret;
}

欧拉筛求 \(f(1), f(2), \dots, f(n)\)

根据定义:\(f(1) = 1\)

\(n = p_1^{\alpha_1} \dots p_k^{\alpha_k}\) 一定会被 \(m = p_1^{\alpha_1 - 1} \dots p_k^{\alpha_k}\) 筛到。

  • 如果 \(\alpha_1 = 1\),则 \((n, m) = 1\)\(f(n) = f(m) \cdot f(p_1)\)
  • 如果 \(\alpha_1 > 1\),则 \((n, m) \ne 1\)\(f(n) = \dfrac{f(m)}{f(p_1^{\alpha_1 - 1})} \cdot f(p_1^{\alpha_1})\)

因此,对于质数的幂次 \(p^{cnt}\),暴力调用 calc_f(p, cnt)

否则,记录数组 \(cnt_i\) 表示 \(i\) 中最小质因子的次数,根据上述分类求解。

void init(int n) {
	f[1] = 1;
	for(int i = 2; i <= n; ++ i) {
		if(v[i] == 0) {
			p[++ idx] = i;
			cnt[i] = 1;
			f[i] = calc_f(i, 1);
		}
		for(int j = 1; p[j] <= n / i; ++ j) {
			v[i * p[j]] = 1;
			if(i % p[j] == 0) {
				cnt[i * p[j]] = cnt[p[j]] + 1;
				f[i * p[j]] = f[i] / calc_f(p[j], cnt[p[j]]) * calc_f(p[j], cnt[p[j]] + 1);
				break;
			}
			cnt[i * p[j]] = 1;
			f[i * p[j]] = f[i] * calc_f(p[j], 1);
		}
	}
}

例题

NC229685

题意:求 \(n\) 的正因子个数,\(q\) 次询问,\(n \le 10^7\)

\(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\),则 \(f(n) = (\alpha_1 + 1)\dots(\alpha_k + 1)\)
\((p, q)\) 互质,则 \(f(p)\cdot f(q) = (\alpha_1 + 1)\dots(\alpha_k + 1)(\beta_1 + 1)\dots(\beta_l + 1) = f(p\cdot q)\)

submission

NC23047

题意:求 \(\bigoplus\limits_{i = 1}^n (i^n \bmod (10^9 + 7))\)\(n \le 1.3 \times 10^7\)

定义 \(f(i) = i^n\)

对于 \(\forall p, q, \ \ f(pq) = (pq)^n = p^nq^n\),是完全积性的。

submission

CF757E

题意:定义函数 \(f_r(n)\)

  • \(f_0(n)\) 为满足 \(p\cdot q=n\)\(\gcd(p,q)=1\) 的有序对 \((p,q)\) 个数;
  • \(\displaystyle f_{r + 1}(n)=\sum_{u\cdot v=n}\frac{f_{r}(u)+f_{r}(v)}{2}\).

一共 \(q\) 组询问,每组询问给出 \(r,n\),求 \(f_r(n)\)\(10^9+7\) 的结果。

数据范围:\(q\le10^6\),\(0\le r\le10^6\),\(1\le n\le10^6\).


对于 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\),只有 \(p = \prod\limits_{i \in S}p_i^{\alpha_i} , \ q = \prod\limits_{i \notin S}p_i^{\alpha_i}\) 时会对 \(f_0(n)\) 造成贡献。

所以 \(f_0(n) = 2^k = 2^{\sigma(n)}\).

对于 \((p, q) = 1\)\(\{p_i\} \cap\{q_i\} = \phi\).

所以 \(\sigma(pq) = \sigma(p) + \sigma(q)\).

所以 \(f_0(pq) = f_0(p)\cdot f_0(q)\),于是我们证明了 \(f_0\) 是积性函数。


现在考虑 \(r \ge 1\).

注意到 \((u, v)\)\((v, u)\) 都有贡献,所以 \(\forall d \mid n\)\(f_r(n)\) 的贡献为 \(2 \times \dfrac{f_{r - 1}(d)}{2}\)

\[f_r(n) = \sum\limits_{d \mid n} f_{r - 1}(d) \]

考虑积性函数 \(f(n)\),以及函数 \(g(n) = \sum\limits_{d\mid n}f(d)\).

对于 \((p, q) = 1\),有

\[\begin{aligned} g(p) &= \sum\limits_{d_1 \mid p} f(d_1)\\ g(q) &= \sum\limits_{d_2 \mid q} f(d_2)\\ \\ g(p) \times g(q) &= \sum\limits_{d_1 \mid p}\sum\limits_{d_2 \mid q} f(d_1)\times f(d_2)\\ &= \sum\limits_{d_1 \mid p}\sum\limits_{d_2 \mid q} f(d_1\times d_2) \\ &= g(p\times q) \end{aligned} \]

所以 \(g(n)\) 也是积性函数。

因为 \(f_0\) 是积性函数,所以 \(\forall r, (p, q) = 1, \ f_r(p\times q) = f_r(p) \times f_r(q)\).


于是目标 \(f_r(n) = f_r(p_1^{\alpha_1})\times \dots \times f_r(p_k^{\alpha_k})\),只需预处理 \(\forall r, p, \alpha, \ \ f_r(p^{\alpha})\) 即可。

不妨从 \(f_0\) 开始递推。

  • \(\alpha = 0\)\(f_0 = 1\).
  • \(\alpha > 0\)\(f_0 = 2\).

\(f_0(p^{\alpha})\) 的值与 \(p\) 无关。

根据递推式 \(f_r(p^{\alpha}) = \sum\limits_{i = 0}^{\alpha} f_{r - 1}(p^i)\)\(f_r\) 只与 \(f_{r - 1}\) 有关,所以 \(\forall r\)\(f_r(p^{\alpha})\) 的值与 \(p\) 无关。

\(dp_{r, i} = f_r(p^i)\).

\[\begin{aligned} dp_{r, 0} &= 0 \\ dp_{r, i} &= \sum\limits_{j = 0}^{i}dp_{r - 1, j} \end{aligned} \]

submission


莫比乌斯反演

引入

  • 如果 \(f(n) = \sum\limits_{i = 1}^ng(i)\),则 \(g(n)\) 可通过 \(f(n) - f(n - 1)\) 反求。
  • 如果 \(f(n) = \sum\limits_{d \mid n} g(d)\),怎么通过 \(f\) 反求 \(g(n)\)

如果 \(n = p_1^{\alpha_1}\dots p_k^{\alpha_k}\).

令性质 \(a_i\) 不整除 \(p_i^{\alpha_i}\),则 \(N(a_i) = f(p_1^{\alpha_1}\dots p_i^{\alpha_i - 1}\dots p_k^{\alpha_k})\).

\[\begin{aligned} g(n)= N((1 - a_1)\dots(1 - a_k)) &= \sum\limits_{S \subseteq\{1, 2,\dots k\} } (-1)^{|S|} N(\prod\limits_{i \in S} a_i)\\ &= \sum\limits_{S \subseteq\{1, 2,\dots k\} } (-1)^{|S|} f(p_1^{\alpha_1 - [1 \in S]}\dots p_k^{\alpha_k - [k \in S]})\\ &= \sum\limits_{d \mid n} [\dfrac{n}{d} = p_1\dots p_i] (-1)^i f(d) \end{aligned} \]

引入莫比乌斯函数 \(\mu(n) = [n = p_1\dots p_i](-1)^i\).

\[\mu(n)= \begin{cases} 1&n=1\\ 0&n\text{ 含有平方因子}\\ (-1)^k&n\text{ 无平方因子且有 } k\text{ 个质因子}\\ \end{cases} \]

于是

\[g(n) = \sum\limits_{d \mid n} \mu(\dfrac{n}{d}) \cdot f(d) \]

定理(莫比乌斯反演)

\(f:\mathbb{N} \rightarrow \mathbb{R}, \ g:\mathbb{N} \rightarrow \mathbb{R}\) 是两个函数,则

\[f(n) = \sum\limits_{d \mid n} g(d) \Longleftrightarrow g(n) = \sum\limits_{d \mid n} \mu(\dfrac{n}{d}) \cdot f(d) \]

环计数问题

题意:\(n\) 个数围成一圈,每个数取值范围在 \(1\)\(r\),求有多少个这样的环,两个环不相同当且仅当不能通过旋转重合。

\(n\) 个数展开成序列并无限延伸。

定义周期 \(d\) 为满足 \(\forall a_i = a_i + d\) 的最小正整数。

显然 \(d \mid n\),否则与 \(\forall a_i = a_i + n\) 矛盾。

\(f(d)\) 表示周期为 \(d\) 的不同环的个数。

一个环对应 \(d\) 个不同的序列(分别以 \(a_1, a_2\dots a_d\) 开头)。

所有不同的序列共 \(r^n\) 个。

所以

\[\begin{aligned} r^n &= \sum\limits_{d \mid n} d \cdot f(d) \\ n \cdot f(n) &= \sum\limits_{d \mid n} \mu(\dfrac{n}{d}) \cdot r^d \end{aligned} \]

总方案数为 \(\sum\limits_{d = 1}^n f(d)\).

定理(莫比乌斯反演2)

\(f:\mathbb{N} \rightarrow \mathbb{R}, \ g:\mathbb{N} \rightarrow \mathbb{R}\) 是两个函数,且存在正整数 \(N\),使得 \(\forall n > N, \ f(n) = g(n) = 0\).

\[f(n) = \sum\limits_{\begin{aligned} n &\mid m\\ m &\le N \end{aligned}} g(d) \Longleftrightarrow g(n) = \sum\limits_{\begin{aligned} n &\mid m\\ m &\le N \end{aligned}} \mu(\dfrac{m}{n}) \cdot f(m) \]

例题

NC14648

题意:给定序列 \(\{a_i\}, \ \{b_i\}\),有多少对 \((x, y) = 1\) 满足 \(a_{b_x} = b_{a_y}\).

定义 \(g(d) = \sum\limits_{x, y}[(x, y) = d][a_{b_x} = b_{a_y}]\),考虑反演:

\[\begin{aligned} f(d) &= \sum\limits_{d \mid d'}g(d') = \sum\limits_{\begin{aligned}d& \mid x\\d&\mid y\end{aligned}}[a_{b_x} = b_{a_y}]\\ g(d) &= \sum\limits_{d \mid d'} \mu(d'/d)f(d') \end{aligned} \]

\[f(1) = \sum\limits_{i = 1}^ng(i) \Longleftrightarrow g(1) = \sum\limits_{i = 1}^{n} \mu(i)f(i) \]

其中 \(\forall f_i\) 可以在 \(O(\dfrac{n}{1} + \dfrac{n}{2} + \cdots + \dfrac{n}{n}) = O(n\ln n)\) 内求出。

submission

AT_abc162_e

题意:给定\(n,k\),求

\[\sum^k_{a_1=1}\sum^k_{a_2=1}\sum^k_{a_3=1}\dots\sum^k_{a_n=1}\gcd(a_1,a_2,a_3,\dots,a_n)\ \bmod\ 1000000007 \]

和上题套路一致,设 \(g(d) = \sum [\gcd(a_i) = d]\).

有反演:

\[f(d) = \sum\limits_{d \mid d'}g(d') \Longleftrightarrow g(d) = \sum\limits_{d \mid d'}^{n} \mu(d'/d)f(d') \]

\(d \mid \gcd(a_i)\),则 \(\forall i, \ d \mid a_i\),所以 \(f(d) = \lfloor \dfrac{k}{d} \rfloor^n\).

最终答案为 \(\sum g(d) \cdot d\).

submission

AT_agc038_c

题意:给定数组 \(A\),求 \(S = \sum\limits_{i=1}^{N}\sum\limits_{j=i+1}^{N}\mathrm{lcm}(A_i,A_j)\) .

令 $g(d) = \sum\limits_{i, j}[(A_i, A_j) = d] \cdot\mathrm{lcm}(A_i,A_j) $.

由于 \(\mathrm{lcm}(a, b) = \dfrac{ab}{\gcd(a, b)}\),则 $\sum\limits_{d = 1}^{\max(A_i)} g(d) - \sum\limits_{i = 1}^nA_i= 2S $

\[\begin{aligned} g(d) &= \sum\limits_{i, j}[(A_i, A_j) = d] \cdot\dfrac{A_iA_j}{\gcd(A_i, A_j)}\\ &= \frac{1}{d}\sum\limits_{i, j}[(A_i, A_j) = d] A_iA_j\\ &\\ f(d) &= \sum_{d \mid d'} g(d')\cdot d'\\ &= \sum_{d \mid A_i, d\mid A_j} A_iA_j\\ &= (\sum_{d \mid A_i} A_i)^2 \end{aligned} \]

最后对 \(g(d) \cdot d\) 做反演即可。

submission

狄利克雷(Dirichlet)卷积

定义

\(f:\mathbb{N^+} \rightarrow \mathbb{R}, \ g:\mathbb{N^+} \rightarrow \mathbb{R}\),则他们的狄利克雷卷积为

\[(f * g)(n) = \sum_{d \mid n} f(d)\cdot g(n/d) \]

性质

  1. 如果 \(f(n), \ g(n)\) 是积性函数,则 \(h(n) = (f*g)(n)\) 也是积性函数。

    证明:

    假设 \((p, q) = 1\),则

    \[\begin{aligned} h(pq) &= \sum_{\begin{aligned}d_1\mid p \\d_q\mid 2 \end{aligned}} f(d_1d_2) \cdot g(\dfrac{pq}{d_1d_2})\\ &= \sum_{\begin{aligned}d_1\mid p \\d_q\mid 2 \end{aligned}} f(d_1)\cdot f(d_2) \cdot g(\dfrac{p}{d_1})\cdot g(\dfrac{q}{d_1})\\ &= h(p) \cdot h(q) \end{aligned} \]

  2. \(f = g * 1 \Leftrightarrow g = f * \mu\).

    证明:

    \[f(n) = \sum_{d \mid n} g(n) \Longleftrightarrow g(n) = \sum_{d\mid n} \mu(n / d)\cdot f(d) \]

  3. 满足交换律与结合律。

    \[\begin{aligned} f * g &= g * f \\ (f * g) * h &= f * (g * h) \end{aligned} \]

  4. \(\epsilon = \mu * 1\).

    证明:

    \(\mu\) 的和函数 \(F(n) = \sum\limits_{d \mid n}\mu(d)\).

    \(F(1) = \mu(1) = 1\).

    \[\begin{aligned} F(p^k) &= \mu(1) + \mu(p) + \mu(p^2) + \cdots + \mu(p^k) \\ &= 1 + (-1) + 0 + \cdots + 0\\ &= 0 \end{aligned} \]

    \(F(n) = \prod F(p_i^k) = 0\).

    所以 \(\epsilon(n) = F(n)= [n = 1]\).

  5. \(id = \phi * 1\).

    即证 \(n = \sum\limits_{d \mid n} \phi(d)\).

    \(m \in [1, n]\) 分类, \(m\) 属于 \(C_d\) 类当且仅当 \((m, n) = d\)\((m / d, n / d) = 1\).

    所以 \(C_d\) 的大小为小于 \(n / d\) 且与之互素的正整数个数,恰与 \(\phi(n / d)\) 相等。

    \[n = \sum|C_d| = \sum \phi(n/d) = \sum \phi(d) \]

  6. \(\phi = \mu * id\).

    证明:

    对于 \(n = p_1^{a_1} \cdots p_k^{a_k}\),令性质 \(a_i\) 表示能够被 \(p_i\) 整除。

    \[\begin{aligned} \phi(n) &= N((1 - a_1)\cdots(1 - a_k)) \\ &= \sum_{S \subseteq\{1, \dots, k\}} (-1)^{|S|} \dfrac{n}{\prod\limits _{i \in S}p_i}\\ &= \sum_{d \mid n} [d = p_{x_1}\cdots p_{x_i}] (-1)^i \dfrac{n}{i}\\ &= \sum_{d \mid n} \mu(d) \cdot \dfrac{n}{i}\\ &= (\mu * id)(n) \end{aligned} \]

    引理:\(\dfrac{\phi(n)}{n} = \sum\limits_{d \mid n}\dfrac{\mu(d)}{d}\)

杜教筛

引入

  1. \(\Phi(n) = \sum\limits_{i = 1}^{n} \phi(n)\)

    对于欧拉函数,有 \(\phi * I = id\),即 \(\phi(n) = n - \sum\limits_{d \mid n, d < n}\phi(n)\)

    所以

    \[\begin{aligned} \sum_{i = 1}^n\phi(i) &= \sum_{i = 1}^n (i - \sum_{d \mid i, d < i}\phi(d))\\ &= \dfrac{n(n + 1)}{2} - \sum_{i = 2}^n\sum_{d \mid i, d < i}\phi(d)\\ &= \dfrac{n(n + 1)}{2} - \sum_{\frac{i}{d} = 2}^n\sum_{d = 1}^{\lfloor\frac{n}{\lfloor\frac{i}{d}\rfloor}\rfloor}\phi(d)\\ &= \dfrac{n(n + 1)}{2} - \sum_{i = 2}^n\sum_{d = 1}^{\lfloor\frac{n}{i}\rfloor}\phi(d)\\ &= \dfrac{n(n + 1)}{2} - \sum_{i = 2}^n\Phi(\lfloor\frac{n}{i}\rfloor)\\ \end{aligned} \]

    于是只需预处理 \(O(\sqrt{n})\)\(\Phi(\lfloor\dfrac{n}{i}\rfloor)\),就可以算出 \(\Phi(n)\)

    第三第四步将枚举因数化为枚举倍数,是常见减小复杂度的做法。

  2. \(M(n) = \sum\limits_{i = 1}^{n} \mu(n)\)

    和欧拉函数类似,利用 \(\mu(n) = [n = 1] - \sum\limits_{d \mid n, d < n}\mu(d)\)

    \[\begin{aligned} \sum_{i = 1}^n\mu(n) &= \sum_{i = 1}^n [i = 1] - \sum\limits_{d \mid i, d < i}\mu(d)\\ &= 1 - \sum_{i = 2}^n\sum_{d \mid i, d < i}\mu(d)\\ &= 1 - \sum_{i = 2}^n\sum_{d = 1}^{\lfloor\frac{n}{i}\rfloor}\mu(d)\\ &= 1 - \sum_{i = 2}^nM(\lfloor\frac{n}{i}\rfloor)\\ \end{aligned} \]

推导

对于一个数论函数 \(f(n)\),杜教筛可以在低于线性复杂度内求 \(S(n) = \sum\limits_{i = 1}^nf(i)\).

如果利用整除分块把相等的一起算,就加快了速度。

根据 \(f(n)\) 的性质,构造 \(S(n)\) 关于 \(S(\lfloor\dfrac{n}{i}\rfloor)\) 的递推式,方法如下。

构造两个积性函数 \(h, \ g\),满足 \(h\) 易于求和,\(g\) 易于计算 且\(h = f * g\)

\(h(i) = \sum\limits_{d \mid i}g(d)\cdot f(\dfrac{i}{d})\),对 \(h(i)\) 求和,有

\[\begin{aligned} \sum_{i = 1}^nh(i) &= \sum_{i = 1}^n\sum\limits_{d \mid i}^ig(d)\cdot f(\dfrac{i}{d})\\ &= \sum_{d = 1}^ng(d)\sum\limits_{d \mid i}^n\cdot f(\dfrac{i}{d})\\ &= \sum_{d = 1}^ng(d)\sum\limits_{i = 1}^{\lfloor\dfrac{n}{d}\rfloor}\cdot f(i)\\ &= \sum_{d = 1}^ng(d)\cdot S(\lfloor\dfrac{n}{d}\rfloor) \end{aligned} \]

  1. 公式法求 \(\sum_{i = 1}^n\phi(n)\)

    \(h = id, \ f = \phi, \ g = I\)

    所以 \(\sum\limits_{i = 1}^n id(i) = \sum\limits_{i = 1}^n S(\lfloor\dfrac{n}{d}\rfloor)\),即 \(S(n) = \sum\limits_{i = 1}^n id(i) - \sum\limits_{i = 2}^n S(\lfloor\dfrac{n}{d}\rfloor)\)

    同理,可用 \(\epsilon = \mu * I\) 求出 \(M(n)\)

实现

对于 \(n < N^{\frac{2}{3}}\) 预处理,否则暴力递归然后记忆化。

复杂度证明:[Auferstanden].

#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace std;

using uint = unsigned int;
using ll = long long;
constexpr int N = 3e6 + 5, V = 3e6;

__gnu_pbds::gp_hash_table<int, int> Mu;
__gnu_pbds::gp_hash_table<int, ll> Phi;

int mu[N], p[N], v[N], idx;
ll phi[N];

void init() {
	phi[1] = mu[1] = 1;
	
	for(int i = 2; i <= V; ++ i) {
		if(v[i] == 0) {
			mu[i] = -1;
			phi[i] = i - 1;
			p[++ idx] = i;
		}
		for(int j = 1; j <= idx && p[j] <= V / i; ++ j) {
			v[i * p[j]] = 1;			
			if(i % p[j] == 0) {
				phi[i * p[j]] = phi[i] * p[j];
				mu[i * p[j]] = 0;
				break;
			}
			mu[i * p[j]] = -mu[i];
			phi[i * p[j]] = phi[i] * (p[j] - 1);
		}
	}
	
	for(int i = 1; i <= V; ++ i) {
		mu[i] += mu[i - 1];
		phi[i] += phi[i - 1];
	} 
}

ll get_Phi(uint n) {
	if(n <= V) return phi[n];
	if(Phi.find(n) != Phi.end()) return Phi[n];
	ll ans = (ll)n * (n + 1) / 2;
	for(uint i = 2, j; i <= n; i = j + 1) {
		if(n / i == 0) break;
		j = n / (n / i);
		ans -= get_Phi(n / i) * (j - i + 1);
	}
	return Phi[n] = ans;
}
int get_Mu(uint n) {
	if(n <= V) return mu[n];
	if(Mu.find(n) != Mu.end()) return Mu[n];
	int ans = 1;
	for(uint i = 2, j; i <= n; i = j + 1) {
		if(n / i == 0) break;
		j = n / (n / i);
		ans -= get_Mu(n / i) * (j - i + 1);
	}
	return Mu[n] = ans;
}

int main() {
	cin.tie(0)->sync_with_stdio(0);
	
	init();
	
	int T;
	cin >> T;
	
	while(T --) {
		uint n; cin >> n;
		cout << get_Phi(n) << ' ' << get_Mu(n) << '\n';
	}
	return 0;
}

矩阵乘法

引入

如果 \(C = AB\),则 \(c_{ij} = \sum\limits_{k = 1}^{n}a_{ik} \cdot b_{kj}\),即 \(A\) 的第 \(i\) 行与 \(B\) 的第 \(j\) 列的点积。

  • 假设有 \(n\) 个地点,\(i\)\(j\) 做飞机有 \(a_{ij}\) 种选择,坐火车有 \(b_{ij}\) 种选择。求从 \(i\) 先做飞机再坐火车到 \(j\) 的方案。

    枚举中转点 \(k\)

    \(c_{ij} = \sum\limits_{k = 1}^na_{ik}\cdot b_{kj}\),写成矩乘即 \(C = AB\)

矩阵快速幂优化线性递推

  1. \(f(n) = a_1f(n - 1) + a_2f(n - 2) + a_3f(n - 3)\).

\[ \begin{pmatrix} f_n\\ f_{n - 1}\\ f_{n - 2}\\ \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & a_3\\ 1 & 0 & 0 \\ 0 & 1 & 0 \\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ f_{n - 3}\\ \end{pmatrix} \]

  1. \(f(n) = a_1f(n - 1) + a_2f(n - 2) + C\).

    \[\begin{pmatrix} f_n\\ f_{n - 1}\\ C \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & 1\\ 1 & 0 & 0\\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ C \end{pmatrix} \]

    \[\begin{pmatrix} f_n\\ f_{n - 1}\\ 1 \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & C\\ 1 & 0 & 0\\ 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ 1 \end{pmatrix} \]

  2. \(f(n) = a_1f(n - 1) + a_2f(n - 2) + c_2n^2 + c_1n + c_0\).

    \[\begin{pmatrix} f_n\\ f_{n - 1}\\ (n + 1)^2\\ n + 1\\ 1 \end{pmatrix} = \begin{pmatrix} a_1 & a_2 & c_2 & c_1 & c_0\\ 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 2 & 1 \\ 0 & 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 & 1 \\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ n^2\\ n\\ 1 \end{pmatrix} \]

  3. \(f(n) = a_{11}f(n - 1) + a_{12}g(n - 1), \ g(n) = a_{21}f(n - 1) + a_{22}g(n - 2)\).

    \[\begin{pmatrix} f_n\\ g_n\\ \end{pmatrix} = \begin{pmatrix} a_{11} & a_{12}\\ a_{21} & a_{22}\\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ g_{n - 1}\\ \end{pmatrix} \]

  4. \(f(n)\)\(g(n)\) 是线性递推的,则 \(h(n) = f(n)\cdot g(n)\) 也能线性递推。

    \[\begin{aligned} &\\ f(n) &= f(n - 1) + f(n - 2)\\ &\\ f^2(n) &= f^2(n - 1) + f^2(n - 2) + 2\cdot f(n - 1) \cdot f(n - 2)\\ &\\ f(n - 1) \cdot f(n - 2) &= \begin{cases} f(n - 1)\cdot (f(n - 1) - f(n - 3)) \\ (f(n - 2) + f(n - 3))\cdot f(n - 2) \end{cases}\\ &\\ 2\cdot f(n - 1) \cdot f(n - 2) &= f^2(n - 1) + f^2(n - 2) - f^2(n - 3)\\ &\\ f^2(n) &= 2\cdot f^2(n - 1) + 2\cdot f^2(n - 2) - f^2(n - 3) \end{aligned} \]

例题

CF1117D

题意:有多少长度为 \(n\)\(01\) 串,使得任意极长全 \(0\) 字串的长度都被 \(m\) 整除?(\(n \le 10^{18}, \ m \le 100\)

定义 \(f_{i, 0/1}\) 为长度为 \(i\),结尾为 \(0/1\) 的方案数。

\[\begin{aligned} f_{i, 1} &= f_{i - 1, 0} + f_{i - 1, 1}\\ f_{i, 0} &= f_{i - m, 0} + f_{i - m, 1}\\ \end{aligned} \]

上下相加得到 \(f_i = f_{i - 1} + f_{i - m}\)

构造矩阵乘法加速递推。

\[\begin{pmatrix} f_n\\ f_{n - 1}\\ f_{n - 2}\\ \vdots\\ f_{n - m + 1} \end{pmatrix} = \begin{pmatrix} 1 & 0 & \cdots & 0 & 1 \\ 1 & 0 & \cdots & 0 & 0\\ 0 & 1 & \cdots & 0 & 0\\ \vdots& &\ddots\\ 0 & 0 & \cdots & 1 & 0 \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ f_{n - 3}\\ \vdots\\ f_{n - m} \end{pmatrix} \]

于是有 \(F_{n} = AF_{n - 1} = A^2F_{n - 2} = A^{n - m}F_m\)

预处理 \(F_m\),时间复杂度 \(O(m + m^3\log n)\)

注意特判 \(n < m\) 的情况。

submission

NC17890

题意:\(m \times n\) 的方格,每个格子可以填白色或黑色,左右两个不同为白,左右两列不同为全黑,求合法方案数。(\(n\le10^{18}, m \le5\)

先朴素动态规划。

\(f_{i, s}\) 表示第 \(i\) 列状态为 \(s\) 时的方案,'0' 表示白,'1' 表示黑。

考虑 \(s\) 能从哪些 \(s'\) 转移来。

  • \(s\ |\ s' = 2^m - 1\)
  • \(s = 2^m - 1\)\(s'\ne 2^m - 1\)

所以

\[f_{i, s} = \sum_{\begin{aligned}&s\ |\ s' = 2^m - 1\\ &s, \ s'\text{ 不同为 } 2^{m} - 1\end{aligned}}f_{i - 1, s'} \]

又可以看成 \(F_n = A\cdot F_{n - 1} = A^{n - 1}\cdot F_1\) 的形式。

submission

CF718C

题意:给定数列 \(\{a\}\),支持两种操作。

  • 区间 \([l, r]\)\(x\)
  • \(\sum_{i = l}^rf(a_i)\)\(f(1) = f(2) = 1, \ f(n) = f(n - 1) + f(n - 2)\)

\[\begin{pmatrix} f_n\\ f_{n - 1}\\ \end{pmatrix} = \begin{pmatrix} 1 & 1\\ 1 & 0\\ \end{pmatrix} \begin{pmatrix} f_{n - 1}\\ f_{n - 2}\\ \end{pmatrix} \]

写成向量的形式

\[\vec F(n) = A \cdot \vec F(n - 1) = A^n \vec F(0) \]

根据递推式,可以写出 \(\vec F(0) = \begin{pmatrix}1\\0\end{pmatrix}\)

于是可以用 \(\vec{F(a_i)}_{1, 1}\) 来替代原序列,将操作转化为

  • 区间 \([l, r]\) 左乘 \(\begin{pmatrix} 1 & 1\\ 1 & 0\\ \end{pmatrix}^x\)
  • 查询 \(\sum_{i = l}^r\vec{F(a_i)}_{1, 1}\)

用一个 \(2 \times 1\) 的向量表示线段树的节点,\(2 \times 2\) 的向量表示懒标记,维护区间矩阵乘法。

submission

P6327 区间加区间 sin 和

题意:给出一个长度为 \(n\) 的整数序列 \(a_1,a_2,\ldots,a_n\),进行 \(m\) 次操作,操作分为两类。

操作 \(1\):给出 \(l,r,v\),将 \(a_l,a_{l+1},\ldots,a_r\) 分别加上 \(v\)

操作 \(2\):给出 \(l,r\),询问 \(\sum\limits_{i=l}^{r}\sin(a_i)\)


\(\sin(x + v)\)\(\cos(x + v)\) 都是线性递推的。

\[\begin{pmatrix} \sin(x + v) \\ \cos(x + v) \end{pmatrix} = \begin{pmatrix} \cos v & \sin v\\ -\sin v & \cos v\\ \end{pmatrix} \begin{pmatrix} \sin x \\ \cos x \end{pmatrix} \]

线段树维护即可。

submission

斐波*

题意:斐波那契数列 \(\{fib\}\) 满足

\[\begin{aligned} &fib(0) = 0, \ fib(1) = 1\\ &fib(n) = fib(n - 1) + fib(n - 2) \end{aligned} \]

\(S\) 是一个可重集合 \(\left\{s_1,s_2,...,s_{|S|}\right\}\)

\(f(S)\) 定义为

\[\sum_{T \subseteq S} \left[fib(\sum_{s \in T} s)\right]^2 \]

支持两种操作。

  1. \(a_p\) 变为 \(v\)
  2. 计算 \(\sum_{i=l}^{r}\sum_{j=i}^{r}f(\left\{a_i,a_{i+1},..,a_j\right\})\)

定义 \(g(n) = fib^2(n)\)

\[\begin{aligned} g(n) &= 2\cdot g(n - 1) + 2\cdot g(n - 2) - g(n - 3)\\ &\\ \begin{pmatrix} g_n\\ g_{n - 1}\\ g_{n - 2} \end{pmatrix} &= \begin{pmatrix} 2 & 2 & -1\\ 1 & 0 & 0\\ 0 & 1 & 0 \end{pmatrix} \begin{pmatrix} g_{n - 1}\\ g_{n - 2}\\ g_{n - 3}\\ \end{pmatrix}\\ &\\ \end{aligned} \]

证明参考上文 矩阵快速幂优化线性递推.5

写成向量形式。

\[\begin{aligned} \vec G(n) &= A \cdot \vec G(n - 1)\\ &= A^n \cdot \vec G(0) \end{aligned} \]

虽然 \(\vec{G(0)}\) 不存在,但仍可通过递推式求出 \(\vec{G(0)} = \begin{pmatrix}0\\1\\1\\\end{pmatrix}\)

用向量的第一个元素表示答案。

\[\vec F(S) = \sum_{T \subseteq S} \vec G(\sum_{s \in T} s) \]

往集合里新增一个元素 \(a\)

\[\begin{aligned} \vec{F}(S\cup \{a\} ) &= \vec F(S) + \sum_{T \subseteq S} \vec G(\sum_{s \in T} s+ a)\\ \\ &= \vec F(S) + \sum_{T \subseteq S} A^a \vec G(\sum_{s \in T} s)\\ \\ &= \vec F(S) + A^a \cdot \vec F(S)\\ \\ &= (I + A^a) \cdot \vec F(S)\\ \end{aligned} \]

其中 \(I\) 是单位矩阵。

所以

\[\begin{aligned} \vec F(S) &= \prod_{s \in S} (I + A^s) \cdot \vec F(\varnothing)\\ &= \prod_{s \in S} (I + A^s) \cdot \vec G(0)\\ \end{aligned} \]

\((I + A^{a_i})\) 视作元素 \(v_i\)

题目要求的 \(\sum_{i=l}^{r}\sum_{j=i}^{r}f(\left\{a_i,a_{i+1},..,a_j\right\})\)

\[\sum_{i=l}^{r}\sum_{j=i}^{r}\prod_{k=i}^{j}v_k \cdot G(0) \]

即区间 \([l, r]\) 内所有子区间的元素积之和。

考虑分治。

\([l, r]\) 分为 \([l, mid]\)\([mid + 1, r]\)

讨论贡献来源,令 \(\{l, r\}\) 表示 \(\prod_{i = l}^r v_i\)

  • 子区间单独属于左区间或右区间,向下递归。
  • 子区间跨块,贡献为 \(\sum\limits_{i = l}^{mid}\{i, mid\} \cdot \sum\limits_{i = mid + 1}^{r} \{mid + 1, i\}\).

具体实现用线段树内维护 \(4\) 个信息。

对于代表区间 \([l, r]\) 的节点。

  1. \(ans\) 表示 \([l, r]\) 的答案。
  2. \(self = \prod_{i = l}^r v_i\)
  3. \(left = \sum_{i = l}^r\{l, i\}\)
  4. \(right = \sum_{i = l}^r\{i, r\}\)
struct Node {
	Matrix ans, self, l, r;
	Node() { self = I; }
	void operator = (Matrix x){
		ans = self = l = r = x;
	}
	friend Node operator + (Node L, Node R) {
		Node x;
		x.ans = L.ans + R.ans + L.r * R.l;
		x.self = L.self * R.self;
		x.l = L.l + R.l * L.self;
		x.r = R.r + L.r * R.self;
		return x;
	}
} t[N << 2];

submission


线性方程组

Gauss-Jordan 消元法

思想很简单,即

  • 选主元。
  • 选主元不为零的行为主行。
  • 用主行消去主行外的所有主元。

判断无解或无穷解。

如果最终增广矩阵如下。

\[\left[ {\begin{array}{c:c} \begin{matrix} 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 0 & 0 & 1\\ 0 & 0 & 0 & 0 & 0\\ \end{matrix}& \begin{matrix} 1 \\ 1 \\ 1 \\ 1 \\ \end{matrix} \end{array}} \right] \]

最后一行系数矩阵为零,而增广矩阵非零,无解。

如果增广矩阵也为零呢?

\[\left[ {\begin{array}{c:c} \begin{matrix} 1 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 0 & 0 & 1\\ 0 & 0 & 0 & 0 & 0\\ \end{matrix}& \begin{matrix} 1 \\ 1 \\ 1 \\ 0 \\ \end{matrix} \end{array}} \right] \]

可以得到

\[\begin{cases} x_1 = 1 - x_2\\ x_3 = 1 - x_4\\ x_5 = 1 \end{cases} \]

其中 \(x_2, \ x_4 \in \R\) ,有无穷多组解,\(x_2, \ x_4\) 确定,则解确定。

增广矩阵每一行第一个非零元对于的变量称为 首变量(lead variable),化简过程种跳过的变量称为 自由变量(free variable)

因此 \(x_1, x_3, x_5\) 为首变量,\(x_2, x_4\) 为自由变量。

实现:P2455 [SDOI2006] 线性方程组

时间复杂度 \(O(n^3)\)

#include<bits/stdc++.h>
using namespace std;

using db = double;
constexpr int N = 105;

db a[N][N];
int n;

bool neq(db x, db y) {
	return fabs(x - y) > 1e-6;
}


int main() {
	cin.tie(0)->sync_with_stdio(0);
	
	cin >> n;
	for(int i = 1; i <= n; ++ i) {
		for(int j = 1; j <= n + 1; ++ j) {
			cin >> a[i][j];
		}
	}
	int cur = 1;
	for(int k = 1; k <= n; ++ k) {					\\ 选主元
		for(int i = cur; i <= n; ++ i) {
			if(neq(a[i][k], 0)) {					\\ 选主行	
				for(int j = k; j <= n + 1; ++ j) {
					swap(a[cur][j], a[i][j]);
				}
				break;
			}
		} 
		if(neq(a[cur][k], 0)) {						\\ 消元
			db x = a[cur][k];
			for(int j = k; j <= n + 1; ++ j) {
				a[cur][j] /= x;
			}
			for(int i = 1; i <= n; ++ i) {
				if(i == cur) continue;
				db x = a[i][k];
				for(int j = k; j <= n + 1; ++ j) {
					a[i][j] -= x * a[cur][j];
				}
			}
			++ cur;			\\ 主行移至下一行
		}
	}
	for(int i = cur; i <= n; ++ i) {
		if(neq(a[i][n + 1], 0)) {
			cout << -1;
			exit(0);
		}
	}
	if(cur != n + 1) {
		cout << 0;
	}
	else {
		for(int i = 1; i <= n; ++ i) {
            cout << "x" << i << "=" << fixed << setprecision(5) << a[i][n + 1] << '\n';
        }
	}
	return 0;
}
异或方程组

异或可看成模 \(2\) 意义下的加法,写法与加法无异。

有几个优化的点。

  • bitset<N> a[N] 替代系数矩阵。
  • 交换用 swap(a[i], a[cur])
  • 消元用 a[i] ^= a[cur])

时间复杂度 \(O(\dfrac{n^3}{w})\)

例题

POJ1222

题意:\(5 \times 6\) 的方格,改变一盏灯的状态会改变周围所有灯的状态,给出一种开关方案使得所有灯熄灭。

\(x_{i, j} = 0 / 1\) 表示 \((i, j)\) 有无操作。

如果 \((i, j)\) 初状态为 \(a_{i, j}\),则达到末状态需要满足 \(a_{i, j} \oplus\)

\(30\) 个未知数与 \(30\) 个方程进行高斯消元。

如果处理无穷多组解的情况?将自由变量全赋值为 \(0\),第 \(i\) 行的首变量即列的增广一列的值。

submission

CF1344F

题意:一个包含三原色 RYB 的序列混合的结果定义为:

  • 如果序列开头两项颜色相同,将这两项删去。
  • 如果序列开头两项颜色不同,将这两项替换为与这两种颜色不同的颜色。
  • 特别地,如果序列为空,则混合的结果是白色 W

有一个长为 \(n\) 的颜色序列(某些位置为空),给出 \(k\) 个操作:

  • mix:选择一个子序列和混合时的顺序(忽略空位置),给出其混合后的结果。
  • RY:选择一个子序列,将所有 R 变为 Y,所有 Y 变为 RB 和空位置不变。
  • RB:选择一个子序列,将所有 R 变为 B,所有 B 变为 RY 和空位置不变。
  • YB:选择一个子序列,将所有 Y 变为 B,所有 B 变为 YR 和空位置不变。

你需要根据 mix 操作的信息确定一种可能的原序列。保证 \(n, k \leqslant 10^3\)


WRYB 依次赋值为 \(0, 1, 2, 3\),可以发现 mix 操作即对取出元素做异或。

\((00)_2, (01)_2, (10)_2, (11)_2\) 表示为 \((b_ia_i)_2\)

  • RY,交换选定数的 \(a_i, b_i\)
  • RB\(b_i \leftarrow a_i \oplus b_i\)
  • YB\(a_i \leftarrow a_i \oplus b_i\)

动态维护当前的 \(a_i\)\(b_i\) 与初始值的关系,设 \(i\) 初始为 \((b_0a_0)_2\)

  • \(t_i = (00) \iff a_i = 0\)
  • \(t_i = (01) \iff a_i = a_{i_0}\)
  • \(t_i = (10) \iff a_i = b_{i_0}\)
  • \(t_i = (11) \iff a_i = a_{i_0} \oplus b_{i_0}\)

\(b_i\) 同理维护一个 \(t_i'\)

\(a_{i_0}\)\(b_{i_0}\) 表示为 \(2n\) 个未知数。

对于一次 mix 操作,可以对分别对当前 \(\{a_i\}\)\(\{b_i\}\) 异或得到关于 \(a_{i_0}\)\(b_{i_0}\)的两组方程。

高斯消元求出所有\(a_{i_0}, \ b_{i_0}\)

submission


线性基

引入

线性基即高中数学向量基底拓展到 \(n\) 维的情况。

线性基内元素线性无关,即不能互相表示。

线性基可以表示出任意当前线性空间内的元素。

异或线性基

对于一组基 \(\{b\}\),其内元素不能通过异或运算互相表示。

  1. 高斯消元求线性基

    求解 \(\{a\} = {1, 3, 4, 6, 7}\) 的一组基底。

    把一个 \(n\) 位二进制数看作 \(n\) 维向量。

    \[\begin{bmatrix} 1 & 0 & 0\\ 1 & 1 & 0\\ 0 & 0 & 1\\ 0 & 1 & 1\\ 0 & 1 & 1\\ \end{bmatrix} \]

    执行高斯消元。

    \[\begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1\\ 0 & 0 & 0\\ 0 & 0 & 0\\ \end{bmatrix} \]

    剩下 \(3\) 个非零元素 \(\{1, 2, 4\}\)即为 \(\{a\}\) 的一组基。

    显然可用 \(1, 2, 4\) 表示出 \(3, 6, 7\) 却无法互相表示。

    引理:大小为 \(sz\) 的基底能组成 \(2^{sz}\) 个不同的数。

    证明:高斯消元得到的基底互不相交,任意组合互不相同。

  2. 在线求线性基

    高斯消元是离线的,复杂且有局限性。

    \(b_i\) 为基底中最高位为 \(i\) 的元素。

    用如下方法插入新元素,其实际意义与高斯消元无异。

    void insert(int x) {
    	for(int i = 30; i >= 0; -- i) {
    		if(x >> i & 1) {
    			if(b[i] == 0) {
    				b[i] = x;
    				return;
    			}
    			x ^= b[i];
    		}
    	}
    }
    
  3. 求线性基内得到的最大(小)元素

    高斯消元得到的基底元素交集为空,全部异或起来即最大值。

    在线插入法可以如下贪心:

    int get_max() {
    	int cur = 0;
    	for(int i = 30; i >= 0; -- i) {
    		cur = max(cur, cur ^ b[i]);
    	}
    	return cur;
    }
    
  4. 判断某个元素是否在线性空间内存在

    低位操作不会影响高位,从高到低贪心。

    bool exist(int x) {
    	int cur = 0;
    	for(int i = 30; i >= 0; -- i) {
    		if((x >> i & 1) != (cur >> i & 1)) {
    			cur ^= b[i];
    		}
    	}
    	return x == cur;
    }
    

    模板submission

例题

CF1101G

题意:

给定 \(\{a_i\}\),试将其划分为尽可能多的非空子段,满足每一个元素出现且仅出现在其中一个子段中,且在这些子段中任取若干段,它们包含的所有数的异或和不能为\(0\)

如果不存在方案输出 \(-1\),否则输出所有合法的划分方案中最大的划分数。


表示成前缀异或。

\(i_1, i_2, \dots i_k\) 为划分点。

\(\{s_{i_2}\oplus s_{i_1 - 1}, \dots s_{i_k}\oplus s_{i_{k - 1} - 1}\}\) 互相组合不能表示出零。

表示出零,当且仅当存在元素能被其他元素表示。

所以 \(\{s_{i_2}\oplus s_{i_1 - 1}, \dots s_{i_k}\oplus s_{i_{k - 1} - 1}\}\) 的线性基(等效于 \(\{s_i\}\) 的线性基)为极大符合条件集合。

线性基的大小唯一确定,无解的情况为 \(s_n = 0\)

submisson


形式幂级数

多项式与形式幂级数

  • 多项式:\(A(x) = \sum_{i = 0}^na_ix^i\)
  • 形式幂级数:\(A(x) = \sum_{i \ge 0}a_ix^i\)

其中 \(a_i \in K\)\(K\) 是一个域,通常考虑 \(K = \mathbb{R}\)\(K = \mathbb{Z}_{p}\)

注意这里的 \(x\) 可以理解为独立于域 \(K\) 的一个符号。

形式幂级数的运算

\(A(x) = \sum_{i \ge 0} a_ix^i, \ B(x) = \sum_{i \ge 0} b_ix^i\)

  • 加法:\(A(x) + B(x) = \sum_{i \ge 0} (a_i + b_i)x^i\)
  • 减法:\(A(x) - B(x) = \sum_{i \ge 0} (a_i - b_i)x^i\)
  • 乘法:\(A(x)\times B(x) = \sum_{k \ge 0} (\sum_{i = 0}^ka_i b_{k - i})x^k\)

可以验证,形式幂级数在以上定义的 \(+, -, \times\) 下形成一个环。

记号:记形式幂级数(或多项式)\(A(x)\)\(x^n\) 项的系数为 \([x^n]A(x)\)

形式幂级数的逆元

  • 形式幂级数的逆元:\(A(x)B(x) = 1\)

  • 逆元存在的条件:\([x^0]A(x) \neq 0\)

  • 暴力计算的方法:递推。

    \(A(x) = a_0 + a_1x + a_2x^2 +\cdots, \ B(x) = b_0 + b_1x + b_2x^2 + \cdots\)

    \(A(x)B(x) = a_0b_0 + (a_0b_1 + a_1b_0)x + \cdots + (a_0b_n + a_1b_{n - 1} + \cdots + a_nb_0)x^n + \cdots\)

    \(A(x)B(x) = 1\) 当且仅当

    \[\begin{cases} a_0b_0 = 1\\ a_0b_1 + a_1b_0 = 0\\ \vdots\\ a_0b_n + a_1b_{n - 1} + \cdots + a_nb_0 = 0\\ \vdots \end{cases} \]

    所以 \(b_0 = a_0^{-1}\)\(b_n = (a_1b_{n - 1} +\cdots+ a_nb_0) \cdot a_0^{-1}\)

常见的逆
  1. \(A(x) = 1 + x + x^2 + \cdots\)\(B(x) = 1 - x\),即 \(A(x) = \dfrac{1}{1 - x}\)

  2. \(A(x) = 1 + ax + a^2x^2 + \cdots\)\(B(x) = 1 - ax\),即 \(A(x) = \dfrac{1}{1 - ax}\)

  3. \(A(x) = 1 + f(x) + f^2(x) + \cdots\)\(B(x) = 1 - f(x)\),即 \(A(x) = \dfrac{1}{1 - f(x)}\)

  4. \(A(x) = {k - 1\choose 0} + {k \choose1}x + {k + 1\choose2}x^2 + \cdots\)\(B(x) = (1 - x)^k\),即 \(A(x) = \dfrac{1}{(1 - x)^k}\)

    \(A(x) = (1 + x + x^2 + \cdots)^k = \dfrac{1}{(1 - x)^k}\)

    即不定方程 \(x_1 + x_2 + \cdots+ x_k = n, \ \forall x_i \ge0\) 的常生成函数。

    同时,我们知道该方程的解的数量为 \(n + k - 1\choose k - 1\)

    所以有 \([x^n]A(x) = {n + k - 1\choose k - 1} = {n + k - 1\choose n}\)


常生成函数(Ordinary Generating Function)

定义

一个数列 \(\{a_n\}\) 对应的常生成函数为 \(A(x) = \sum_{n \ge 0} a_nx^n\)

  1. 两种物体,其中取 \(i\) 个第 \(1\) 种物体的方案数为 \(a_i\),取 \(j\) 个第 \(2\) 种物体的方案数为 \(b_i\),求取 \(k\) 个物体的方案数 \(c_k\)

    \[C(x) = \sum_{k \ge 0} c_k = \sum_{k \ge 0} \sum_{i = 0}^ka_ib_{k - i} = A(x) B(x) \]

    所以 \(c_k = [x^k](A(x)B(x))\)

  2. \(n\) 个水果,苹果个数必须是偶数,香蕉个数必须是 \(3\) 的倍数,草莓个数不超过 \(5\),求方案数。

    \(a_i\) 为取 \(i\) 个苹果的方案数,则 \(a = \{1, 0, 1, 0, 1\cdots\}\)

    所以

    • \(A(x) = 1 + x^2 + x^4 + \cdots\)
    • \(B(x) = 1 + x^3 + x^6 + \cdots\)
    • \(C(x) = 1 + x^2 + x^3 + x^4 + x^5\)

    \(n\) 个水果的方案为 \(A(x)B(x)C(x)\)\(x^n\) 项的系数。

    可以先 \(O(n^2)\)\(A(x)\)\(B(x)\) 乘积的前 \(n\) 项,再 \(O(n^2)\)\(A(x)B(x)\)\(C(x)\) 乘积的前 \(n\) 项。

不定方程的解的数量

求不定方程 \(x_1 + x_2 = n\) 的解的数量,其中 \(l_1 \le x_1 \le r_1, \ l_2 \le x_2 \le r_2\)

令数列 \(\{a_n\}\) 表示 \(x_1 = n\) 的解的数量,则 \(\forall n \in [l_1, r_1], \ a_n = 1\)

那么 \(\{a_n\}\) 的常生成函数 \(F_1(x) = \sum_{i = l_1}^{r_1} x^i\)

所以解的数量为 \([x^n] (F_1(x)F_2(x))\)

同理,推广到 \(k\) 元不定方程,解的数量为 \([x^n](\prod F_i(x))\)

拓展:求 \(x_1 + 2x_2 + 3x_3 = n\) 的正整数解个数。

\(F_1(x) = \sum_{n \ge 1} x^n = x + x^2 + x^3 + \cdots\)

\(F_2(x) = \sum\limits_{n \ge 1, \ 2 \mid n} x^n = x^2 + x^4 + x^6 + \cdots\)

\(F_3(x) = \sum\limits_{n \ge 1, \ 3 \mid n} x^n = x^3 + x^6 + x^9 + \cdots\)

相乘即可。

定理

\(S = \{a_1, a_2, a_3, \dots a_k\}\),且 \(a_i\) 可以取的次数集合为 \(M_i\),记 \(F_i = \sum\limits_{u \in M_i}x^u\),则从 \(S\) 中取 \(n\) 个元素的方案 \(g(n)\) 的常生成函数 \(G(x) = \sum_{i \ge 0}g(i)x^i\),满足

\[G(x) = F_1(x) F_2(x) \dots F_k(x) \]

递推关系

  1. 斐波那契数列满足 \(a_0 = 0, a_1 = 1, a_2 = 1, a_n = a_{n - 1} + a_{n - 2}\),求其常生成函数。

    \[\begin{aligned} \\ A(x) &= a_0 + a_1x + a_2x^2 + a_3x^3 +\cdots\\ \\ &= a_0 + a_1x + (a_0 + a_1)x^2 + (a_1 + a_2)x^3 + \cdots\\ \\ &= x + (a_0x^2 + a_1x^3 + \cdots) + (a_1x^2 + a_2x^3 + \cdots)\\ \\ &= x + xA(x) + x^2A(x) \end{aligned} \]

    所以 \(A(x) = \dfrac{x}{1 - x - x^2}\)

  2. 利用常生成函数,求解斐波那契通项公式。

\[ \begin{aligned} A(x) &= \dfrac{x}{1 - x - x^2}\\ \\ &= x(\dfrac{c}{1 - ax} + \dfrac{d}{1 - bx})\\ \\ &= cx(1 + ax + a^2x^2 + \cdots) + dx(1 + bx + b^2x^2 + \cdots)\\ \\ &= \sum_{n \ge 1} (a^{n - 1}c + b^{n - 1}d) x^n \end{aligned} \]

待定系数解得

\[ \begin{cases} a = \dfrac{1 + \sqrt 5}{2} \\ b = \dfrac{1 - \sqrt 5}{2} \\ c = \dfrac{1}{\sqrt 5} \times \dfrac{1 + \sqrt 5}{2} \\ d = \dfrac{1}{\sqrt 5} \times \dfrac{1 - \sqrt 5}{2} \end{cases} \]

所以

\[ \begin{aligned} &\left[x^0\right] A(x)= 0\\ &\left[x^n\right] A(x) = \dfrac{1}{\sqrt 5}[(\dfrac{1 - \sqrt 5}{2})^n + (\dfrac{1 + \sqrt 5}{2})^n] \end{aligned} \]

  1. 假设数列 \(\{a_n\}\) 存在递推关系 \(a_n = c_1a_{n - 1} + c_2a_{n - 2} + \cdots + c_ka_{n - k}\),求其常生成函数。

    \[\begin{aligned} A(x) &= a_0 + a_1x + \cdots + a_{k - 1}x^{k - 1} + \sum_{n \ge k}(c_1a_{n - 1} +\cdots + c_ka_{n - k})x^n\\ \\ &= a_0 + \cdots + a_{k - 1}x^{k - 1} + c_1x(A(x) -\sum_{i \le k - 2}a_ix^i) + c_2x^2(A(x) - \sum_{i \le n - 3}a_ix^i) + \cdots + c_kx^kA(x)\\ \\ &= (c_1x + \cdots + ck_x^k)A(x) + B(x) \end{aligned} \]

    \(A(x)\) 可以表示为 \(\dfrac{B(x)}{1 - (c_1x + \cdots + ck_x^k)}\)

    若想将 \(A(x)\) 还原为 \(\sum a_ix^i\) 的形式,待定系数 \(A(x) = B(x) \sum \dfrac{v_i}{1 - u_ix}\)

例题

A-背包

\[G(x) = \prod F(x) = \dfrac{x}{(1 - x)^4} \]

那么 \([x^n]G(x) = [x^{n - 1}]\dfrac{1}{(1 - x)^4} = \begin{pmatrix}n + 2\\ 3\end{pmatrix} = \dfrac{n(n + 1)(n + 2)}{6}\)

submission

CF451E

题意:\(n\) 种花,分别 \(f_1, f_2\dots,f_n\) 个,求取 \(s\) 朵花的方案数,\(n \le 20, s \le 10^{18}\)

\[\begin{aligned} F_i(x) &= \dfrac{1 - x^{f_i + 1}}{1 - x}\\ &\\ G(x) &= \dfrac{\prod (1 - x^{f_i + 1})}{(1 - x)^n} \end{aligned} \]

不妨令 \(F(x) = \prod (1 - x^{f_i + 1})\)

\[[x^s]G(x) = \sum_{i = 0}^s [x^i]F(x) \cdot [x^{s - i}]\dfrac{1}{(1 - x)^n} = \sum_{i = 0}^s [x^i]F(x) \begin{pmatrix}s - i + n - 1\\n - 1\end{pmatrix} \]

\(n\) 很小,暴力展开 \(F(x)\) 的系数。

submission

P6078 [CEOI2004] Sweets

题意:\(n\) 种糖,分别 \(m_1, m_2\dots,m_n\) 个,求吃至少 \(a\),不多于 \(b\) 的方案数 ,\(n \le 10, a \le 10^7\)

\(F(x) = \prod (1 - x^{m_i + 1})\)

\[\begin{aligned} \sum_{s = a}^b[x^s]G(x) &= \sum_{s = a}^b\sum_{i = 0}^s [x^i]F(x) \begin{pmatrix}s - i + n - 1\\n - 1\end{pmatrix}\\ &= \sum_{i = 0} [x^i]F(x) \sum_{s = a}^b\begin{pmatrix}s - i + n - 1\\n - 1\end{pmatrix}\\ \end{aligned} \]

引理:\(\sum_{i = a}^b\begin{pmatrix}i\\j\end{pmatrix} = \begin{pmatrix} b + 1\\ j + 1\end{pmatrix} - \begin{pmatrix} a\\ j + 1\end{pmatrix}\)

证明:

\[\begin{matrix} (a, j) & (a, j + 1)\\ (a + 1, j) & (a + 1, j + 1)\\ (a + 2, j) & (a + 2, j + 1)\\ \vdots&\vdots\\ (b, j) & (b, j + 1)\\ \end{matrix} \]

其中

\[\begin{aligned} \begin{pmatrix}a \\j + 1 \end{pmatrix} + \begin{pmatrix} a\\j \end{pmatrix} + \begin{pmatrix} a + 1\\ j\end{pmatrix} + \cdots \begin{pmatrix} b\\ j\end{pmatrix} &= \begin{pmatrix} a + 1\\ j + 1\end{pmatrix} + \begin{pmatrix} a + 1\\ j\end{pmatrix} + \cdots \begin{pmatrix} b\\ j\end{pmatrix}\\ \\ &= \begin{pmatrix} a + 2\\ j + 1\end{pmatrix} + \begin{pmatrix} a + 2\\ j\end{pmatrix} + \cdots \begin{pmatrix} b\\ j\end{pmatrix}\\ \\ &= \begin{pmatrix} b\\ j + 1\end{pmatrix} +\begin{pmatrix} b\\ j\end{pmatrix}\\ \\ &= \begin{pmatrix} b + 1\\ j + 1\end{pmatrix} \end{aligned} \]

所以 \(\sum_{i = a}^b\begin{pmatrix}i\\j\end{pmatrix} = \begin{pmatrix} b + 1\\ j + 1\end{pmatrix} - \begin{pmatrix} a\\ j + 1\end{pmatrix}\)

所以原问题答案为

\[\begin{aligned} \sum_{s = a}^b[x^s]G(x) &= \sum_{i = 0} [x^i]F(x) \sum_{s = a}^b\begin{pmatrix}s - i + n - 1\\n - 1\end{pmatrix}\\ \\ &= \sum_{i = 0} [x^i]F(x) \begin{pmatrix}b - i + n\\n\end{pmatrix} - \begin{pmatrix}\max(a, i) - i + n - 1\\n\end{pmatrix}\\ \end{aligned} \]

题目模数 \(P = 2004\) 不好处理。

对于模数非质数的除法,可以先把模数乘上除数,再将运算结果除以除数得到答案。

不妨先令答案乘上 \(n!\),同时 \(P \leftarrow P \cdot n!\),最后再除以 \(n!\)

submission


指数生成函数(Exponential Generating Function)

定义

一个数列 \(\{a_n\}\) 的指数生成函数为 \(A(x) = \sum\limits_{n \ge 0}a_n\dfrac{x^n}{n!}\)

对于 \(\{a_n\} = \{1, 1, 1, \cdots\}\)\(A(x) = 1 + \dfrac{x}{1!} + \dfrac{x^2}{2!} + \dfrac{x^3}{3!} + \cdots = e^x = \exp (x)\)

  1. 两种物体,其中取 \(i\) 个第 \(1\) 种物体的方案数为 \(a_i\),取 \(j\) 个第 \(2\) 种物体的方案数为 \(b_i\),求取 \(k\) 个物体并排成一排的方案数 \(c_k\)

    \(c_k = \sum\limits_{i = 0}^k a_ib_{k - i}\dfrac{k!}{i!(k - i !)}\)

    \(C(x) = \sum\limits_{k \ge 0} \dfrac{c_k}{k!} = \sum\limits_{k \ge 0}\sum\limits_{i = 0}^k \dfrac{a_i}{i!}\cdot \dfrac{b_{k - i}}{(k - i !)} = A(x) B(x)\)

  2. \(1, 2, 3, 4\) 组成 \(6\) 位数,每个数字出现次数不得大于 \(2\),求不同的六位数个数。

    \(\{a\} = \{1, 1, 1, 0, 0 \cdots\}, \ F(x) = 1 + \dfrac{x}{1!} + \dfrac{x^2}{2!}\)

    \(G(x) = F^4(x)\)

    则不同的六位数个数为 \(6! [x^6]G(x)\)

定理

\(S = \{a_1, a_2, a_3, \dots a_k\}\),且 \(a_i\) 可以取的次数集合为 \(M_i\),记 \(F_i = \sum\limits_{u \in M_i}x^u\),则从 \(S\) 中取 \(n\) 个元素排成一排的方案 \(g(n)\) 的指数生成函数 \(G(x) = \sum_{i \ge 0}g(i)\dfrac{x^i}{i!}\),满足

\[G(x) = F_1(x) F_2(x) \dots F_k(x) \]

公式(定义)

  • \(\exp(x) = 1 + \dfrac{x}{1!} + \dfrac{x^2}{2!} + \cdots = \sum_{n \ge 0}\dfrac{x^n}{n!}\)
  • \(\exp(ax) = 1 + \dfrac{ax}{1!} + \dfrac{a^2x^2}{2!} + \cdots = \sum_{n \ge 0}\dfrac{a^nx^n}{n!}\)
  • \(\exp(f(x)) = 1 + \dfrac{f(x)}{1!} + \dfrac{f^2(x)}{2!} + \cdots = \sum_{n \ge 0}\dfrac{f^n(x)}{n!}\)
  • \(\dfrac{\exp(x) + \exp(-x)}{2} = \sum_{n \ge 0} [2 \mid n] \dfrac{x^n}{n!}\)
  • \(\dfrac{\exp(x) - \exp(-x)}{2} = \sum_{n \ge 0} [2 \nmid n] \dfrac{x^n}{n!}\)

例题

POJ3734

题意:\(n\) 个格子排成一列,每个格子可以被涂成红、黄、蓝或绿,偶数个格子是红和绿,求方案数。

\[\begin{aligned} H(x) &= F^2(x) G^2(x) \\ \\ &= \exp^2(x)(\dfrac{\exp(x) + \exp(-x)}{2})^2\\ \\ &= \dfrac{\exp(4x) + 2\exp(2x) + 1}{4} \\ \\ &= \dfrac{1}{4} + \sum_{n \ge 0} \dfrac{1}{4}(\dfrac{(4x)^n}{n!} + 2\dfrac{(2x)^n}{n!})\\ \\ &= 1 + \sum_{n \ge 1}\dfrac{4^{n - 1} + 2^{n - 1}}{n!} x^n \end{aligned} \]

submission

CF891E

题意: \(n\) 个数,\(k\) 次操作,每次随机选择一个数 \(x \in [1,n]\),把 \(a_x\) 减一,并将答案增加除 \(a_x\) 外所有数的乘积。

求最终答案的期望,对 \(10^9 + 7\) 取模。

第一次操作对答案的贡献为

\[\prod[i \ne x] a_i = \prod a_i - \prod (a_i - [i =x]) \]

以此类推,当前轮的贡献为当前所有数之积减去下一轮所有数之积。

最终结果可以表示为 \(\prod a_i - \prod(a_i - x_i)\)\(x_i\)\(i\) 被操作的次数。

所以后项的期望值

\[\begin{aligned} \mathbb{E'} &= \dfrac{\sum\limits_{x_1 + \cdots + x_n = k} (a_1 - x_1) \cdots(a_n - x_n) \cdot \begin{pmatrix}k\\x_1, \cdots, x_n\end{pmatrix}}{n^k} \\ \\ &= \dfrac{\sum\limits_{x_1 + \cdots + x_n = k} (a_1 - x_1) \cdots(a_n - x_n) \cdot \dfrac{k!}{x_1!\cdots x_n!}}{n^k} \\ \\ &= \dfrac{k!}{n^k} \sum_{x_1 + \cdots + x_n = k} \dfrac{a_1 - x_1}{x_1!}\cdots\dfrac{a_n - x_n}{x_n!} \end{aligned} \]

\(F_i(x) = \sum_{j \ge 0} \dfrac{a_i - j}{j!}x^j\)

\[\begin{aligned} F_i(x) &= a_i\sum_{j \ge 0} \dfrac{x^j}{j!} - x\sum_{j - 1\ge 0} \dfrac{x^{j - 1}}{(j - 1)!}\\ \\ &= a_i\exp(x) - x\exp(x)\\ \\ &= (a_i - x)\exp(x) \end{aligned} \]

\(G(x) = \prod(a_i - x)\)

那么

\[\begin{aligned} \mathbb{E'} &=\dfrac{k!}{n^k}[x^k](\prod F_i(x))\\ \\ &= \dfrac{k!}{n^k}\sum_{i = 0}^{k}[x^i]G(x)\cdot [x^{k - i}]\exp^n(x)\\ \\ &= \dfrac{k!}{n^k}\sum_{i = 0}^{\min(n, k)}[x^i]G(x)\cdot \dfrac{n^{k - i}}{(k - i)!}\\ \\ &= \dfrac{1}{n^k}\sum_{i = 0}^{\min(n, k)}[x^i]G(x)\cdot n^{k - i} \cdot k^{\underline{i}} \end{aligned} \]

由于 \(i > n\)\(G(x)\) 系数为 \(0\),所以枚举到 \(\min(n, k)\) 即可。

submission

Catalan 数

推导

\(n + 1\) 个数相乘 \(x_0x_1x_2\cdots x_n\),求其结合顺序的方案数。如 \(n = 3\) 时,有 \(5\) 种方案:

\[x_0(x_1(x_2x_3)), \ x_0((x_1x_2)x_3), \ (x_0x_1)(x_2x_3), \ (x_0(x_1x_2))x_3, \ ((x_0x_1)x_2)x_3 \]

枚举最后一步在哪划分,得到递推式

\[\begin{aligned} &c_0 = 1, \ c_1 = 1\\ &c_n = c_0c_{n - 1} + c_1c_{n - 2} + \cdots + c_{n - 1}c_0 \end{aligned} \]

考虑其生成函数

\[\begin{aligned} C(x) &= \sum_{n \ge 0}c_nx^n \\ &= 1 + x + \sum_{n \ge 2}(\sum_{i = 0}^{n - 1}c_ic_{n - 1 - i}) x^n\\ \\ &= 1 + x + x\sum_{n - 1 \ge 1}(\sum_{i = 0}^{n - 1}c_ic_{n - 1 - i}) x^{n - 1}\\ \\ &= 1 + x + x\sum_{n \ge 1}(\sum_{i = 0}^{n}c_ic_{n - i}) x^{n}\\ \\ &= 1 + x + x(C^2(x) - 1) \end{aligned} \]

\(C(x) = \dfrac{1 \pm \sqrt{1 - 4x}}{2x}\)

若满足 \(g^2(x) = f(x)\),则 \([x^0]g(x) > 0\) 的记作 \(\sqrt {f(x)}\)\([x^0]g(x) < 0\) 的记作 \(-\sqrt {f(x)}\)

由于 \(4x\) 不存在逆元(常数项为 \(0\)),必然被分子约掉。

而分子上如果取正号,则常数项不为 \(0\),不能约去常数项为 \(0\) 的式子。

所以 \(C(x) = \dfrac{1 - \sqrt{1 - 4x}}{2x}\)

利用广义二项式定理,展开

\[\begin{aligned} C(x) &= \dfrac{1}{2x}(1 - \sum_{n \ge 0}\begin{pmatrix}\frac{1}{2}\\n\end{pmatrix}(-4x)^n)\\ &= -\dfrac{1}{2x}\sum_{n \ge 1}\begin{pmatrix}\frac{1}{2}\\n\end{pmatrix}(-4x)^n\\ &= \sum_{n -1 \ge 0}\begin{pmatrix}\frac{1}{2}\\n\end{pmatrix}2^{2n - 1}(-x)^{n - 1}\\ &= \sum_{n \ge 0}\begin{pmatrix}\frac{1}{2}\\n + 1\end{pmatrix}2^{2n + 1}(-x)^n\\ \end{aligned} \]

广义组合数:\(\alpha \in \mathbb{R}, \ \begin{pmatrix}\alpha\\0\end{pmatrix} = 1,\ \begin{pmatrix}\alpha\\k\end{pmatrix} = \dfrac{\alpha(\alpha - 1) \cdots(\alpha - k + 1)}{k!}\)

广义二项式定理:\((x + y)^\alpha = \sum\limits_{k = 0}^{+\infty}\begin{pmatrix}\alpha\\k\end{pmatrix}x^{\alpha - k}y^k\)

可以推出卡特兰数的通项公式

\[\begin{aligned} \left[x^n\right]C(x) &= \dfrac{\frac{1}{2}(\frac{1}{2} - 1)(\frac{1}{2} - 2)\cdots(\frac{1}{2} - n)}{(n + 1)!} (-1)^n2^{2n + 1}\\ \\ &= \dfrac{\frac{1}{2}(-\frac{1}{2})(-\frac{3}{2})\cdots(-\frac{2n - 1}{2})}{(n + 1)!} (-1)^n2^{2n + 1}\\ \\ &= \dfrac{1 \times 1 \times 3 \times \cdots \times(2n - 1)}{(n + 1)!} 2^{n}\\ \\ &= \dfrac{1}{(n + 1)!}\cdot \dfrac{(2n)!}{2^n \cdot n!} 2^{n}\\ \\ &= \dfrac{1}{n + 1}\cdot \dfrac{(2n)!}{(2n - n)!\cdot n!} = \dfrac{1}{n + 1}\begin{pmatrix}2n\\n\end{pmatrix} \end{aligned} \]

多项式的表示形式

系数表示与点值表示

假设 \(f(x)\) 是一个 \(n\) 次多项式,则 \(f(x)\) 的系数表示为 \(f(x) = a_nx^n + a_{n - 1}x^{n - 1} + \cdots + a_0\)

\(f(x)\) 的点值表示为 \((x_0, f(x_0)), \ (x_1, f(x_1)), \dots, (x_n, f(x_n))\),其中 \(\forall i \neq j, \ x_i \neq x_j\)

  • \(n + 1\) 个点值可以表示一个 \(n\) 次多项式。

  • 在点值表示下 \(n\) 次多项式的乘法复杂的为 \(O(n)\)

    \(h(x) = f(x) \cdot g(x)\),则 \(\forall i \in [0, n], \ h(x_i) = f(x_i) \cdot g(x_i)\)

复数与单位根

复数的指数形式

\(a + bi = re^{i\theta}\),其中 \(r = \sqrt {a^2 + b^2}, \ \tan \theta = \dfrac{b}{a}\)

欧拉公式:\(e^{ix} = \cos x + i\sin x\)

单位根

\(x^n = 1\) 在复数域上的根称为 \(n\) 次单位根。\(n\) 次单位根有 \(n\) 个,形式为 \(\omega_{n}^k = e^{i\frac{2k\pi}{n}}\)

单位根在复平面上等分单位圆。

单位根的性质:

  • \(\omega_n^k = \omega_{2n}^{2k}\)
  • \(\omega_{2n}^{k + n} = -\omega_{2n}^{k}\)

快速傅里叶变换(Fast Fourier Transform)

离散傅里叶变换(Discrete Fourier Transform)

将多项式 \(A(x) = a_0 + a_1x + \dots + a_{n - 1}x^{n - 1}\) 转化为其点值形式 \((\omega_n^k, \ A(\omega_n^k)), \ (k = 0, 1, \dots, n - 1)\)

不妨令 \(n\)\(2\) 的整次幂。

把原式拆成奇偶两部分,即 \(A(x) = (a_0 + a_2x^2 + \cdots + a_{n - 2}x^{n - 2}) + (a_1 + a_3x^3 + \cdots + a_{n - 1}x^{n - 1})\)

\(B(x) = a_0 + a_2x + \cdots + a_{n - 2}x^{n / 2 - 1}, \ \ C(x) = a_1 + a_3x + \cdots + a_{n - 2}x^{n / 2 - 1}\)

\(A(x) = B(x^2) + xC(x^2)\)

对于 \(k \in [0, n / 2 - 1]\)

\[\begin{aligned} A(\omega_n^k) &= B(\omega_n^{2k}) + \omega_n^{k}C(\omega_n^{2k})\\ \\ &= B(\omega_{n / 2}^{k}) + \omega_n^{k}C(\omega_{n / 2}^{k})\\ \end{aligned} \]

对于另一半的点值,可用 \(A(\omega_n^{k + n / 2})\) 表示,即

\[\begin{aligned} A(\omega_n^{k + n / 2}) &= B(\omega_n^{2k + n}) + \omega_n^{k + n / 2}C(\omega_n^{2k + n})\\ \\ &= B(\omega_{n / 2}^{k}) - \omega_n^{k}C(\omega_{n / 2}^{k})\\ \end{aligned} \]

具体的讲,当 \(n = 8\) 时,各项存在如下关系:

\(T(n) = 2T(n / 2) + O(n)\)

可以直观看出,以这种方式将系数表示转化为点表示的时间复杂度为 \(O(n \log n)\)

对于具体实现

  • 分治(递归,常数大)。

  • 蝴蝶变换(bit-reversal permutation)(非递归,常数小)。

    观察上图第一行和最后一行各项的二进制表示,互相颠倒。

    因此可以预处理最后一行的系数,自下而上递推。

逆离散傅里叶变换(Inverse DFT)

将多项式的点值表示 \((\omega_n^k, \ b_k), \ (k = 0, 1, \dots, n - 1)\) 转化为其系数表示 \(A(x) = a_0 + a_1x + \dots + a_{n - 1}x^{n - 1}\)

\(n \times n\) 的矩阵 \(\Omega\),其中 \(\Omega_{i, j} = \omega_n^{ij}\),设向量 \(a = (a_0, a_1, \dots, a_{n - 1}), \ b = (b_0, _1, \dots, b_{n - 1})\)

则 IDFT 相当于求解方程 \(\Omega a = b\)

\[\begin{pmatrix} (\omega_n^0)^0 & (\omega_n^0)^1 & \cdots & (\omega_n^0)^{n - 1}\\ (\omega_n^1)^0 & (\omega_n^1)^1 & \cdots & (\omega_n^1)^{n - 1}\\ \vdots & \vdots& \ddots & \vdots \\ (\omega_n^{n- 1})^0 & (\omega_n^{n - 1})^1 & \cdots & (\omega_n^{n - 1})^{n - 1}\\ \end{pmatrix} \begin{pmatrix} a_0\\ a_1\\ \vdots\\ a_{n - 1} \end{pmatrix} = \begin{pmatrix} b_0\\ b_1\\ \vdots\\ b_{n - 1} \end{pmatrix} \]

如果我们能够求出 \(\Omega\) 的逆,则 \(a = \Omega^{-1}b\)

\[M = \overline\Omega\cdot\Omega = \begin{pmatrix} (\omega_n^{-0})^0 & (\omega_n^{-0})^1 & \cdots & (\omega_n^{-0})^{n - 1}\\ (\omega_n^{-1})^0 & (\omega_n^{-1})^1 & \cdots & (\omega_n^{-1})^{n - 1}\\ \vdots & \vdots& \ddots & \vdots \\ (\omega_n^{-(n- 1)})^0 & (\omega_n^{-(n - 1)})^1 & \cdots & (\omega_n^{-(n- 1)})^{n - 1}\\ \end{pmatrix} \begin{pmatrix} (\omega_n^0)^0 & (\omega_n^0)^1 & \cdots & (\omega_n^0)^{n - 1}\\ (\omega_n^1)^0 & (\omega_n^1)^1 & \cdots & (\omega_n^1)^{n - 1}\\ \vdots & \vdots& \ddots & \vdots \\ (\omega_n^{n- 1})^0 & (\omega_n^{n - 1})^1 & \cdots & (\omega_n^{n - 1})^{n - 1}\\ \end{pmatrix} \]

其中

\[\begin{aligned} M_{i, j} &= (\omega_{n}^{-i})^{0}\cdot (\omega_{n}^{0})^{j} + (\omega_{n}^{-i})^{1}\cdot (\omega_{n}^{1})^{j} + \cdots(\omega_{n}^{-i})^{n - 1}\cdot (\omega_{n}^{n - 1})^{j}\\ \\ &= (\omega_{n}^{j-i})^{0} + (\omega_{n}^{j-i})^{1} + \cdots(\omega_{n}^{j-i})^{n - 1} \end{aligned} \]

相当于等比数列求和

\[M_{i, j} \begin{cases} \dfrac{1 - (w_n^{j - i})^n}{1 - w_n^{j - i}} = 0 \quad & w_n^{j - i} \neq 1\text{ 即 } i \neq j \\ \\ n \quad & i = j \end{cases} \]

\(\overline\Omega\) 满足 \(\overline\Omega_{i, j} = \omega^{-ij}\),有 \(\overline\Omega\cdot\Omega = nI\),因此

\[a = \dfrac{1}{n}\overline\Omega b \]

相当于给定 \(B(x) = b_0 + b_1x + \cdots + b_{n - 1}x^{n - 1}\),求点值 \(a_k = B(\omega_n^{-k}), \ (0 \le k < n)\)

例题

A * B Problem Plus

题意:给定 \(a, \ b\),求 \(a \times b\)\(a, \ b < 10^{50001}\)(范围可以更大)。

\(a\) 看作 \(a_0 + a_110^1 + a_210^2 + \cdots\),fft 后再处理进位。

submission

SP8372 TSUM

题意:给定长度为 \(N\) 的数列 \(s\),对于任意可能存在的 \(V\),求满足 \(s_i + s_j + s_k = V, \ \ i < j < k\) 的对数,\(|s_i| \le 20000, \ N \le 40000\)

构造多项式 \(A(x) = \sum x^{s_i}\)

那么 \(\sum\limits_{i}\sum\limits_{j}\sum\limits_{k}[s_i + s_j + s_k = V] = [x^V]A^3(x)\)

这样求得的数对不一定满足偏序关系,也不一定互不相同。

偏序关系很好处理,最后将答案除上 \(3!\) 即可。

现要除去存在位置相同的数对,考虑容斥。

性质 \(a_1: i = j\),性质 \(a_2: i = k\),性质 \(a_3:j = k\)

  1. 减去满足三个性质中一个的方案。

    钦定两个位置相等。

    \(B(x) = \sum x^{2s_i}\),产生的方案为 \([x^V](A(x)B(x))\)

  2. 加上满足三个性质中两个的方案。

    \(i = j = k\)

    \(C(x) = \sum x^{3s_i}\),这部分的方案为 \([x^V]C(x)\)

  3. 减去满足三个性质中三个的方案。

    与第二部分相同。

则最终答案 \(D(x) = A^3(x) - 3B(x) + 2C(x)\)

可以先对 \(A(x), \ B(x), \ C(x)\) 分别做 dft,计算出 \(D(x)\) 的点值,最后再对 \(D(x)\) 做 idft。

submission

FFT 在字符串匹配中的应用

普通的单模式串匹配

问题概述:给定模式串 \(a\)(长度为 \(m\))、文本串 \(b\)(长度为 \(n\)),求所有位置 \(x\),满足 \(B\) 串以 \(x\) 结尾的连续 \(m\) 个字符与 \(a\) 串完全相同。

定义匹配函数 \(C(x, y) = [a_x - b_y]^2\),当 \(C(x, y) = 0\) 时则称 \(a\) 的第 \(x\) 个字符与 \(B\) 的第 \(y\) 个字符匹配。

定义完全匹配函数 \(P(x) = \sum\limits_{i = 0}^{m - 1}[a_i - b_{(x -m + i + 1)}]^2\)

当且仅当 \(P(x) = 0\) 时以 \(x\) 结尾的连续 \(m\) 个字符与 $$ 匹a配。

\(s\) 串满足 \(s_i = a_{(m - i - 1)}\),即 \(a\) 串的翻转。

于是 \(P(x) = \sum\limits_{i = 0}^{m - 1}[s_{(m - i + 1)} - b_{(x -m + i + 1)}]^2\)

暴力展开:\(P(x) = \sum\limits_{i = 0}^{m - 1} s_{(m - i + 1)}^2 + \sum\limits_{i = 0}^{m - 1}b_{(x -m + i + 1)}^2 - \sum\limits_{i = 0}^{m - 1}2\cdot s_{(m - i + 1)}b_{(x - m + i + 1)}\)

第一项为常数。

第二项可以预处理 \(f(x) = \sum_{i = 0}^xb_i^2\),计算 \(f(x) - f(x - m)\)

第三项等效于求 \(g(x) = \sum\limits_{i + j = x}s_ib_j\)

\(P(x) = T + f(x) - f(x - m) - 2g(x)\)

把字符串当作多项式,即 \(B(x) = b_0 + b_1x + b_2x^2 + \cdots\)

\(g\)\(S\)\(B\) 的卷积。

最后检验多项式 \(P\) 有多少系数为 \(0\) 的项。

带通配符的单模式串匹配

问题概述:给定模式串 \(a\)(长度为 \(m\)),文本串 \(b\)(长度为 \(n\)),串的某些字符是 “通配符”(可以与任意字符匹配)。求所有位置 \(x\),满足 \(b\) 串以 \(x\) 结尾的连续 \(m\) 个字符与 \(a\) 串完全相同。

总结思路:

  1. 定义匹配函数。
  2. 定义完全匹配函数。
  3. 快速计算每一位的完全匹配函数(翻转模式串化为卷积)。

设通配符的数值为 \(0\)

定义匹配函数 \(C(x, y) = [a_x - b_y]^2a_xb_y\)

则完全匹配函数 \(P(x) = \sum\limits_{i = 0}^{m - 1}[a_i - b_{(x -m + i + 1)}]^2a_ib_{(x - m + i + 1)}\)

\(a\) 翻转,\(P(x) = \sum\limits_{i = 0}^{m - 1}[s_{(m - i + 1)} - b_{(x -m + i + 1)}]^2\cdot s_ib_{(x - m + i + 1)}\)

暴力展开:

\[\begin{aligned} P(x) &= \sum\limits_{i = 0}^{m - 1}[s_{(m - i + 1)} - b_{(x -m + i + 1)}]^2\cdot s_{(m - i + 1)}b_{(x -m + i + 1)}\\ \\ &= \sum\limits_{i = 0}^{m - 1} s_{(m - i + 1)}^3b_{(x - m + i + 1)} + \sum\limits_{i = 0}^{m - 1}s_{(m - i + 1)}b_{(x - m + i + 1)}^3 - \sum\limits_{i = 0}^{m - 1}2\cdot s_{(m - i + 1)}^2b_{(x - m + i + 1)}^2\\ \\ &= \sum_{i + j = x}s_i^3b_j + \sum_{i + j = x}s_ib_j^3 -2 \cdot \sum_{i + j = x}s_i^2b_j^2\\ \end{aligned} \]

把右边写成多项式乘积的形式,则

\[\begin{aligned} \\ P(x) = \sum s_i^3x^i \cdot \sum b_ix^i +\sum s_ix^i \cdot \sum b_i^3x^i -2\cdot \sum s_i^2x^i\cdot \sum b_i^2x^i\\ \\ \end{aligned} \]

例题

P4173 残缺的字符串

模板题。

#include<bits/stdc++.h>
using namespace std;
using namespace numbers;

using ll = long long;
constexpr int N = 6e5 + 5, tot = 1 << 19;

struct Complex {
	double x, y;
	Complex operator + (const Complex &o) const {
		return {x + o.x, y + o.y};
	}
	Complex operator - (const Complex &o) const {
		return {x - o.x, y - o.y};
	}
	Complex operator * (const Complex &o) const {
		return {x * o.x - y * o.y, x * o.y + y * o.x};
	}
} a[N], b[N], c[N];

int rev[N];

void fft(Complex a[], int Inv) {
	for(int i = 0; i < tot; ++ i) {
		if(i < rev[i]) {
			swap(a[i], a[rev[i]]);
		}
	}
	for(int mid = 1; mid < tot; mid <<= 1) {
		auto w1 = Complex({cos(pi / mid), Inv * sin(pi / mid)});
		for(int i = 0; i < tot; i += mid * 2) {
			auto wk = Complex({1, 0});
			for(int j = 0; j < mid; ++ j, wk = wk * w1) {
				auto x = a[i + j], y = a[i + j + mid];
				a[i + j] = x + wk * y;
				a[i + j + mid] = x - wk * y;
			}
		}
	}
	if(Inv == -1) {
		for(int i = 0; i < tot; ++ i) {
			a[i].x /= tot;
		}
	}
}

string s, t;
int m, n, A[N], B[N];

int main() {
	cin.tie(0)->sync_with_stdio(0);
	
	cin >> m >> n >> s >> t;
	reverse(s.begin(), s.end());
	for(int i = 0; i < m; ++ i) {
		A[i] = s[i] == '*' ? 0 : s[i] - 'a' + 1;
	}
	for(int i = 0; i < n; ++ i) {
		B[i] = t[i] == '*' ? 0 : t[i] - 'a' + 1;
	}
	
	for(int i = 0; i < tot; ++ i) {
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 18);
	}
	
	for(int i = 0; i < tot; ++ i) {
		a[i] = Complex({A[i] * A[i] * A[i], 0});
		b[i] = Complex({B[i], 0});
	}
	fft(a, 1), fft(b, 1);
	for(int i = 0; i < tot; ++ i) {
		c[i] = c[i] + a[i] * b[i];
	}
	
	for(int i = 0; i < tot; ++ i) {
		a[i] = Complex({A[i], 0});
		b[i] = Complex({B[i] * B[i] * B[i], 0});
	}
	fft(a, 1), fft(b, 1);
	for(int i = 0; i < tot; ++ i) {
		c[i] = c[i] + a[i] * b[i];
	}
	
	for(int i = 0; i < tot; ++ i) {
		a[i] = Complex({A[i] * A[i], 0});
		b[i] = Complex({B[i] * B[i], 0});
	}
	fft(a, 1), fft(b, 1);
	for(int i = 0; i < tot; ++ i) {
		c[i] = c[i] - Complex({2, 0}) * a[i] * b[i];
	}
	
	fft(c, -1);
	
	vector<int> ans;
	for(int i = m - 1; i < n; ++ i) {
		ll v = c[i].x + 0.5;
		if(v == 0) {
			ans.push_back(i - m + 2);
		}
	}
	
	cout << ans.size() << '\n';
	for(int x : ans) cout << x << ' ';
	return 0;
}
CF528D

题意:给定只含 ATGC 的两个字符串 \(s, \ t\) 和一个非负整数 \(k\),求有多少 \(i\) 满足任意 \(j \in [0, |t|)\),都存在 \(p \in [0, |s|)\) 使得 \(|i + j - p|\le k\)\(s_p = t_j\)

\(s\) 的长度为 \(n\)\(t\) 的长度为 \(m\)

预处理第 \(i\) 个位置能否与字符 \(c\) 匹配,记做 \(b_{i, c}\)

定义完全匹配函数 \(P(x)\),表示以 \(x\) 结尾的字符串与 \(t\) 匹配的个数,匹配成功当且仅当 \(P(x) = m\)

\(P(x) = \sum\limits_{c\in t}\sum\limits_{t_i = c}b_{(x - m + i + 1, c)}\)

单独考虑每个字符,记 \(f(x, A) = \sum_{i = 0}^{m - 1}[t_i = A][b_{x - m + i + 1, A}]\)

按照套路将 \(t\) 翻转。

\(f(x, A) = \sum_{i = 0}^{m - 1}[t'_{m -i - 1} = A][b_{x - m + i + 1, A}]\)

\(T(x) = \sum_{i \ge 0} [t'_i = A]x^i, \ B(x) = \sum_{i \ge 0}[b_{i, A}]x^i\),则 \(f(i, A) = [x^i]T(x)B(x)\)

submission

拉格朗日插值

拉格朗日插值定理

\(n\) 个点值 \((x_i, y_i), \ (1\le i \le n)\),满足 \(x_i \neq x_j, \ (i\neq j)\),它们 唯一 确定一个 \(n - 1\) 次多项式 \(f(x)\) 满足

\[f(x) = \sum_{i = 1}^ny_i\prod_{j \neq i}\dfrac{x - x_j}{x_i - x_j} \]

构造一个多项式 \(f(x) = f_1(x) + f_2(x) + \cdots + f_n(x)\)

满足 \(f_i(x_j) = \begin{cases}y_j & i = j\\0 & i \neq j\end{cases}\)

待定系数,\(f_1(x) = A(x - x_2)(x - x_3)\cdots(x - x_n)\)

带入 \(x_1\),解出 \(A = \dfrac{y_1}{(x_1 - x_2)(x_1 - x_3)\cdots(x_1 - x_n)}\),其余 \(f_i\) 同理。

  • \(\text{CRT}\) 的关系?

    多项式模多项式:如果 \(f(x) = q(x)g(x) + r(x)\),其中 \(r(x)\) 的次数小于 \(g(x)\),则记做 \(f(x)\equiv r(x)\pmod {g(x)}\)

    多项式互质:两个多项式的公因式只有常数,则称这两个多项式互质。

    对于任意 \(i \in [1, n]\)

    \[f(x) - f(x_i) =a_1(x - x_i) + a_2(x - x_i^2) + \cdots a_{n - 1}(x^{n - 1} - x_i^{n - 1}) \equiv 0 \pmod{x - x_i} \]

    有同余方程组

    \[\begin{cases} f(x) \equiv f(x_1) \pmod {x - x_1}\\ \\ f(x) \equiv f(x_2) \pmod {x - x_2}\\ \\ \vdots\\ \\ f(x) \equiv f(x_{n - 1}) \pmod {x - x_{n - 1}}\\ \end{cases} \]

    显然有模数两两互质,满足中国剩余定理的使用条件。

  • 暴力实现:先算 \(g(x) = \prod(x - x_i)\),再求 \(n\)\(g(x) / (x - x_i)\),复杂度 \(O(n^2)\)

  • 特殊情况1:只要求一个 \(f(x_0)\),复杂度 \(O(n^2)\)

  • 特殊情况2:只要求一个 \(f(x_0)\),满足 \(x_i = i\),复杂度 \(O(n)\)(可以预处理)。

例题

CF622F

题意:求 \(\sum_{i = 1}^ni^k\pmod {10^9 + 7}, \ n \le 10^9, \ k \le 10^6\)

\(f(n) = \sum_{i = 1}^ni^k\) 是关于 \(n\)\(k + 1\) 次多项式。

证明:

对于第二类斯特林数,满足公式

\[n^m = \sum\limits_{i = 0}^m\begin{Bmatrix}m\\i\end{Bmatrix}n^{\underline{i}} \]

那么

\[f(n) = \sum\limits_{i = 1}^n \sum\limits_{j = 0}^k\begin{Bmatrix}k\\j\end{Bmatrix}i^{\underline{j}} = \sum\limits_{j = 0}^k\begin{Bmatrix}k\\ j\end{Bmatrix}j!\cdot \sum\limits_{i = 1}^n\begin{pmatrix}i\\ j\end{pmatrix} \]

有组合恒等式

\[\sum\limits_{l = 0}^n\begin{pmatrix}l\\ k\end{pmatrix} =\begin{pmatrix}n + 1\\ k + 1\end{pmatrix} \]

\[f(n)= \sum\limits_{i = 0}^k\begin{Bmatrix}k\\ i\end{Bmatrix}i!\begin{pmatrix}n + 1\\ i + 1\end{pmatrix}= \sum\limits_{i = 0}^k\begin{Bmatrix}k\\ i\end{Bmatrix}\dfrac{(n + 1)^{\underline{i + 1}}}{i + 1} \]

所以求出 \([0, k + 1]\) 的函数值,直接拉插即可。

submission

Polynomia

题意:\(f(n)\)\(n\) 次多项式,给定 \(f(i), \ i \in[0, n]\),询问 \(s(R) - s(L - 1)\)

\(f(n)\)\(n\) 次多项式,则其前缀和为 \(n + 1\) 次多项式。

先对 \(f(n)\) 做一遍拉插求出 \(f(n + 1)\),因而得到 \(s(n + 1)\),再对 \(s\) 做拉插。

submission

reference

Ebola:浅谈FFT在字符串匹配中的应用

阶与原根

若正整数 \(m, \ a\),满足 \((a, m) = 1\),则使 \(a^n\equiv 1 \pmod m\) 的最小正整数 \(n\) 称为 \(a\)\(m\) 的阶,记作 \(\delta_m(a)\)

\(\delta_7(1) = 1, \ \delta_7(2) = 3, \ \delta_7(3) = 6\)

原根

\(\delta_m(a) = \varphi(m)\),则称 \(a\)\(m\) 的一个原根。

欧拉定理:若 \((a, m) = 1\),则 \(a^{\varphi(m)}\equiv 1\pmod m\)

阶的性质

假设 \((a, m) = 1, \ \delta = \delta_m(a)\),则

  1. \(a^0, a^1, \dots, a^{\delta - 1}\) 在模 \(m\) 意义下两两不同。

    证明:

    如果存在 \(a^x \equiv a^y \pmod m, \ x < y \le \delta - 1\)

    \(a^{y - x} \equiv 1\),且 \(y - x < \delta\),与阶的最小性矛盾。

  2. \(a^{\gamma}\equiv a^{\gamma'} \pmod m \iff \gamma \equiv \gamma'\pmod \delta\)

  3. \(\delta \mid \varphi(m)\)

    证明:

    \(\varphi(m) = q\delta + r, \ (0 \le r < \delta)\)

    如果 \(r > 0\),则 \(a^{q\delta + r} \equiv a^{r} \equiv a^{\varphi(m)}\equiv 1 \pmod m\),则有 \(r < \delta\),与 \(\delta_m(a) = \delta\) 矛盾。

    所以 \(r = 0\)

  4. \(m \in\mathbb{N^*}, \ a, b\in \mathbb{Z}, \ (a, m) = (b, m) = 1\),则

    \[\delta_m(ab) = \delta_m(a)\delta_m(b) \]

    的充要条件为 \((\delta_m(a), \delta_m(b)) = 1\)

  5. \(k\in \mathbb{N}, \ m \in \mathbb{N^*}, \ a\in \mathbb{Z}, \ (a, m) = 1\),则

    \[\delta_m(a^k) = \dfrac{\delta_m(a)}{(\delta_m(a), k)} \]

    证明:

    注意到:

    \[\begin{aligned} & a^{k\delta_m(a^k)}=(a^k)^{\delta_m(a^k)}\equiv 1 \pmod m \\ \implies & \delta_m(a)\mid k\delta_m(a^k) \\ \implies & \dfrac{\delta_m(a)}{\left(\delta_m(a),k\right)}\mid\delta_m(a^k) \end{aligned} \]

    另一方面,由 \(a^{\delta_m(a)}\equiv 1 \pmod m\),可知:

    \[(a^k)^{\frac{\delta_m(a)}{(\delta_m(a),k)}}=(a^{\delta_m(a)})^{\frac{k}{(\delta_m(a),k)}}\equiv 1 \pmod m \]

    故:

    \[\delta_m(a^k)\mid\dfrac{\delta_m(a)}{(\delta_m(a),k)} \]

    综合以上两点,得:

    \[\delta_m(a^k)=\dfrac{\delta_m(a)}{(\delta_m(a),k)} \]

原根的存在与判定

原根的存在定理

只有模 \(2,\ 4,\ p^a,\ 2p^a\)\(p\) 是奇质数)存在原根。

原根的判定定理

\(m > 1\)\(g\) 为正整数且 \((g, m) = 1\)。则 \(g\)\(m\) 的原根当且仅当对于任意 \(\varphi(m)\) 的质因子 \(q_i\)\(g^{\varphi(m)/q_i} \not\equiv 1 \pmod m\)

证明:如果 \(\delta < \varphi(m)\)\(\delta \mid \varphi(m)\),则一定存在一个 \(q_i\) 使得 \(\delta \mid\varphi(m) / q_i\)

原根个数

\(m\) 有原根,则它原根的个数为 \(\varphi(\varphi(m))\)

证明:

\(m\) 有原根 \(g\),则:

\[\delta_m(g^k)=\dfrac{\delta_m(g)}{\left(\delta_m(g),k\right)}=\dfrac{\varphi(m)}{\left(\varphi(m),k\right)} \]

所以若 \(\left(k,\varphi(m)\right)=1\),则有:\(\delta_m(g^k)=\varphi(m)\),即 \(g^k\) 也是模 \(m\) 的原根。

而满足 \(\left(\varphi(m),k\right)=1\)\(1\leq k \leq \varphi(m)\)\(k\)\(\varphi(\varphi(m))\) 个。所以原根就有 \(\varphi(\varphi(m))\) 个。

P6091 【模板】原根submission

指标(离散对数)

定义

对于质数 \(p\),假设 \(g\)\(p\) 的一个原根,则 \(g^0, \ g^1, \dots, g^{p - 2}\) 在模 \(p\) 意义下是 \(1, 2, \dots, p - 1\) 的一个排列。

假设对于 \(x \in [1, p)\)\(g^c\equiv x \pmod p\),则称 \(x\) 的指标为 \(c\),记作 \(\operatorname{ind}(x) = c\)(或 \(\operatorname{ind}_g(x) = c\))。

性质

对于任意 \(x, y \in [1, p)\),存在

\[\begin{aligned} \operatorname{ind}(xy) &= \operatorname{ind}(x) + \operatorname{ind}(y)\pmod {\varphi(p)}\\ \\ \operatorname{ind}(x^c) &= c\operatorname{ind}(x)\pmod {\varphi(p)}\\ \end{aligned} \]

类似于实数运算中的对数,因此指标亦称离散对数。

BSGS (baby step giant step)

给定质数 \(p\),求最小满足 \(g^c \equiv x \pmod {p}\) 的非负整数 \(c\) 的值。

\(c = aB + b\),其中 \(B = \lceil\sqrt{p}\rceil\)

因为 \(c < \varphi(p) = p - 1\),所以 \(a, \ b < B\)

  1. BS:枚举 \(b = 0, \ 1, \ \dots, B - 1\),将 \(xg^{b}\) 计入哈希表。

  2. GS:枚举 \(a = 1, \ 2, \ \dots, B\),若存在 \(g^{aB} = xg^b\),则最小满足条件的 \(c = aB - b\)

这样枚举会漏掉 \(c = 0\) 的解,单独特判即可。

最小性证明:

对于 \(xg^b \bmod p\) 相同的 \(b\),大的会在哈希表中覆盖小的,从而使 \(aB - b\) 最小。

\(B > b\),所以 \(a\) 对答案的贡献大于 \(b\),从小到大枚举 \(a\) 使答案最小。

【模板】BSGS

例题

Discrete Roots

题意:给出两个质数 \(p, k\) 和一个整数 \(a\),求 \(x^k = a \pmod p\) 的所有解。

\[\begin{aligned} &\operatorname{ind}(x^k) = k\operatorname{ind}(x) = \operatorname{ind}(a) \pmod{\varphi(p)}\\ \\ &k\operatorname{ind}(x) \equiv\operatorname{ind}(a)\pmod{\varphi(p)}\\ \\ &x \equiv g^{\operatorname{ind}(x)} \pmod p \end{aligned} \]

所以只需处理 \(p\) 的原根以及 \(a\) 的指标,中间的同余方程可用 exgcd 求解。

特判 \(a = 0\) 的情况。

submission

快速数论数论变换(NTT)

即把 FFT 中 \(\mathbb{C}\) 上的运算变成 \(\mathbb{Z}_p\) 上的运算。

  • 假设素数 \(p\) 满足 \(p = r2^l + 1\)\(g\)\(p\) 的原根。

  • \(g_n = g^{\frac{p - 1}{n}}\) 替代 \(\omega_n\)

  • \(g_{2n}^{2k} \equiv g_n^k \pmod p, \ (2n < 2^l)\)

  • \(g_{2n}^{n} \equiv -1 \pmod p, \ (2n < 2^l)\)

    \(g_{2n}^n = g^{\frac{p - 1}{2}}\)

    由于 \((g^{\frac{p - 1}{2}})^2 \equiv g^{p - 1} \equiv 1\pmod p\),所以 \(g_{2n}^n\) 只可能同余 \(1\)\(-1\)

    又因为 \(g\) 为原根,\(\delta_{p}(g) = p - 1\)

    \(g^{\frac{p - 1}{2}} \equiv 1\) 则与阶的最小性矛盾,所以 \(g^{\frac{p - 1}{2}}\equiv-1\pmod p\)

  • \(\sum_{k = 0}^{n - 1}g_{n}^{ik}g_{n}^{-kj} \equiv \begin{cases} n & i = j\\ 0 & i \neq j \end{cases}\pmod p\),其中 \(i, j \in [0, n)\)

优点:快,精确。

限制:模数要满足 \(p = 2^l + 1\)

常见模数:

  • \(65537 = 2^{16} + 1, \ g = 3\)

  • \(998244353 = 119 \cdot 2^{23} + 1, \ g = 3\)

  • \(1004535809 = 479 \cdot 2^{21} + 1, \ g = 3 \quad > 10^{9}\)

  • \(4179340454199820289 = 29 \cdot 2^{57} + 1, \ g = 3 \quad> 4\cdot 10^{18}\)

A * B Problem Plussubmission

分治 FFT(NTT)

  1. 在模 \(998244353\) 意义下,计算 \(f(x) = \prod (x - a_i)\) 的各项系数。

    • 计算 \([l, mid]\) 之积。

    • 计算 \([mid + 1, r]\) 之积

    • \([l, mid]\)\([mid + 1, r]\) 相乘。

    时间复杂度 \(O(n\log^2n)\)

  2. 在模 \(998244353\) 意义下,计算 \(f(x) = \prod f_i(x)\) 的各项系数,其中 \(\sum\deg(f_i(x)) \le 10^5\)

    可以和上题一样分治。

    也可以按照次数维护一个优先队列,每次相乘当前最小的两个,即一棵哈夫曼树。

例题

P4721 【模板】分治 FFT

题意:给定 \(g_1 \dots g_{n - 1}\),求 \(f_0\dots f_{n - 1}\),满足 \(f_0 = 1\)\(f_i = \sum_{j = 1}^ig_jf_{i - j}\)

后式是一个卷积的形式,考虑分治。

假设当前正在处理区间 \([l, r]\)

  • 递归 \([l, mid]\),求出 \(f_l\dots f_{mid}\)
  • 计算 \(f_l\dots f_{mid}\)\(f_{mid + 1}\dots f_r\) 的贡献。
  • 递归 \([mid + 1, r]\)

具体怎么求贡献?

\(\forall i \in [l, mid], \ a_{i - l} = f_l\)

\(\forall i \in [1, r - l], \ b_{i - 1} = g_i\)

对于 \(\forall i \in [mid + 1, r]\),加上 \([x^{i - l - 1}]A*B\) 的贡献。

void solve(int l, int r) {
	if(l == r) {
		return;
	}
	int mid = l + r >> 1;
	solve(l, mid);
	
	bit = 0;
	while((1 << bit) < (r - l)) ++ bit;
	tot = 1 << bit;
	for(int i = 0; i < tot; ++ i) {
		rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
	}
	
	memset(a, 0, tot * 8);
	memset(b, 0, tot * 8);
	
	for(int i = l; i <= mid; ++ i) a[i - l] = f[i];
	for(int i = 1; i <= r - l; ++ i) b[i - 1] = g[i];
	
	ntt(a, 1), ntt(b, 1);
	for(int i = 0; i < tot; ++ i) a[i] = (ll)a[i] * b[i] % P;
	ntt(a, -1);
	
	for(int i = mid + 1; i <= r; ++ i) {
		f[i] = (f[i] + a[i - l - 1]) % P;
	}
	solve(mid + 1, r);
}
C-挑选队友

题意:\(m\) 个群,\(n\) 位选手,选其中的k名,每个群中都应有至少一名,求方案数。

考虑生成函数 \(F_i(x) = \sum_{j = 1}^{s_i}\begin{pmatrix}s_i\\j\end{pmatrix}x^j\)

则答案即 \([x^k]\prod F_i(x)\)

实测分治时传 vector 的效率也不差。

submission

D-tokitsukaze and Another Protoss and Zerg

和上题基本一致,生成函数略有不同。

如果星族选 \(0\) 个,则虫族可选任意一个非空子集。

所以 \(F_i(x) =(2^{b_i} - 1) + \sum_{j = 1}^{a_i}\begin{pmatrix}a_i\\j\end{pmatrix}x^j\)

submission

牛顿迭代

推导

给定多项式 \(g(x)\),求满足 \(g(f(x)) = 0\) 的形式幂级数 \(f(x)\)

\(g(x) = b_0 + b_1x + \cdots b_kx^{k}, \ f(x) = a_0 + a_1x + \cdots\)

设当前求出 \(f\) 的前 \(n\) 项。

  • \(n = 1\) 时,解 \(g(a_0) = 0\)

  • 假设已经求出前 \(n\)\(f(x) \equiv a_0 + a_1x + \cdots a_{n - 1}x^{n - 1}\pmod {x^n}\)

    \(f(x) \equiv f_0(x) - \dfrac{g(f_0(x))}{g'(f_0(x))}\pmod{x^{2n}}\)

证明:

对于 \(g(f(x))\),有泰勒展开

\[\begin{aligned} g(f(x)) = g(f_0(x)) + g'(f_0(x))\cdot[f(x) - f_0(x)] + \dfrac{g''(f_0(x))}{2!}\cdot [f(x) - f_0(x)]^2 + \cdots \dfrac{g^{(n)}(f_0(x))}{n!}\cdot [f(x) - f_0(x)]^n + \cdots \end{aligned} \]

观察到 \(f(x) - f_0(x)\) 次数最小也有 \(x^n\)$。

所以在模 \(x^{2n}\) 意义下,从第三项开始都为 \(0\)

根据定义 \(g(f(x)) = 0\)

\(f(x) \equiv f_0(x) - \dfrac{g(f_0(x))}{g'(f_0(x))}\pmod{x^{2n}}\)

多项式求逆

\(h(x)\) 是给定的形式幂级数,求它的逆 \(f(x)\),则 \(g(f(x)) = \dfrac{1}{f(x)} - h(x)\)

得到的迭代式为(求导时 \(h(x)\) 可当做常数,\(f(x)\) 看成自变量

\[\begin{aligned} f(x) &\equiv f_0(x) - \dfrac{g(f_0(x))}{g'(f_0(x))}\\ \\ &\equiv f_0(x) - \dfrac{\dfrac{1}{f_0(x)} - h(x)}{-\dfrac{1}{f_0^2(x)}}\\ \\ &\equiv 2f_0(x) - f_0^2(x)\cdot h(x) \pmod {x^{2n}} \end{aligned} \]

边界 \([x^0]f(x) = [x^0]h^{-1}(x)\)

时间复杂度 \(O(\sum\limits_{i = 1}^{\log N} i \cdot 2^i) = O(N\log N)\)

介于本人不会求导,给出另一种推导方式。

已知 \(f_0(x) = f(x) \bmod {x^n}\)

\(f_1(x) = f(x) \bmod x^{2n}\)

\([f_1(x) - f_0(x)]^2 \equiv \pmod {x^{2n}}\)

\[f_1^2(x) - 2f_1(x)f_0(x) + f_0^2(x) \equiv 0 \pmod{x^{2n}} \]

在模 \(x^{2n}\) 意义下,\(f_1(x) * h(x) = 1\)

两边同乘 \(h(x)\)

\[f_1(x) - 2f_0(x) + f_0^2(x)h(x) \equiv 0 \pmod{x^{2n}} \]

P4238 【模板】多项式乘法逆

void polyinv(ll *f, const ll *h, int n){
	static ll d[N], g[N];
	int V = 1; while(V < n + n - 1) V <<= 1;
	memcpy(d, h, n * 8), memset(d + n, 0, (V - n) * 8);
	memset(f, 0, V * 8), memset(g, 0, V * 8);
	f[0] = qpow(h[0], P - 2);
	for(int w = 2; w / 2 < n; w <<= 1){
		memcpy(g, d, w * 8);
		for(int i = 0; i < w * 2; ++i) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? w : 0);
		ntt(f, w << 1, 1), ntt(g, w << 1, 1);
		for(int i = 0; i < w * 2; ++i) f[i] = (2 - f[i] * g[i]) % P * f[i] % P;
		ntt(f, w << 1, -1);
		memset(f + w, 0, w * 8);
	}
	memset(f + n, 0, (V - n) * 8);
}
  • \(n\) 为项数而不是次数。

  • \(w\)\(f_1(x)\) 的长度,当前已知长度为 \(w / 2\)\(f_0(x)\)

  • 由于要算 \(f_0^2(x) * h(x)\),所以 ntt 要开到 \(4\)\(w / 2\)

  • 做完 idft 后只需保留前 \(w\) 项,否则后续有影响。

多项式开方

\(h(x)\) 是给定的形式幂级数,求它的开方 \(f(x)\),则 \(g(f(x)) = f(x)^2 - h(x)\)

得到的迭代式为:

\[\begin{aligned} f(x) &= f_0(x) - \dfrac{f_0^2(x) - h(x)}{2f_0(x)} \pmod{x^{2n}}\\ \\ &= (f_0(x) + \dfrac{h(x)}{f_0(x)}) \cdot 2^{-1} \end{aligned} \]

P5205 【模板】多项式开根

void polysqrt(ll *f, const ll *h, int n){
	static ll d[N], g[N], f_inv[N];
	int V = 1; while(V < n + n - 1) V <<= 1;
	memcpy(d, h, n * 8), memset(d + n, 0, (V - n) * 8);
	memset(f, 0, V * 8), memset(g, 0, V * 8), memset(f_inv, 0, V * 8);
	f[0] = 1;
	constexpr int i2 = 499122177;
	for(int w = 2; w / 2 < n; w <<= 1){
		memcpy(g, d, w * 8);
		for(int i = 0; i < w * 2; ++i) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? w : 0);
		polyinv(f_inv, f, w);
		ntt(f, w << 1, 1), ntt(g, w << 1, 1), ntt(f_inv, w << 1, 1);
		for(int i = 0; i < w * 2; ++i) f[i] = (f[i] + f_inv[i] * g[i]) % P * i2 % P;
		ntt(f, w << 1, -1);
		memset(f + w, 0, w * 8);
	}
	memset(f + n, 0, (V - n) * 8);
}

例题

CF438E The Child and Binary Tree

题意:给定集合 \(\{c_1, c_2, \dots, c_n\}\quad(c_i \ge 1)\),有根二叉树的点权都属于该集合,左右儿子区分,问满足点权和 \(s = 1, 1, \dots,m\) 有多少不同二叉树。

\(f_n\) 表示点权和为 \(n\) 时的方案数。

\(v_i\) 表示 \(i\) 这个点权是否在集合中出现。

枚举左右子树的权值

\[f_n = \begin{cases} 1 & n = 0\\ \\ \sum\limits_{i = 1}^{n}v_i\sum\limits_{j = 0}^{v_i}f_{j}\cdot f_{v_i - j} &n > 0 \end{cases} \]

下式可写成卷积的形式:

\[f_n = \sum_{i + j + k = n}[v_i]\cdot f_j \cdot f_k \]

\(F(x) = \sum_{i \ge 1} f_0x^{i}\)

\(G(x) = \sum_{i \ge 1}[v_i]x^{i}\)

那么

\[F(x) = \sum[i > 0]\cdot [x^i][F^2(x)G(x)] + f_0 \]

由于题目保证了 \(c_i > 0\),所以 \([x^0]G(x) = 0\)

\(F = F^2G + 1\)

解方程:

\[F = \dfrac{1\pm \sqrt{1 - 4G}}{2G} \]

  • \(\lim\limits_{x\rightarrow 0}F(x) = f_0 = 1\)

  • \(\lim\limits_{x\rightarrow 0}G(x) = 0\)

取正号时,有 \(\lim\limits_{x\rightarrow 0}F(x) = +\infty\),舍去。

取负号时,有 \(\lim\limits_{x\rightarrow 0}F(x) = 1\),成立。

所以

\[F = \dfrac{1- \sqrt{1 - 4G}}{2G} \]

\([x^0]G(x) = 0\),无法求逆,考虑上下同乘 \(1 + \sqrt{1 - 4G}\)

\[F = \dfrac{2}{1 + \sqrt{1 - 4G}} \]

法2:牛顿迭代。

\(g(F(x)) = G(x)F^2(x) - F(x) + 1 = 0\)

  • \(F(x) \equiv 1 \pmod {x}\)

  • \(F(x) \equiv F_0(x)- \dfrac{G(x)F_0^2(x) + 1}{2G(x)F_0(x) - 1} \pmod {x^{2n}}\)

submission

F-卷积

题意:定义 \(F(x)=\sum_{i=1} f_ix^i\) ,其中 \(f_i=af_{i-1}+bf_{i-2}|(i>=2),f_0=0,f_1=1\)

给定 \(n, a, b\),求 \([x^{n}]\sum_{i\ge 1}F^i(x)\),(\(n \le 2\times 10^6\))。

\[\begin{aligned} F(x) &= f_1 + \sum_{i\ge2}(af_i - 1 + bf_{i - 2})x^i\\ \\ &= f_1 + axF(x) + bx^2(F(x) + f_0)\\ \\ &= 1 + axF(x) + bx^2F(x) \end{aligned} \]

\(F(x) = \dfrac{1}{1 - ax - bx^2}\)

\(\sum_{i\ge1}F^i(x) = \dfrac{F(x)}{1 - F(x)} = \dfrac{x}{1 -(a + 1)x - bx^2}\)

\(G(x) = \dfrac{1}{1 -(a + 1)x - bx^2}\),则答案转化为求 \([x^{n -1}]G(x)\)

到此步为止,已经可以 \(O(n\log n)\) 多项式求逆了。

复杂度依旧吃紧。

继续观察。

\(G(x)\)\(F(x)\) 比对,形式出奇一致。

得到 \(g_i = (a + 1)g_{i - 1} + bg_{i - 2}\),求 \(g_{n - 1}\)

可以 \(O(n)\) 计算,也可以 \(O(4\log N)\) 矩阵快速幂。

submission


形式幂级数的更多运算

形式幂级数与幂级数的比较

  • 形式幂级数本质是序列(\(x^i\) 无意义),幂级数本质是极限。
  • 形式幂级数通过带入 \(x\) 还原成幂级数。
  • 假设系数在 \(\mathbb{C}\) 上,可以证明形式幂级数与具有正收敛半径的幂级数在 '通常' 的所有运算上服从同样规律(加减乘除求导积分……)。

形式幂级数的更多运算

假设 \(f(x) = a_0 + a_1x + a_2x^2 + \cdots + a_nx^{n} + \cdots\)

求导

定义 \(f(x)\) 的导数为 \(a_1 + 2a_2x + \cdots + (n + 1)a_{n + 1}x^{n} + \cdots\),记做 \(f'(x)\)\(\dfrac{df(x)}{d(x)}\)

对于形式幂级数而言,

求导是序列上的一个变换,即 \(\{a_0, a_1, \cdots, a_n,\cdots\} \Rightarrow \{a_1, 2a_2, \cdots, (n + 1)a_{n + 1},\cdots\}\)

积分

定义 \(f(x)\) 的积分为 \(a_0x + \dfrac{a_1}{2}x^2 + \cdots + \dfrac{a_{n - 1}}{n}x^{n} + \cdots\),记做 \(\int f(x)dx\)\(\int_{0}^{x} f(y)dy\)

\(\{a_0, a_1, \cdots, a_n,\cdots\} \Rightarrow \{0, a_0, \dfrac{a_1}{2}, \cdots, \dfrac{a_{n - 1}}{n},\cdots\}\)

推论:如果 \([x^0]f(x) = 0\),令 \(g(x) = f'(x)\),则 \(\int g(x)dx = f(x)\)

复合

假设 \(f(x) = a_1x + a_2x^2 + \cdots + a_nx^{n} + \cdots, \ g(x) = b_0 + b_1x + b_2x^2 + \cdots + b_nx^{n} + \cdots\)

\(g\) 复合 \(f\) 定义为 \(c_0 + c_1x + \cdots c_nx^n + \cdots\),满足 \(c_0 = b_0, \ c_n = \sum\limits_{k = 1}^{n}b_k\sum\limits_{i_1 + i_2 + \cdots+ i_k = n}\prod a_{i_j}\)

记做 \(g \circ f\)\(g(f(x))\)

如果 \(f\) 的常数项不为 \(0\)

那么 \(c_0 = b_0 + b_0a_0 + b_0a_0^2 + \cdots + b_na_0^n + \cdots\)

\(c_0\) 本身就是一个极限的形式,涉及到收不收敛的问题,这是在形式幂级数中不愿看到的。

因此在定义复合时,一般令 \([x^0]f(x) = 0\)

再考虑 \(c_n = \sum\limits_{k = 1}^{n}b_k\sum\limits_{i_1 + i_2 + \cdots+ i_k = n}\prod a_{i_j}\)

如果 \(i_j > n\),那么 \(\sum{i_j} > n\),所以 \(c_n\) 的定义不需要考虑收敛。

  • \(\exp(x) = \sum_{n \ge0} \dfrac{1}{n!}x^n\)
  • \(\ln (1 + x) = \sum_{n \ge 1}(-1)^{n + 1}\dfrac{x^n}{n}\)
  • \(\ln (1 - x) = -\sum_{n \ge 1}\dfrac{x^n}{n}\)
  • 设形式幂级数 \(f(x)\) 满足 \([x^0]f(x) = 0\),则可定义 \(\exp(f(x))\)\(\ln(1 + (f(x))\)。(或 \([x^0] = 1\) 可定义 \(\ln(f(x))\))。
  • \(g(x) = \exp(f(x)) \iff f(x) = \ln(g(x))\)

推论:\((g \circ f)' = (g' \circ f) \cdot f'\)

假设 \(f(x) = \sum_{i \ge 1} a_ix^i, \ g(x) = \sum_{i \ge0}b_i, \ g(f(x)) = \sum_{i \ge0}c_ix^i\)

满足

\[\begin{cases} f'(x) = \sum_{n \ge 0} (n + 1)a_{n + 1}x^{n} & a_0 = 0\\ \\ g'(x) = \sum_{n \ge 0} (n + 1)b_{n + 1}x^{n}\\ \\ g(f(x))' = \sum_{n \ge 0} (n + 1)c_{n + 1}x^{n} & c_0 = b_0, \ c_n = \sum\limits_{k = 1}^{n}b_k\sum\limits_{i_1 + i_2 + \cdots+ i_k = n}\prod a_{i_j}\\ \\ g'(f(x)) = \sum_{n \ge 0} d_{n}x^{n} & d_n = \sum\limits_{k = 0}^{n}(k + 1) \cdot b_{k + 1}\sum\limits_{i_1 + i_2 + \cdots+ i_k = n}\prod a_{i_j}\\ \end{cases} \]

即证 \((n + 1)c_{n + 1} = \sum\limits_{i = 0}^{n}(i + 1)a_{i + 1}{}d_{n - i}\)

左边:

\[\begin{aligned} \sum\limits_{i = 0}^{n}(i + 1)a_{i + 1}{}d_{n - i} &= \sum\limits_{i = 0}^{n}(i + 1)a_{i + 1}{}\sum\limits_{k = 0}^{n - i}(k + 1) \cdot b_{k + 1}\sum\limits_{i_1 + i_2 + \cdots+ i_k = n - i}\prod a_{i_j}\\ \\ &= \sum\limits_{k = 0}^{n}(k + 1) \cdot b_{k + 1}\sum\limits_{i = 0}^{n}(i + 1)a_{i + 1}{}\sum\limits_{i_1 + i_2 + \cdots+ i_k = n - i}\prod a_{i_j}\\ \\ &= \sum\limits_{k = 1}^{n + 1}k \cdot b_{k}\sum\limits_{i = 1}^{n + 1}i\cdot a_{i}{}\sum\limits_{i_1 + i_2 + \cdots+ i_{k - 1} + i = n + 1}\prod_{j = 1}^{k - 1} a_{i_j}\\ \\ &= \sum\limits_{k = 1}^{n + 1}k \cdot b_{k}\sum\limits_{i_1 + i_2 + \cdots+ i_{k - 1} + i = n + 1}a_{i_1}a_{i_2}\cdots a_{i_{k - 1}}\cdot a_i\cdot i \\ \\ &= \sum\limits_{k = 1}^{n + 1}b_{k}[\sum\limits_{i_1 + i_2 + \cdots+ i_{k - 1} + i_k = n + 1}a_{i_1}\cdots a_{i_k}\cdot i_1 + \sum\limits_{i_1 + i_2 + \cdots+ i_{k - 1} + i_k = n + 1}a_{i_1}\cdots a_{i_k}\cdot i_2 + \sum\cdots ] &\text{把 k 项拆开,每次选出一个特殊的 } i_j\\ \\ &= \sum\limits_{k = 1}^{n + 1}b_{k}\sum\limits_{i_1 + i_2 + \cdots+ i_{k - 1} + i_k = n + 1}(i_1 + i_2 +_ \cdots i_k)\prod_{j = 1}^ka_{i_j}\\ \\ &= \sum\limits_{k = 1}^{n + 1} b_{k}\sum\limits_{i_1 + i_2 + \cdots+ i_{k - 1} + i_k = n + 1}(n + 1)\prod_{j = 1}^ka_{i_j}\\ \end{aligned} \]

右边:

\[\begin{aligned} (n + 1)c_{n + 1} &= (n + 1)\sum\limits_{k =1}^{n + 1}b_k\sum\limits_{i_1 + i_2 + \cdots+ i_k = n + 1}\prod_{i = 1}^ka_{i_j}\\ \end{aligned} \]

左边等于右边。

计算 \(\ln(f(x))\)

(满足 \([x^0]f(x) = 1\))重要观察:

\[\ln(f(x))' = \dfrac{1}{f(x)}f'(x) \]

\(O(n)\) 求导,\(O(n\log n)\) 求逆,\(O(n)\) 积分。

P4725 【模板】多项式对数函数(多项式 ln)

计算 \(\exp(f(x))\)

(满足 \([x^0]f(x) = 1\))如果 \(g(x) = \exp(f(x))\),那么 \(\ln(g(x)) =f(x)\)

构造牛顿迭代 \(h(g(x)) = \ln(g(x)) - f(x)\)

有递推式

\[g(x) = g_0(x) \cdot[1 - \ln(g_0(x)) + f(x)] \pmod{x^{2n}} \]

P4726 【模板】多项式指数函数(多项式 exp)

例题

三轮

题意:\(n\) 种商品,每种商品体积为 \(v_i\),都有 \(10^5\) 件,输出凑成 \(1\)\(m\) 的体积的总方案数。

对质数 \(19260817\) 取模 。(\(n, m, v_i \le 5\times 10^4\)

\(v_i\) 至少为 \(1\),可认为每种商品都有无穷件。

考虑其生成函数 \(F_i(x) = 1 + x^{v_i} + x^{2v_i} + \cdots = \dfrac{1}{1 - x^{v_i}}\)

所以 \(G(x) = \prod\limits_{i = 1}^{k} \dfrac{1}{1 - x^{v_i}}\)

由于 \(v_i\) 很大,无法分治 ntt 求解。

将积化为和,两边取对数。

\[\begin{aligned} \ln(G(x)) &= \sum\limits_{i = 1}^{k} \ln\dfrac{1}{1 - x^{v_i}}\\ \\ &= \sum\limits_{i = 1}^{k} -\ln\ (1 - x^{v_i})\\ \\ &= \sum\limits_{i = 1}^{k} \sum_{j \ge 1} \dfrac{x^{v_ij}}{j} \end{aligned} \]


第二类斯特林数

第二类斯特林数(斯特林子集数)\(\begin{Bmatrix}n\\ k\end{Bmatrix}\),也可记做 \(S_2(n,k)\),表示将 \(n\) 个两两不同的元素,划分为 \(k\) 个互不区分的非空子集的方案数。

递推关系

我们插入一个新元素时,有两种方案:

  • 将新元素放入一个现有的非空子集,有 \(k\begin{Bmatrix}n-1\\ k\end{Bmatrix}\) 种方案。
  • 将新元素单独放入一个子集,有 \(\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}\) 种方案;

\[\begin{Bmatrix}n\\ k\end{Bmatrix}=\begin{Bmatrix}n-1\\ k-1\end{Bmatrix}+k\begin{Bmatrix}n-1\\ k\end{Bmatrix} \]

边界是 \(\begin{Bmatrix}n\\ 0\end{Bmatrix}=[n=0]\)

通项公式

不妨先认为 \(k\) 个集合互不相同,转化成经典容斥问题,最后乘上 \(\dfrac{1}{k!}\)

\[\begin{Bmatrix}n\\ k\end{Bmatrix} = \dfrac{1}{k!}\sum\limits_{i = 0}^k (-1)^i C_k^i (k - i)^n \]

重要公式

记下降阶乘幂 \(x^{\underline{n}}=\dfrac{x!}{(x-n)!}=\prod_{k=0}^{n-1} (x-k)\)

则可以利用下面的恒等式将普通幂转化为下降幂:

\[x^n =\sum\limits_{k = 0}^n \begin{Bmatrix}n\\ k\end{Bmatrix} \begin{pmatrix}x\\ k\end{pmatrix} k! =\sum\limits_{k = 0}^n \begin{Bmatrix}n\\ k\end{Bmatrix} x^{\underline{k}} \]

考虑各式组合意义。

  • \(x^n \rightarrow\) \(n\) 个不同的球放入 \(x\) 个不同的盒子。
  • \(\begin{pmatrix}x\\ k\end{pmatrix} \rightarrow\) \(x\) 个盒子中选出 \(k\) 个。
  • \(\begin{Bmatrix}n\\ k\end{Bmatrix} \rightarrow\) \(n\) 个不同的球放入 \(k\) 个相同的盒子且都不为空。
  • \(k! \rightarrow\) 将选出的 \(k\) 个盒子排列。

正确性显然。

指数生成函数

\[\sum_{n \ge 0} \begin{Bmatrix}n\\k\end{Bmatrix}\dfrac{x^n}{n!} = \dfrac{1}{k!}(\exp(x) - 1)^k \]

不妨将盒子染成 \(k\) 种不同颜色,每种颜色在长度为 \(n\) 的排列中必须出现一次。

对于第一种颜色,\(F_1(x) = x + \dfrac{x^2}{2!} + \dfrac{x^3}{3!} + \cdots = \exp(x) - 1\)(没有零次项,因为必须出现)。

全部的合法方案为 \([x^n]\prod F_i\)

最后将染色去除,得到 \(G(x) = \dfrac{1}{k!}(\exp(x) - 1)^k\)

第二类斯特林数·列

利用公式

\[\sum_{n \ge 0} \begin{Bmatrix}n\\k\end{Bmatrix}\dfrac{x^n}{n!} = \dfrac{1}{k!}(\exp(x) - 1)^k \]

其中

\[f(x)^k = \exp(\ln f(x)^k) = \exp(k\ln f(x)) \]

如果 \([x^0]f(x) \neq 1\) 则不能直接求对。

考虑给每项除以一个公因式 \(a_ix^i\),满足第 \(i\) 项是系数非 \(0\) 的最低项。

最后再乘上 \((a_ix^i)^k\)

P5396 第二类斯特林数·列submission

EGF 求得的系数为 \(\dfrac{a_n}{n!}\)

第二类斯特林数·行

\[\begin{aligned} \begin{Bmatrix}n\\k\end{Bmatrix} &= \dfrac{1}{k!}\sum_{i = 0}^k(-1)^i\begin{pmatrix}k\\i\end{pmatrix}(k - i)^n\\ \\ &= \sum_{i = 0}^k\dfrac{(-1)^i}{i!}\dfrac{(k - i)^n}{(k - i)!}\\ \end{aligned} \]

\(F(x) = \sum_{i \ge 0} \dfrac{(-1)^i}{i!}x^i \,, \ G(x) = \sum_{i \ge 0} \dfrac{i^n}{i!}x^i\)

于是 \(S_2(n) = F * G\)

P5395 第二类斯特林数·行submission


第一类斯特林数

\(k\) 个轮换的 \(n\) 元置换的方案,记为 \(c(n, k)\)\(\begin{bmatrix}n\\k\end{bmatrix}\)

置换向原位置连边,形成若干个环,即轮换。

对于置换 \(\sigma = \begin{pmatrix}1 & 2 & 3 & 4 & 5\\3 & 5 & 1 & 2 & 4\end{pmatrix}\),有两个轮换:

递推关系

\[\begin{bmatrix}n\\k\end{bmatrix} = \begin{bmatrix}n - 1\\k - 1\end{bmatrix} + (n - 1)\begin{bmatrix}n - 1\\k\end{bmatrix} \]

边界:\(\begin{bmatrix}0\\0\end{bmatrix} = \begin{bmatrix}1\\1\end{bmatrix} = 1\)

  • 自己向自己连边,单独成环。

  • 已经有了 \(k\) 个环,在 \(n - 1\) 个空隙里选一个插入。

重要公式

上升幂转普通幂

\[x^{\overline{n}} = \sum_{k = 0}^n\begin{bmatrix}n\\k\end{bmatrix}x^k \]

假设 \(x^{\overline{n}} = \sum\limits_{k = 0}^nf(n, k)x^k\)

联立

\[\begin{cases} x^{\overline{n}} = \sum\limits_{k = 0}^nf(n, k)x^k\\ \\ x^{\overline{n}} = (x + n - 1)x^{\overline{n - 1}} = \sum\limits_{k = 0}^{n - 1}f(n - 1, k)\cdot (x + n - 1) \cdot x^k\\ \end{cases} \]

得到 \(f\) 的递推式:\(f(n, k) = f(n - 1, k - 1) + (n - 1)\cdot f(n - 1, k)\)

发现 \(f\) 与第一类斯特林数递推式相同,初值相同,证毕。

下降幂转普通幂

\[x^{\underline{n}} = \sum_{k = 0}^n(-1)^{n + k}\begin{bmatrix}n\\k\end{bmatrix}x^k \]

\(-x\) 带入 \(1\) 中的 \(x\)

\[\begin{aligned} (-x)^{\overline{n}} &= (-x)(1 - x)\cdots(n - 1 - x)\\ \\ &= (-1)^n\cdot x(x - 1)\cdots(x - n + 1)\\ \\ &= (-1)^n\cdot x^{\underline {n}} = \sum_{k = 0}^n\begin{bmatrix}n\\k\end{bmatrix}(-x)^k\\ \end{aligned} \]

把左式的负号移至右式,即证。

指数生成函数

等效于 \(n\) 个不同球放入 \(k\) 个互不区分且非空的盒子,装有 \(i\) 个球的盒子有 \((i - 1)!\) 种不同形态,求方案数。

\(i\) 个球只用大小为 \(i\) 的盒子的方案为 \((i - 1)!\)

先将盒子编号,对于每个盒子,有生成函数 \(F(x) = x + \dfrac{x^2}{2!} + 2!\cdot\dfrac{x^3}{3!} + \cdots = -\ln(1 - x)\)

\(k\) 个盒子,则 \(G(x) = \dfrac{1}{k!}[-\ln(1 - x)]^k\)

第一类斯特林数·列

\[\begin{bmatrix}n\\k\end{bmatrix}= n! \cdot [x^n]G(x) \]

P5409 第一类斯特林数·列submission

第一类斯特林数·行

展开

\[x^{\overline{n}} = \sum_{k = 0}^n\begin{bmatrix}n\\k\end{bmatrix}x^k \]

显然可以分治 ntt \(O(n\log^2n)\) 求(但被出题人卡了)。

考虑倍增。

\[x^{\overline{2n}} = x^\overline{n}(x + n)^\overline{n} \]

\(f(x) = \prod\limits_{i = 0}^{n - 1}(x + i) = \sum\limits_{i = 0}^{n}a_ix^i\),则 \((x + n)^\overline{n} = f(x + n)\)

问题转化为已知多项式 \(f(x)\),快速求 \(f(x + c)\)

\[\begin{aligned} \sum\limits_{i = 0}^{n}a_i(x + c)^i &= \sum\limits_{i = 0}^{n}a_i\sum_{j = 0}^i\begin{pmatrix}i\\j\end{pmatrix}x^j \cdot c^{i - j}\\ \\ &= \sum_{j = 0}^nx^j \sum_{i = j}^{n}\begin{pmatrix}i\\j\end{pmatrix}a_i\cdot c^{i - j}\\ \\ &= \sum_{j = 0}^n\dfrac{x^j}{j!} \sum_{i = j}^{n}a_i\cdot i!\cdot \dfrac{c^{i - j}}{(i - j)!}\\ \end{aligned} \]

第二个求和式可以写成 \(g(x) = \sum i!\cdot a_ix^{i}, \ h(x) = \sum \dfrac{c^i}{i!}x^{n - i}\) 的卷积。

\([x^j]f(x + c) = [x^{j + n}]g*h\)

时间复杂度 \(T(n) = T(n / 2) + O(n\log n) = O(n\log n)\)

submission

有符号的第一类斯特林数

定义:\(S_1(n, k) = (-1)^{n + k}\begin{bmatrix}n\\k\end{bmatrix}\)

重要公式

\[x^{\underline{n}} = \sum_{k = 0}^nS_1(n, k)x^k \]

指数生成函数

\[\sum_{i \ge 0}S_1(n, k)\dfrac{x^n}{n!} = \dfrac{1}{k!}[\ln(1 + x)]^k \]

两类斯特林数的关系及斯特林反演

\[\begin{aligned} \sum_{k \ge 0} (-1)^{n + k}\begin{bmatrix}n\\k\end{bmatrix}\begin{Bmatrix}k\\m\end{Bmatrix} = [n = m]\\ \\ \sum_{k \ge 0} (-1)^{k + m}\begin{Bmatrix}n\\k\end{Bmatrix}\begin{bmatrix}k\\m\end{bmatrix} = [n = m]\\ \end{aligned} \]

证明:

对于公式 \(x^{n} = \sum\limits_{k = 0}^n\begin{Bmatrix}n\\k\end{Bmatrix}x^\underline{k}\),可以写成向量之积:

\[\begin{pmatrix} x^0\\ x^1\\ \vdots\\ x^n\\ \vdots\\ \end{pmatrix} = \begin{pmatrix} s_2(0, 0)\\ s_2(1, 0) & s_2(1, 1)\\ \vdots\\ s_2(n, 0) & s_2(n, 1) & s_2(n, 2) & \cdots & s_2(n, n)\\ \vdots \end{pmatrix} \begin{pmatrix} x^\underline0\\ x^\underline1\\ \vdots\\ x^\underline n\\ \vdots\\ \end{pmatrix} \]

对于 有符号 第一类斯特林数:

\[\begin{pmatrix} x^\underline0\\ x^\underline1\\ \vdots\\ x^\underline n\\ \vdots\\ \end{pmatrix} = \begin{pmatrix} s_1(0, 0)\\ s_1(1, 0) & s_1(1, 1)\\ \vdots\\ s_1(n, 0) & s_1(n, 1) & s_1(n, 2) & \cdots & s_1(n, n)\\ \vdots \end{pmatrix} \begin{pmatrix} x^0\\ x^1\\ \vdots\\ x^n\\ \vdots\\ \end{pmatrix} \]

我们有 \(S_1\times S_2 = I\)

则在 \(S_1\) 中取一行 \(n\),在 \(S_2\) 中取一列 \(m\),两个向量之积为 \(1\) 当且仅当 \(m = n\)

\(\sum_{k \ge 0} (-1)^{n + k}\begin{bmatrix}n\\k\end{bmatrix}\begin{Bmatrix}k\\m\end{Bmatrix} = [n = m]\)

斯特林反演

\[f_n = \sum_{i = 0}^n\begin{Bmatrix}n\\i\end{Bmatrix}g_i \iff g_n = \sum_{i = 0}^n(-1)^{n + i}\begin{bmatrix}n\\i\end{bmatrix}f_i \]

证明:

\[\begin{aligned} f_n &= \sum_{i = 0}^n[i = n]f_i\\ \\ &= \sum_{i = 0}^n\sum_{k \ge 0}^n (-1)^{k + i}\begin{Bmatrix}n\\k\end{Bmatrix}\begin{bmatrix}k\\i\end{bmatrix}f_i\\ \\ &= \sum_{k \ge 0}^n\begin{Bmatrix}n\\k\end{Bmatrix}\sum_{i = 0}^n (-1)^{k + m}\begin{bmatrix}k\\i\end{bmatrix}f_i\\ \\ &= \sum_{k \ge 0}^n\begin{Bmatrix}n\\k\end{Bmatrix}f_k \end{aligned} \]


整数拆分

\(n\)\(k\) 无序拆分

\(n\) 个无标号球分配到 \(k\) 个无标号盒子的方案数,满足每个盒子不为空,记为 \(p(n, k)\)

递推关系

\[p(n, k) = p(n - 1, k - 1) + p(n - k, k) \]

假设第 \(i\) 个盒子(第 \(i\) 行)里有 \(a_i\) 个球,满足 \(a_1 \ge a_2\cdots\ge a_k \ge 1\)

分两部分考虑。

  • \(k\) 个盒子有且仅有新加入的一个球,方案为 \(p(n - 1, k - 1)\)
  • \(k\) 个盒子不止一个球,把黄色一列去掉,方案为 \(p(n - k, k)\)

常生成函数

考虑上图中有多少有 \(i\) 个球的列。

\(i\) 个球时,只能有 \(1\) 列,一种方案。

\(2i\) 个球时,只能有 \(2\) 列,一种方案。

因此其常生成函数为 \(F_i(x) = 1 + x^{i} + x^{2i} + \cdots = \dfrac{1}{1 - x^i}\)

\(G_k = \prod_{i = 1}^kF_i\)

由于至少要有一列为 \(k\),所以

\[P_k(x) = G_k(x) - G_{k - 1}(x) = x^k\prod\limits_{i = 1}^k\dfrac{1}{1 - x^i} \]

  • 快速求 \(P_k\) 的前 \(n\) 项:对后式先取 \(\ln\)\(\exp\),详见 形式幂级数的更多运算-例题-三轮

    \[\sum\limits_{i = 1}^{k} \ln\dfrac{1}{1 - x^{i}} = \sum\limits_{i = 1}^{k} \sum_{j \ge 1} \dfrac{x^{ij}}{j} \]

\(n\) 的无序拆分

\(n\) 个无标号球分配到一些无标号盒子的方案数,满足每个盒子不为空,记为 \(p(n)\)

可知 \(p(n) = \sum_{k = 1}^np(n, k)\)

常生成函数

延续上板的思考方向,行的个数没有限制,所以只要一些长度为 \(i\) 的凑出 \(n\) 个球即可。

那么

\[\begin{aligned} P(x) &=\prod_{i \ge 1}\dfrac{1}{1 - x^i}\\ \\ &= \exp\sum_{i \ge1}\sum_{j \ge 1}\dfrac{x^{ij}}{j}\\ \\ &= \exp\sum_{n \ge1}\sum_{d \mid n}\dfrac{x^{n}}{d}\\ \end{aligned} \]

LOJ6268. 分拆数submission

递推关系

证明繁琐,当结论记。

\[p(n) = \sum_{k \ge 1}(-1)^{k - 1}[p(n - \dfrac{3k^2 - k}{2}) + p(n - \dfrac{3k^2 + k}{2})] \]

产生贡献的项只有 \(O(\sqrt N)\) 个,复杂度 \(O(N\sqrt N)\)

主要运用于模数不友好的情况。


生成函数模型

分配问题总结

\(n\) 个球放入 \(k\) 个盒子,球方案数。

\[\begin{array}{|c|*{3}{l|}} \hline n\text{ 个球} & k\text{ 个盒子} & \text{盒子可以为空} & \text{每个盒子至少一个球}\\ \hline \\ \text{有标号} & \text{有标号} & k^n & k!\begin{Bmatrix}n\\k\end{Bmatrix}\\ \hline \\ \text{有标号} & \text{无标号} & \sum\limits_{i = 1}^k\begin{Bmatrix}n\\k\end{Bmatrix} & \begin{Bmatrix}n\\k\end{Bmatrix}\\ \hline \\ \text{无标号} & \text{有标号} & \begin{pmatrix}n + k - 1\\k - 1\end{pmatrix} & \begin{pmatrix}n - 1\\k - 1\end{pmatrix}\\ \hline \\ \text{无标号} & \text{无标号} & p(n + k, k) & p(n, k)\\ \hline \end{array} \]

p(n + k, k):把每行之前都加一个球,则 \(k\) 个盒子都不为空

分配问题(加强版1)

\(n\) 个球放入 \(k\) 个盒子,装有 \(i\) 个球的盒子有 \(f_i\) 种形态,不同形态算不同方案,有多少种方案?

\(\{f_i\}_{i\ge1}\) 的常生成函数 \(F(x) = \sum_{i\ge1}f_ix^i\),其指数生成函数 \(E(x) = \sum_{i \ge 1}\dfrac{f_i}{i!}x^i\)(有没有常数项取决于需不需要每个盒子都有球)。

\[\begin{array}{|c|*{3}{l|}} \hline n\text{ 个球} & k\text{ 个盒子} & 方案的生成函数\\ \hline \\ \text{有标号} & \text{有标号} & \text{e.g.f} = E(x)^k\\ \hline \\ \text{有标号} & \text{无标号} & \text{e.g.f} = \dfrac{1}{k!}E(x)^k\\ \hline \\ \text{无标号} & \text{有标号} & \text{o.g.f} = F(x)^k\\ \hline \end{array} \]

分配问题(加强版2)

\(n\) 个球放入一些盒子且每个盒子都不为空,装有 \(i\) 个球的盒子有 \(f_i\) 种形态,不同形态算不同方案,有多少种方案?

\(\{f_i\}_{i\ge1}\) 的常生成函数 \(F(x) = \sum_{i\ge1}f_ix^i\),其指数生成函数 \(E(x) = \sum_{i \ge 1}\dfrac{f_i}{i!}x^i\)

即对加强版 \(1\) 做个 \(\sum_{i\ge0}\)

\[\begin{array}{|c|*{3}{l|}} \hline n\text{ 个球} & k\text{ 个盒子} & 方案的生成函数\\ \hline \text{有标号} & \text{有标号} & \text{e.g.f} = \dfrac{1}{1 - E(x)^k}\\ \hline \\ \text{有标号} & \text{无标号} & \text{e.g.f} = \exp E(x)^k\\ \hline \\ \text{无标号} & \text{有标号} & \text{o.g.f} = \dfrac{1}{1 - F(x)^k}\\ \hline \text{无标号} & \text{无标号} & \text{o.g.f} = \prod_{i \ge 1}(\dfrac{1}{1 - x^i})^{f_i} = \exp\sum_{j \ge 1}\dfrac{1}{j}F(x^j) \\ \hline \end{array} \]

无标号/无标号:

考虑大小为 \(i\) 的盒子的常生成函数(即 \([x^n]\) 表示只用大小为 \(i\) 的盒子放入 \(n\) 个球的方案)。

对于盒子的第一种形态 \(g(x) = 1 + x^i + x^{2i} + \cdots\)

以此类推,其常生成函数为 \(g^{f_i - 1}(x)\)

所以无标号/无标号的常生成函数为

\[\prod_{i \ge 1}(\dfrac{1}{1 - x^i})^{f_i} = \exp\sum_{i \ge 1} f_i\sum_{j \ge 1}\dfrac{x^{ij}}{j} = \exp\sum_{j \ge 1}\dfrac{1}{j}\sum_{i \ge 1} f_ix^{ij} = \exp\sum_{j \ge 1}\dfrac{1}{j}F(x^j) \]

例题

CF961G Partitions

题意:

给出 \(n\) 个物品,每个物品有一个权值 \(w_i\)

定义一个集合 \(S\) 的权值 \(W(S)=|S|\sum\limits_{x\in S}w_x\)

定义一个划分的权值为 \(W'(R)=\sum\limits_{S\in R}W(S)\)

求将 \(n\) 个物品划分成 \(k\) 个集合的所有方案的权值和。答案对 \(10^9+7\) 取模。

\(n,k\le2\times10^5\)\(w_i\le10^9\)


感性理解,每个数的贡献是相同的,所以答案一定是 \(P\cdot \sum a_i\) 的形式。

枚举当前元素所在集合大小。

\[\begin{aligned} P &= \sum_{i = 1}^ni\cdot \begin{pmatrix}n - 1\\i - 1\end{pmatrix}\begin{Bmatrix}n - i\\k - 1\end{Bmatrix} &\text{从剩下 } n - 1 \text{ 个里选出在当前集合的,再划分其余的 }n - i \text{个。}\\ \\ &= \sum_{i = 1}^ni\cdot \dfrac{(n - 1)!}{(i - 1)!(n - i)!}\sum_{j = 0}^{k - 1}(-1)^j\dfrac{(k - j - 1)^{n - i}}{j!(k - j - 1)!}\\ \\ &= \sum_{j = 0}^{k - 1}(-1)^j\dfrac{1}{j!(k - j - 1)!}\sum_{i = 1}^ni\cdot \dfrac{(n - 1)!(k - j - 1)^{n - i}}{(i - 1)!(n - i)!}\\ \end{aligned} \]

单独计算后面一个求和式,把 \(k - j - 1\) 当作常数 \(t\)

\[\begin{aligned} \sum_{i = 1}^ni\cdot \dfrac{(n - 1)!t^{n - i}}{(i - 1)!(n - i)!} &=\sum_{i = 1}^n\dfrac{(n - 1)!t^{n - i}}{(i - 1)!(n - i)!}\cdot (i + 1 - 1)\\ \\ &=\sum_{i = 1}^n\dfrac{(n - 1)!t^{n - i}}{(i - 1)!(n - i)!}\cdot (i - 1 + 1)\\ \\ &=(n- 1)\sum_{i = 1}^n\dfrac{(n - 2)!}{(i - 2)!(n - i)!}\cdot t^{n - i} + \sum_{i = 1}^n\dfrac{(n - 1)!}{(i - 1)!(n - i)!}\cdot t^{n - i}\\ \\ &=(n- 1)\sum_{i = 1}^n\begin{pmatrix}n - 2\\n- i\end{pmatrix}\cdot t^{n - i} + \sum_{i = 1}^n\begin{pmatrix}n - 1\\n- i\end{pmatrix}\cdot t^{n - i}\\ \\ &=(n- 1)(t + 1)^{n - 2} + (t + 1)^{n - 1} \end{aligned} \]

时间复杂度 \(O(n\log n)\)

还有一种更为精巧的解法:

考虑 \(w_i\) 会对答案产生多少次贡献?

在一个大小为 \(|S|\) 的集合中,\(w_i\) 贡献 \(|S|\) 次,等效于集合中每一个元素都使 \(w_i\) 产生一次贡献。

分两部分讨论

  • 自己使自己的产生的贡献,显然每一种划分产生一次,共 \(\begin{Bmatrix}n\\k\end{Bmatrix}\) 次。

  • 其他元素使自己的产生的贡献,把其余 \(n - 1\) 个球划分好 \(k\) 个集合,对于每种划分,当前元素可以任选一个集合放进去,因此 \(n - 1\) 个物品都会有一次贡献,共 \((n - 1)\begin{Bmatrix}n - 1\\k\end{Bmatrix}\)

综上 \(P = \begin{Bmatrix}n\\k\end{Bmatrix} + (n - 1)\begin{Bmatrix}n-1\\k\end{Bmatrix}\)

submission

CF960G Bandit Blues

题意:给定 \(n, \ a, \ b\),定义 \(A\) 为一个排列中是前缀最大值的数的个数,定义 \(B\) 为一个排列中是后缀最大值的数的个数,求长度为 \(n\) 的排列中满足 \(A = a\)\(B = b\) 的排列个数。\(n \le 10^5\),对 \(998244353\) 取模。

首先,排列里最大值一定同时是前缀最大和后缀最大,如果存在 \(a/b = 0\),无解。

\(f(i, j)\) 表示 \(i\) 个数的排列有 \(j\) 个前缀最大的方案。

不妨从大到小一个一个填。

  • 填到序列的最前面,一定是前缀最大,有 \(f(i - 1, j - 1)\) 种情况。
  • 由于所有数都比他大,填到任意一个数后面,有 \((i - 1)f(i - 1, j)\) 种情况。

所以 \(f(i, j) = f(i - 1, j - 1) + (n - 1) f(i - 1, j)\),恰为第一类斯特林数的递推式,由于边界相同,所以 \(f(i, j) = \begin{bmatrix}i\\j\end{bmatrix}\)

枚举最大值左边的元素个数。

则答案为 \(\sum\limits_{i = 0}^{n - 1}\begin{pmatrix}n - 1\\i\end{pmatrix}\begin{bmatrix}i\\a - 1\end{bmatrix}\begin{bmatrix}n - i - 1\\b - 1\end{bmatrix}\)

可以直接求出两列斯特林数,但形式仍不够优美。

考虑式子的组合意义:选出 \(i\) 个排成 \(a - 1\) 个环 \(\rightarrow\) 剩下 \(n - 1 - i\) 个排成 \(b - 1\) 个环。

也就是 \(n - 1\) 个元素排成 \(a + b - 2\) 个环,选其中 \(a - 1\) 个分给左边。

于是答案化简为 \(\begin{bmatrix}n - 1\\a + b- 2\end{bmatrix}\begin{pmatrix}a + b - 2\\a - 1 \end{pmatrix}\)

第一列斯特林数没有实用的通项公式,随便求出一行或一列即可。

submission

附录:模板

#include<bits/stdc++.h>
using namespace std;

using ll = long long;
constexpr int N = 5e5 + 5, P = 998244353;		// g = 3

ll gg[30], ig[30], fac[N], ifac[N], inv[N];

ll qpow(ll a, ll b) {
	ll ret = 1;
	while(b) {
		if(b & 1) ret = ret * a % P;
		b >>= 1;
		a = a * a % P;
	}
	return ret;
}

void init() {
	gg[0] = ig[0] = 1;
	for(int i = 1; i < 30; ++ i) gg[i] = qpow(3, (P - 1) / (1 << i));
	for(int i = 1; i < 30; ++ i) ig[i] = qpow(gg[i], P - 2);
	fac[0] = 1;
	for(int i = 1; i < N; ++ i) {
		inv[i] = (i == 1) ? 1 : -(P / i) * inv[P % i] % P;
		fac[i] = fac[i - 1] * i % P;
	}
	ifac[N - 1] = qpow(fac[N - 1], P - 2);
	for(int i = N - 1; i >= 1; -- i) {
		ifac[i - 1] = ifac[i] * i % P; 
	}
}

int rev[N];

void ntt(ll *a, int tot, int ty) {
	for(int i = 0; i < tot; ++ i) {
		if(i < rev[i]) {
			swap(a[i], a[rev[i]]);
		}
	}
	int t = 1;
	for(int mid = 1; mid < tot; mid <<= 1, ++ t) {
		ll g1 = gg[t];
		if(ty == -1) {
			g1 = ig[t];
		}
		for(int i = 0; i < tot; i += mid * 2) {
			ll gk = 1;
			for(int j = 0; j < mid; ++ j, gk = gk * g1 % P) {
				ll x = a[i + j], y = a[i + j + mid];
				a[i + j] = (x + gk * y) % P;
				a[i + j + mid] = (x - gk * y) % P;
			}
		}
	}
	if(ty == -1) {
		ll tmp = qpow(tot, P - 2);
		for(int i = 0; i < tot; ++ i) {
			a[i] = a[i] * tmp % P;
		}
	}
}


void polymul(ll *f, const ll *g, const ll *h, int n, int m) {		// 项数,非次数
	static ll a[N], b[N];
	int tot = 1, bit = 0;
	while(tot < n + m - 1) ++ bit, tot <<= 1;
	for(int i = 0; i < tot; ++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1);
	memcpy(a, g, n * 8), memset(a + n, 0, (tot - n) * 8);
	memcpy(b, h, m * 8), memset(b + m, 0, (tot - m) * 8);
	ntt(a, tot, 1), ntt(b, tot, 1);
	for(int i = 0; i < tot; ++ i) a[i] = a[i] * b[i] % P;
	ntt(a, tot, -1);
	memcpy(f, a, tot * 8);
}

void polyinv(ll *f, const ll *h, int n){
	static ll d[N], g[N];
	int V = 1; while(V < n + n - 1) V <<= 1;
	memcpy(d, h, n * 8), memset(d + n, 0, (V - n) * 8);
	memset(f, 0, V * 8), memset(g, 0, V * 8);
	f[0] = qpow(h[0], P - 2);
	for(int w = 2; w / 2 < n; w <<= 1){
		memcpy(g, d, w * 8);
		for(int i = 0; i < w * 2; ++i) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? w : 0);
		ntt(f, w << 1, 1), ntt(g, w << 1, 1);
		for(int i = 0; i < w * 2; ++i) f[i] = (2 - f[i] * g[i]) % P * f[i] % P;
		ntt(f, w << 1, -1);
		memset(f + w, 0, w * 8);
	}
	memset(f + n, 0, (V - n) * 8);
}


void polysqrt(ll *f, const ll *h, int n){
	static ll d[N], g[N], f_inv[N];
	int V = 1; while(V < n + n - 1) V <<= 1;
	memcpy(d, h, n * 8), memset(d + n, 0, (V - n) * 8);
	memset(f, 0, V * 8), memset(g, 0, V * 8), memset(f_inv, 0, V * 8);
	f[0] = 1;
	constexpr int i2 = 499122177;
	for(int w = 2; w / 2 < n; w <<= 1){
		memcpy(g, d, w * 8);
		for(int i = 0; i < w * 2; ++i) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? w : 0);
		polyinv(f_inv, f, w);
		ntt(f, w << 1, 1), ntt(g, w << 1, 1), ntt(f_inv, w << 1, 1);
		for(int i = 0; i < w * 2; ++i) f[i] = (f[i] + f_inv[i] * g[i]) % P * i2 % P;
		ntt(f, w << 1, -1);
		memset(f + w, 0, w * 8);
	}
	memset(f + n, 0, (V - n) * 8);
}


void polyder(ll *f, const ll *h, int n) {							// 项数,非次数
	for(int i = 0; i <= n - 1; ++ i) {
		f[i] = (i + 1) * h[i + 1] % P;
	}
	f[n - 1] = 0;
}


void polyint(ll *f, const ll *h, int n) {							// 项数,非次数
	for(int i = n - 1; i >= 1; -- i) {
		f[i] = h[i - 1] * inv[i] % P; 
	}
	f[0] = 0;
}


void polyln(ll *f, const ll *h, int n) {				// h[0] = 1
	static ll a[N], b[N];
	polyinv(a, h, n);
	polyder(b, h, n);
	polymul(a, a, b, n, n);
	polyint(f, a, n);	
}

void polyexp(ll *f, const ll *h, int n) {				// h[0] = 0
	static ll d[N], g[N], f_ln[N];
	int V = 1; while(V < n + n - 1) V <<= 1;
	memcpy(d, h, n * 8), memset(d + n, 0, (V - n) * 8);
	memset(f, 0, V * 8), memset(g, 0, V * 8), memset(f_ln, 0, V * 8);
	f[0] = 1;	//ln(h[0])
	for(int w = 2; w / 2 < n; w <<= 1){
		memcpy(g, d, w * 8);
		for(int i = 0; i < w * 2; ++i) rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? w : 0);
		polyln(f_ln, f, w);
		ntt(f, w << 1, 1), ntt(g, w << 1, 1), ntt(f_ln, w << 1, 1);
		for(int i = 0; i < w * 2; ++i) f[i] = (1 - f_ln[i] + g[i]) % P * f[i] % P;
		ntt(f, w << 1, -1);
		memset(f + w, 0, w * 8);
	}
	memset(f + n, 0, (V - n) * 8);
}

void polypow(ll *f, ll *h, string K, int n) {
	int cur = 0;
	while(cur < n && h[cur] == 0) ++ cur;
	ll k1 = 0, k2 = 0;
	for(auto ch : K) {
		if((k1 * 10 + ch - '0') * cur >= n || cur == n) {
			for(int i = 0; i < n; ++ i) f[i] = 0;
			return;
		}
		k1 = (k1 * 10 + ch - '0') % P;
		k2 = (k2 * 10 + ch - '0') % (P - 1);
	}
	
	ll h_cur = h[cur], icur = qpow(h_cur, P - 2);
	for(int i = cur; i < n; ++ i) {
		f[i - cur] = h[i] * icur % P;
	}
	polyln(f, f, n - cur);
	for(int i = 0; i < n - cur; ++ i) f[i] = f[i] * k1 % P;
	polyexp(f, f, n - cur);
	h_cur = qpow(h_cur, k2);
	for(int i = n - 1; i >= k1 * cur; -- i) f[i] = f[i - k1 * cur] * h_cur % P;
	for(int i = 0; i < k1 * cur; ++ i) f[i] = 0;
}

void Stirling2ndCol(ll *f, int n, int k) { //S2(0...n, k)
	for(int i = 1; i <= n; ++ i) {
		f[i] = ifac[i];
	}
	polypow(f, f, to_string(k), n + 1);
	
	for(int i = 0; i <= n; ++ i) {
		f[i] = f[i] * ifac[k] % P * fac[i] % P;
	}
}

void Stirling2ndRow(ll *f, int n) { // S2(n, 0...n)
	static ll g[N];
	for(int i = 0; i <= n; ++ i) {
		f[i] = (i & 1) ? -ifac[i] : ifac[i];
		g[i] = qpow(i, n) * ifac[i] % P;
	}
	polymul(f, f, g, n + 1, n + 1);
}

void Stirling1stCol(ll *f, int n, int k) { //c(0...n, k)
	for(int i = 2; i <= n; ++ i) {
		f[i] = 0;
	}
	f[0] = 1, f[1] = -1;
	polyln(f, f, n + 1);
	for(int i = 0; i <= n; ++ i) f[i] = -f[i];
	
	polypow(f, f, to_string(k), n + 1);
	for(int i = 0; i <= n; ++ i) {
		f[i] = f[i] * ifac[k] % P * fac[i] % P;
	}
}

void Offset(ll *f, ll *h, int n, int c) {		// f <-- h(x + c) 偏移   n次多项式
	static ll g[N], d[N];
	for(int i = 0; i <= n; ++ i) {
		g[i] = fac[i] * h[i] % P;
		d[i] = (i == 0 ? 1 : d[i - 1] * c % P);
	}
	for(int i = 0; i <= n; ++ i) d[i] = d[i] * ifac[i] % P;
	reverse(d, d + n + 1);
	polymul(f, g, d, n + 1, n + 1);
	for(int i = 0; i <= n; ++ i) {
		f[i] = f[i +  n] * ifac[i] % P;
	}
	memset(f + n + 1, 0, n);
}

void Stirling1stRow(ll *f, int n) { // c(n, 0...n)
	static int stk[30], tp;
	static ll g[N];
	tp = 0;
	while(n) {
		stk[++ tp] = n;
		n >>= 1;
	}
	f[0] = 0, f[1] = 1;
	n = 1;
	while(-- tp) {
		Offset(g, f, n, n);
		polymul(f, f, g, n + 1, n + 1);
		n <<= 1;
		if(stk[tp] == n + 1) {
			f[n + 1] = f[n];
			for(int i = n; i >= 1; -- i) {
				f[i] = (f[i] * n + f[i - 1]) % P;
			}
			++ n;
		}
	}
}

void Partition(ll *f, int n) {
	memset(f, 0, (n + 1) * 8);
	for(int i = 1; i <= n; ++ i) {
		for(int j = i; j <= n; j += i) {
			f[j] = (f[j] + inv[i]) % P;
		}
	}
	polyexp(f, f, n + 1);
}

ll n, k, f[N];

int main() {
	cin.tie(0)->sync_with_stdio(0);
	init();
	
	return 0;
}

Reference

OI Wiki

英雄哪里出来:威尔逊定理 —— 数论四大定理之一

skywalkert:浅谈一类积性函数的前缀和

《线性代数》(机械工业出版社)

非's Blog

posted @ 2024-05-06 01:13  Lu_xZ  阅读(104)  评论(0编辑  收藏  举报