降阶公式/ARC173F
ARC173F
题意
给定 \(n,A,B\),初始有一个集合 \(S=\{1,2,\dots,A,A +1,A+2,\dots,A+B\}\)。进行如下操作 \(n-1\) 次使得剩下 \(n\) 个集合:
- 从所有集合中选择一个,记为 \(S_0\)。
- 从 \(S_0\) 中选择一个元素 \(a\) 满足 \(a\in[1,A]\),选择一个元素 \(b\) 满足 \(b\in[A+1,A+B]\)。
- 将 \(S_0\) 分裂成两个集合 \(S_1,S_2\),其中 \(a\in S_1,b\in S_2\)。
- 把 \(S_0\) 删掉,把 \(S_1,S_2\) 加入待选集合。
问有多少种本质不同操作方案,对 \(998244353\) 取模。
其中定义两种方案不同,当且仅当存在一步中 \((S_0,a,b,S_1,S_2)\) 中任意一个元素不同。
\(2\le n\le 2\times 10^5,1\le A,B\le 2\times 10^5,n\le A+B\)
Solution
倒序操作。
设最后得到的集合序列(即有标号)是 \(S_{1:n}\),\(S_i\cap [1,A]=a_i,b_i=|S_i|-a_i\)。
假设得到了这个序列怎么统计分裂方案数?把分裂看成连边,合并 \((u,v)\) 的贡献就是 \(a_ub_v+a_vb_u\)(一个左边一个右边),再求生成树的积和。容易验证,这样的计算是正确的。为了简化计算,我们认为可以节点自己连边。
使用矩阵树定理。设 \(a=(a_2,a_3,\dots a_n)^T\),\(b=(b_2,b_3,\dots b_n)^T\)。\(\det (L)=\det(\operatorname{diag}(Ab+Ba)-ab^T-ba^T)=\det(D-ab^T-ba^T)\)。
为了简化计算而非进行神秘的枚举容斥什么的,我们考虑分块矩阵的”降阶公式“:
构造 \(B=0a\),那么:
而对其施加初等变换:
设
那么:
而 \(D\) 的行列式容易计算。接下来只需计算这个二阶行列式。
而 \(D^{-1}=\operatorname{diag}(Ab+Ba)\) 的每项取倒数。
那么可以计算得到:
那么我们可以有快速求出答案的希望了。考虑一组 \(a,b\) 序列对答案的贡献:最后得到了不应该是序列,而是集合的集合;用多项式系数算即可。还需要矩阵树的系数:贡献就是:
得到答案的式子(略显抽象):
这个式子固然抽象,但是可以把求和每个拆开。在此之前,先证明引理:
设
则:
可以从模板下降幂多项式乘法那里得到。
由于篇幅原因,这里不给出全部推导,我们演示
发现 \(k\) 的具体取值是无关紧要的。那么化为:
设 \(P_1(x,y)=xy,P_2(x,y)=1,P_3(x,y)=Bx+Ay\),则 \(Q_1(x,y)=xy,Q_2(x,y)=1,Q_3(x,y)=Bx+Ay\)(一次的时候是没有变化的),那么这一部分答案就是:
其实可以把一些东西简化一下,这里就不展示了。
那么最后的答案就是
// Problem: [ARC173F] Select and Split
// Platform: Luogu
// URL: https://www.luogu.com.cn/problem/AT_arc173_f
// Memory Limit: 1 MB
// Time Limit: 2000 ms
// Author:British Union
// Long live UOB and koala
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353,maxn=4e5+5;
int fac[maxn],ifac[maxn],N=4e5,n,A,B;
int qp(int a,int b){
if(b==0)return 1;
int T=qp(a,b>>1);T=T*T%mod;
if(b&1)T=T*a%mod;
return T;
}
int C(int a,int b){
if(b>a)return 0;
// cout<<"C("<<a<<","<<b<<")="<<(fac[a]*ifac[b]%mod*ifac[a-b]%mod)<<endl;
return fac[a]*ifac[b]%mod*ifac[a-b]%mod;
}
int gete(int a,int b){
if(a<0||b<0)return 0;
return qp(n,a+b)*C(a+b,a)%mod*ifac[a+b]%mod;
}
int calc(int t,int a,int b){
if(t<0||a<0||b<0)return 0;
int res=0;
for(int i=0;i<=t;i++){
(res+=C(t,i)*gete(a-i,b-(t-i))%mod*qp(B,i)%mod*qp(A,t-i))%=mod;
}
return res;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>A>>B;
fac[0]=1;
for(int i=1;i<=N;i++)fac[i]=fac[i-1]*i%mod;
ifac[N]=qp(fac[N],mod-2);
for(int i=N-1;i>=0;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
int res=calc(n-1,A,B)-2*(n-1)%mod*calc(n-2,A-1,B-1)%mod-(n-1)*(n-2)%mod*(calc(n-3,A-2,B-1)+calc(n-3,A-1,B-2)+calc(n-3,A-1,B-1))%mod;
res=fac[A]*fac[B]%mod*qp(n,mod-2)%mod*res%mod;
res=(res%mod+mod)%mod;
cout<<res<<endl;
return 0;
}