矩阵(递推)
标题挺短啊,有点不适应。
题面
有一个 n × n \tt n\times n n×n 的 01 \tt01 01 矩阵,当它每一行、每一列都恰好有两个位置是 1 \tt1 1 的时候,称为配对矩阵。
请问从 1 × 1 \tt1\times1 1×1 到 n × n \tt n\times n n×n 的所有 01 \tt01 01 矩阵中有多少矩阵为配对矩阵。
设
f
(
i
)
\tt f(i)
f(i) 表示
i
×
i
\tt i\times i
i×i 的配对矩阵的个数,即询问:
∑
i
=
1
n
f
(
i
)
\tt\sum_{i=1}^{n} f(i)
i=1∑nf(i)
答案对 998244353 \tt998244353 998244353 取模, 1 ≤ n ≤ 1 e 7 \tt1\leq n\leq1e7 1≤n≤1e7.
题解
如果,我们把矩阵第 i i i 行第 j j j 列的元素为 1 ,看作是:在第 i i i 行和第 j j j 列之间连一条边,那么,就是这么一个二分图:两边各有 n n n 个点,每个行的结点的度数是 2,列的结点的度数也是 2,整张图形成若干个四元以上的环,每个环一半的点是行结点。
我们不妨从行结点的角度考虑问题。若我们钦定一共
k
k
k 个环,每个环的行结点数为
a
1
,
a
2
,
a
3
,
.
.
.
,
a
k
(
∑
a
i
=
n
)
a_1,a_2,a_3,...,a_k~(\sum a_i=n)
a1,a2,a3,...,ak (∑ai=n) ,那么把
n
n
n 个行结点放入这些环中,初步方案数为
n
!
∏
(
a
i
!
)
\frac{n!}{\prod (a_i!)}
∏(ai!)n! ,再在环内部进行排列,进一步的方案数为
n
!
∏
(
a
i
!
)
⋅
∏
(
a
i
!
)
=
n
!
\frac{n!}{\prod (a_i!)}\cdot \prod (a_i!)=n!
∏(ai!)n!⋅∏(ai!)=n!
(赞美太阳) 这时候把列结点塞进去、塞进每个环内行结点之间的空隙里,方案数变为
n
!
⋅
n
!
=
(
n
!
)
2
n!\cdot n!=(n!)^2
n!⋅n!=(n!)2
考虑旋转同构和翻转同构,再考虑到环与环之间是无序的,除去标号影响,方案数最终为
(
n
!
)
2
k
!
⋅
∏
2
a
i
\frac{(n!)^2}{k!\cdot\prod 2a_i}
k!⋅∏2ai(n!)2
也就是说
f
(
0
)
=
1
,
f
(
n
)
=
∑
k
,
a
(
n
!
)
2
k
!
⋅
∏
2
a
i
(1)
f(0)=1~,~f(n)=\sum_{k,a}\frac{(n!)^2}{k!\cdot\prod 2a_i}\tag{1}
f(0)=1 , f(n)=k,a∑k!⋅∏2ai(n!)2(1)
好,现在的问题是要枚举 a a a 序列。每个 f ( i ) f(i) f(i) 都枚举整个序列是不现实的,我们可以考虑从前面的状态转移过来。
注意到一点,我们在一个方案中挖去一个环后,把剩下的点按顺序重新标号,它又是一个完整的方案,只不过 n n n 要变小。
那么我们不妨就枚举第一行代表的结点所在的环,把这个环挖去后的状态,当然就是一种前驱状态了。主要枚举该环的大小(环中行结点的个数),然后把环排列、列结点、翻转重构等再次考虑进去:
f
(
i
)
=
∑
j
=
2
i
f
(
i
−
j
)
⋅
(
i
−
1
)
!
(
i
−
j
)
!
⋅
i
!
(
i
−
j
)
!
⋅
1
2
f(i)=\sum_{j=2}^{i}f(i-j)\cdot\frac{(i-1)!}{(i-j)!}\cdot\frac{i!}{(i-j)!}\cdot \frac{1}{2}
f(i)=j=2∑if(i−j)⋅(i−j)!(i−1)!⋅(i−j)!i!⋅21
我们把两边同除一个
(
i
!
)
2
(i!)^2
(i!)2 ,会惊奇地发现:
f
(
i
)
(
i
!
)
2
=
∑
j
=
2
i
f
(
i
−
j
)
(
(
i
−
1
)
!
)
2
⋅
1
2
i
\frac{f(i)}{(i!)^2}=\sum_{j=2}^{i}\frac{f(i-j)}{((i-1)!)^2}\cdot\frac{1}{2i}
(i!)2f(i)=j=2∑i((i−1)!)2f(i−j)⋅2i1
或许不那么惊奇,但是我们可以令
d
p
(
i
)
=
f
(
i
)
(
i
!
)
2
dp(i)=\cfrac{f(i)}{(i!)^2}
dp(i)=(i!)2f(i) ,再转变枚举顺序试试:
d
p
(
i
)
=
(
∑
j
=
0
i
−
2
d
p
(
j
)
)
⋅
1
2
i
(2)
dp(i)=\bigg(\sum_{j=0}^{i-2}dp(j)\bigg)\cdot\frac{1}{2i}\tag{2}
dp(i)=(j=0∑i−2dp(j))⋅2i1(2)
顿时变得可做了! ( 2 ) (2) (2) 式明显可以一边计算一边处理前缀和,然后就达到 O ( n ) O(n) O(n) 。
那么,为什么前面还要推 ( 1 ) (1) (1) 式呢?……
练练手呗, 前面的
(
1
)
(1)
(1) 式给了我们推导
(
2
)
(2)
(2) 式的思路,不然的话,后面的推理会变得没来由。
CODE
如果不往生成函数方面想的话,并不难。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 10000005
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
int inv[MAXN];
int as[MAXN];
int main() {
freopen("matrix.in","r",stdin); // or "rune.in" ?
freopen("matrix.out","w",stdout);
// F[i]/(i!)^2 = \sum_{j=1}^{i-1} F[i-j-1]/((i-j-1)!)^2 * 1/2
// DP[i] = (\sum_{j=1}^{i-1} DP[i-j-1]) * 1/2i
n = read();
inv[0] = inv[1] = 1;
for(int i = 2;i <= n;i ++) {
inv[i] = (MOD-inv[MOD%i]) *1ll* (MOD/i) % MOD;
}
as[0] = 1;
int sm = 0,ans = 0,fac = 1;
for(int i = 2;i <= n;i ++) {
fac = fac *1ll* i % MOD;
(sm += as[i-2]) %= MOD;
as[i] = sm *1ll* inv[i] % MOD *1ll* inv[2] % MOD;
(ans += as[i]*1ll*fac%MOD *1ll*fac%MOD) %= MOD;
}
printf("%d\n",ans);
return 0;
}
殊途同归
曾经有化学老师说过,不管剂量谈毒害就是耍流氓。同样的,不管实力大小,怎能谈难度?
这不, T L Y \tt TLY TLY 太阳神 不就用生成函数做出来了?
神谕:
可以令 A ( x ) = ∑ k > 1 a k ( k ! ) 2 x k = ∑ k > 1 k ! × ( k − 1 ) ! × 1 / 2 ( k ! ) 2 x k = ( ln ( 1 1 − x ) − x ) / 2 A(x)=\sum_{k>1}\frac{a_k}{(k!)^2}x^k=\sum_{k>1}\frac{k!\times(k-1)!\times1/2}{(k!)^2}x^k=(\ln(\frac{1}{1-x})-x)/2 A(x)=∑k>1(k!)2akxk=∑k>1(k!)2k!×(k−1)!×1/2xk=(ln(1−x1)−x)/2,那么关于答案 F ( x ) = ∑ k > 1 f k ( k ! ) 2 x k F(x)=\sum_{k>1}\frac{f_k}{(k!)^2}x^k F(x)=∑k>1(k!)2fkxk 有 F ( x ) = exp A ( x ) F(x)=\exp A(x) F(x)=expA(x),直接代入可得 F ( x ) = e − x / 2 1 − x F(x)=\frac{e^{-x/2}}{\sqrt{1-x}} F(x)=1−xe−x/2。
由于数据范围,而 F ( x ) F(x) F(x) 又是微分有限的(它是两个微分有限形式幂级数的乘积),尝试对其微分得 F ′ ( x ) = e − x / 2 x 2 ( 1 − x ) 3 / 2 = x 2 ( 1 − x ) F ( x ) F'(x)=\frac{e^{-x/2}x}{2(1-x)^{3/2}}=\frac{x}{2(1-x)}F(x) F′(x)=2(1−x)3/2e−x/2x=2(1−x)xF(x),于是得到 f n = 1 2 n ∑ i = 0 n − 2 f i f_n=\frac{1}{2n}\sum_{i=0}^{n-2} f_i fn=2n1∑i=0n−2fi
硬要说的话,也可以做。
T L Y \tt TLY TLY 太阳神 无所不能!