做题笔记
P15864 [LBA-OI R3 D] 阵列之弈
首先肯定要拆贡献,把贡献拆到每一个mex中,考虑一个数k能成为任一子矩形mex的充要条件,发现等价于k要在[0,k-1]内所有数围成的矩形之外,这个肯定是充分的,这个矩形的mex显然是k,必要性考虑假如k在这个矩形中,那么取到[0,k-1]的同时一定会取到k。先把corner case做掉,当k=0时,除了1*1的矩阵,其他都合法,k=nm时,所有矩阵合法,那现在我们就能保证k一定在矩形中且[0,k-1]在矩形中。我们考虑k在黄色位置(x,y)的贡献,只要\([0,k-1]\)在红色部分里,那么就合法,但是会算重,只需要减掉蓝色部分就行了。
我们发现,在一个矩形里面放k个数的方案数是只跟这个矩形的面积有关,对于面积为s的矩形,设总面积S=nm,我们有\(f(s)=\binom{s}{k}k!(S-k-1)!\),这个式子不难理解。这样我们就有一个\(O(n^2m^2)\)的做法,考虑优化。我们将每一个(x,y)的所有k放在一起计算,那么对于每一块面积s,方案数就是
\[\begin{aligned}
f(s)=&\sum_{k=0}^s\binom{s}{k}k!(S-k-1)!\\
=&\sum_{k=0}^s\frac{s!(S-k-1)!}{(s-k)!}\\
=&s!\sum_{k=0}^s\frac{(S-k-1)!}{(s-k)!}\\
=&s!\sum_{k=0}^s\binom{S-k-1}{s-k}(S-s-1)!\\
=&s!(S-s-1)!\sum_{k=0}^s\binom{S-k-1}{s-k}\\
=&s!(S-s-1)!\sum_{k=0}^s\binom{S-s+k-1}{k}\\
=&s!(S-s-1)!\sum_{k=0}^s\binom{S-s+k-1}{S-s-1}\\
=&s!(S-s-1)!\binom{S}{S-s}\\
=&\frac{S!}{S-s}
\end{aligned}
\]
这样每一块面积的答案可以\(O(1)\)计算,枚举(x,y),时间复杂度就是\(O(nm)\)的。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e6+5,p=998244353;
int n,m,k,inv[N],fac[N];
constexpr void A(int &x,int y){x=(x+y)%p;}
int F(int x){return fac[k]*inv[k-x]%p;}
signed main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m,k=n*m,inv[0]=inv[1]=fac[0]=1;
if(n==1&&m==1){cout<<1;return 0;}
for(int i=2;i<=k;i++)inv[i]=inv[p%i]*(p-p/i)%p;
for(int i=1;i<=k;i++)fac[i]=fac[i-1]*i%p;
int x=0;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
A(x,F((i-1)*m)),A(x,F(n*(j-1))),A(x,F((n-i)*m)),A(x,F(n*(m-j))),
A(x,-F((i-1)*(j-1))),A(x,-F((i-1)*(m-j))),A(x,-F((n-i)*(j-1))),A(x,-F((n-i)*(m-j)));
cout<<((x+p)%p+2*fac[k]%p)%p;
}
浙公网安备 33010602011771号