[BZOJ5481]矩阵

题目

传送门 to BZOJ可是已经凉透了

题目概要
对于每个 i ∈ [ 2 , n ] i\in[2,n] i[2,n],求出有多少个 i × i i\times i i×i 01 01 01 矩阵满足:每一行每一列的和都是 2 2 2

数据范围与约定
n ⩽ 1 0 7 n\leqslant 10^7 n107

思路

将第 i i i 行都看做节点 r i r_i ri,第 i i i 列都看做节点 c i c_i ci,若 a i j = 1 a_{ij}=1 aij=1 则将 r i r_i ri c i c_i ci 之间连一条无向边。可以发现我们就是做 二分图环剖分。事实上 o e i s \rm oeis oeis 已收录此数列

无论如何,需要先求出 g n g_n gn 为,大小为 2 n 2n 2n 的环有多少种。显然 X \frak X X 部和 Y \frak Y Y 部可以分别排列,避免重复而规定 X \frak X X 的某个元素为首,又考虑到环是不分方向的,可知
g n = n ! ( n − 1 ) ! 2 ( n ⩾ 2 ) g_n=\frac{n!(n{-}1)!}{2}\quad(n\geqslant 2) gn=2n!(n1)!(n2)

思路壹

枚举其中的一个环,要求必须包含某个特定点。记答案为 f n f_n fn
f n = ∑ x = 2 n ( n x ) ( n − 1 x − 1 ) g x f n − x = n ! ( n − 1 ) ! 2 ∑ x = 2 n x ! ( x − 1 ) ! x ! [ ( n − x ) ! ] 2 ( x − 1 ) ! f n − x ⇒ f n ( n ! ) 2 = 1 2 n ∑ x = 2 n f n − x [ ( n − x ) ! ] 2 \begin{aligned} f_n &=\sum_{x=2}^{n}{n\choose{x}}{n{-}1\choose x{-}1}g_x f_{n-x}\\ &={n!(n{-}1)!\over 2}\sum_{x=2}^{n}\frac{x!(x{-}1)!}{x![(n{-}x)!]^2(x{-1})!}f_{n-x}\\ \Rightarrow\frac{f_n}{(n!)^2}&=\frac{1}{2n}\sum_{x=2}^{n}\frac{f_{n-x}}{[(n{-x})!]^2} \end{aligned} fn(n!)2fn=x=2n(xn)(x1n1)gxfnx=2n!(n1)!x=2nx![(nx)!]2(x1)!x!(x1)!fnx=2n1x=2n[(nx)!]2fnx

简单前缀和可做到 O ( n ) \mathcal O(n) O(n)

思路贰

有标号连通块划分?记 F ( x ) = ∑ n ⩾ 2 n ! ( n − 1 ) ! 2 ⋅ x n ( n ! ) 2 = ∑ n ⩾ 2 x n 2 n F(x)=\sum_{n\geqslant 2}\frac{n!(n{-}1)!}{2}\cdot\frac{x^n}{(n!)^2}=\sum_{n\geqslant 2}\frac{x^n}{2n} F(x)=n22n!(n1)!(n!)2xn=n22nxn,则只需求出
G ( x ) = exp ⁡ [ F ( x ) ] G(x)=\exp[F(x)] G(x)=exp[F(x)]

注意这里的 F ( x ) F(x) F(x) 不是常见的指数型生成函数的形式;因为它的组合数系数实际上是 ( n x ) 2 {n\choose x}^2 (xn)2,所以阶乘需平方。

这是可以求解的。只需注意到
F ′ ( x ) = ∑ n ⩾ 2 x n − 1 2 = x 2 − 2 x F'(x)=\sum_{n\geqslant 2}\frac{x^{n-1}}{2}=\frac{x}{2-2x} F(x)=n22xn1=22xx

而后有
G ′ ( x ) = G ( x ) F ′ ( x ) ⇒ ( 2 − 2 x ) ⋅ G ′ ( x ) = x G ( x ) G'(x)=G(x)F'(x)\Rightarrow(2-2x)\cdot G'(x)=xG(x) G(x)=G(x)F(x)(22x)G(x)=xG(x)

G ( x ) = ∑ n ⩾ 0 f n x n G(x)=\sum_{n\geqslant 0}f_nx^n G(x)=n0fnxn,对比系数有
2 ( n + 1 ) f n + 1 − 2 n f n = f n − 1 2(n{+}1)f_{n+1}-2nf_n=f_{n-1} 2(n+1)fn+12nfn=fn1

整理后可以 O ( n ) \mathcal O(n) O(n) 递推。

代码

此处给出 思路壹 的代码。

#include <cstdio>
const int mod = 998244353;
const int MAXN = 10000005;
int n, inv[MAXN];
int main () {
	scanf("%d", &n);
	inv[0] = inv[1] = 1;
	for(int i = 2; i <= n; ++i) // 逆元
		inv[i] = 1ll * (mod - mod/i) * inv[mod%i] % mod;
	int fac = 1, sumF = 1, F, ans = 0, lstF = 0;
	// lstF = F_{i-1}, F = F_{i}, sumF = \sum_{i=0}^{n-2} F_i
	for(int i = 2; i <= n; ++i) {
		fac = 1ll * fac * i % mod; // fac = i!
		F = 1ll * sumF * inv[i] % mod * inv[2] % mod;
		ans = (ans + 1ll * F * fac % mod * fac % mod) % mod;
		sumF = (sumF + lstF) % mod;
		lstF = F;// F_{i-1}
	}
	printf("%d\n", ans); // ans = \sum_{i=1}^{n} f_i
}

代码源自 Ark \textsf{Ark} Ark 。这个链接只是个人主页罢了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值