正题
题目链接:https://www.luogu.com.cn/problem/P5400
题目大意
有一个n×m×ln\times m\times ln×m×l的三维网格,要在每个格子处填上一个数,要求填的数中1∼n×m×l1\sim n\times m\times l1∼n×m×l都恰好出现了一次。
一个极大值被定义为这个格子比其他与它至少有一个坐标相同的格子都大,求恰好有kkk个极大值的概率。
1≤n,m,l≤5×106,1≤k≤100,1≤T≤101\leq n,m,l\leq 5\times 10^6,1\leq k\leq 100,1\leq T\leq 101≤n,m,l≤5×106,1≤k≤100,1≤T≤10
解题思路
恰好我们很难进行计数,所以我们考虑钦定kkk个极大值,然后用二项式反演。
假设n≤m≤ln\leq m\leq ln≤m≤l,那么极大值个数不超过nnn个。
考虑怎么求钦定kkk个极大值时的方案,首先每个极大值的位置是没有关系的,因为三个坐标都肯定各不相同。
那么我们就默认第iii个最大值的位置是(i,i,i)(i,i,i)(i,i,i),且第iii个极大值ai<ai+1a_i<a_{i+1}ai<ai+1。
这样的话对于每个极大值限制的范围就是一层一层的嵌套。先考虑不在限制范围内的数,选一些填上,那么方案就是(nml(n−k)(m−k)(l−k))\binom{nml}{(n-k)(m-k)(l-k)}((n−k)(m−k)(l−k)nml),然后还要考虑在外面填的方案那么总方案就是Anml(n−k)(m−k)(l−k)A_{nml}^{(n-k)(m-k)(l-k)}Anml(n−k)(m−k)(l−k)。
然后考虑填被限制的数字的方案,从外层开始填,那么第一层就是除了(1,1,1)(1,1,1)(1,1,1)以外随便填了。
为了方便我们记Gk=(n−k)(m−k)(l−k)G_k=(n-k)(m-k)(l-k)Gk=(n−k)(m−k)(l−k)那么第一层的方案就是(G0−G1−1)!(G_0-G_{1}-1)!(G0−G1−1)!,同样推出第二层的方案(G1−G2−1)!(G_1-G_2-1)!(G1−G2−1)!,不过要把第二层的数字穿插在第一层中(除了极大值),那么就是(G1−G2−1)!×CG0−G2−1G1−G2−1(G_1-G_2-1)!\times C_{G_0-G_2-1}^{G_1-G_2-1}(G1−G2−1)!×CG0−G2−1G1−G2−1。
那么写出总答案就是
1G0!AG0Gk∏i=0k−1(Gi−Gi+1−1)!CG0−Gi+1−1Gi−Gi+1−1\frac{1}{G_0!}A_{G_0}^{G_k}\prod_{i=0}^{k-1}(G_i-G_{i+1}-1)!C_{G_0-G_{i+1}-1}^{G_i-G_{i+1}-1}G0!1AG0Gki=0∏k−1(Gi−Gi+1−1)!CG0−Gi+1−1Gi−Gi+1−1
拆分开来
1Gk!∏i=0k−1(Gi−Gi+1−1)!(G0−Gi+1−1)!(Gi−Gi+1−1)!(G0−Gi)!\frac{1}{G_k!}\prod_{i=0}^{k-1}(G_i-G_{i+1}-1)!\frac{(G_0-G_{i+1}-1)!}{(G_i-G_{i+1}-1)!(G_0-G_i)!}Gk!1i=0∏k−1(Gi−Gi+1−1)!(Gi−Gi+1−1)!(G0−Gi)!(G0−Gi+1−1)!
1Gk!∏i=0k−1(G0−Gi+1−1)!(G0−Gi)!\frac{1}{G_k!}\prod_{i=0}^{k-1}\frac{(G_0-G_{i+1}-1)!}{(G_0-G_i)!}Gk!1i=0∏k−1(G0−Gi)!(G0−Gi+1−1)!
我们会发现我们能用前面的1Gk!\frac{1}{G_k!}Gk!1的某些部分去补足后面G0−GiG_0-G_{i}G0−Gi和G0−Gi+1−1G_0-G_{i+1}-1G0−Gi+1−1的差,但是因为会有重复部分,我们只提出[G0−Gi+1,G0−Gi+1][G_0-G_i+1,G_0-G_{i+1}][G0−Gi+1,G0−Gi+1]这一部分就有
∏i=1k1G0−Gi∏i=0k−1Gi\prod_{i=1}^{k}\frac{1}{G_0-G_i}\prod_{i=0}^{k-1}G_ii=1∏kG0−Gi1i=0∏k−1Gi
这样我们用O(n)O(n)O(n)预处理逆元的方法就可以做到O(Tn)O(Tn)O(Tn)了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=5e6+10,P=998244353;
ll T,n,m,l,k,fac[N],fnv[N];
ll g[N],G[N],f[N],inv[N],ans;
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans;
}
ll C(ll n,ll m)
{return fac[n]*fnv[m]%P*fnv[n-m]%P;}
signed main()
{fnv[0]=fnv[1]=fac[0]=1;for(ll i=2;i<N;i++)fnv[i]=P-fnv[P%i]*(P/i)%P;for(ll i=1;i<N;i++)fac[i]=fac[i-1]*i%P,fnv[i]=fnv[i-1]*fnv[i]%P;scanf("%lld",&T);while(T--){scanf("%lld%lld%lld%lld",&n,&m,&l,&k);ll S=n*m%P*l%P;g[0]=S;ans=0;if(m<n)swap(n,m);if(l<n)swap(n,l);inv[0]=1;if(k>n){puts("0");continue;}for(ll i=1;i<=n;i++){G[i]=(S-(n-i)*(m-i)%P*(l-i)%P+P)%P;g[i]=(n-i)*(m-i)%P*(l-i)%P;inv[i]=inv[i-1]*G[i]%P;}inv[n]=power(inv[n],P-2);for(ll i=n;i>=1;i--)inv[i-1]=inv[i]*G[i]%P;f[0]=1;for(ll i=1;i<=n;i++)f[i]=f[i-1]*g[i-1]%P;for(ll i=0;i<=n;i++)f[i]=f[i]*inv[i]%P;for(ll i=k;i<=n;i++)(ans+=C(i,k)*f[i]%P*(((i-k)&1)?(P-1):1)%P)%=P;printf("%lld\n",ans);}return 0;
}