题目
https://www.luogu.com.cn/problem/P4831
思路
不会有人用多项式吧(
题目转换:将 1.. m 1..m 1..m 各 2 2 2 个(表示纵坐标),填入 n n n 对无序二元组(表示行),且二元组内两数不同
令 f n , m f_{n,m} fn,m 为答案, g n , m g_{n,m} gn,m 为 1.. m 1..m 1..m 各有 2 2 2 个,放进 2 n 2n 2n 个格子的方案数。
先思考 g的计算:考虑选用了 n − i n-i n−i 对一样的数字,然后剩下的位置要从 m − n − i m-n-i m−n−i 种数字中选出 2 i 2i 2i 个单独的数字补足 2 n 2n 2n 个格子,之后就是有部分元素相同的全排列:
g n , m = ( 2 n ) ! ∑ i = 0 m i n ( n , m − n ) C m n − i C m − n + i 2 i 2 n − i g_{n,m}=(2n)!\sum_{i=0}^{min(n,m-n)}\frac{C_m^{n-i}C_{m-n+i}^{2i}}{2^{n-i}} gn,m=(2n)!i=0∑min(n,m−n)2n−iCmn−iCm−n+i2i
考虑
f
f
f 与
g
g
g 的关系:
g
g
g中“
2
n
2n
2n 个格子”等价于“
n
n
n 对有序二元组”,那么枚举有
n
n
n 对有序二元组中选
i
i
i 对填写了相同的数字,再用
m
m
m 中的
i
i
i 种数字排进他们,剩下的位置是
f
n
−
i
,
m
−
i
f_{n-i,m-i}
fn−i,m−i 的情况:
g
n
,
m
=
∑
i
=
0
n
C
n
i
A
m
i
2
n
f
n
−
i
,
m
−
i
g_{n,m}=\sum_{i=0}^{n}C_n^iA_m^i2^nf_{n-i,m-i}
gn,m=i=0∑nCniAmi2nfn−i,m−i
二项式反演一波:
f n , m = 1 2 n ∑ i = 0 n ( − 1 ) i C n i A m i g n − i , m − i f_{n,m}=\frac{1}{2^n}\sum_{i=0}^{n}(-1)^iC_n^iA_m^ig_{n-i,m-i} fn,m=2n1i=0∑n(−1)iCniAmign−i,m−i
时间复杂度 O ( n ∗ m i n ( n , m − n ) ) O(n*min(n,m-n)) O(n∗min(n,m−n))
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+77,mod=998244353;
int n,m;
ll f[2077][2077],ans,fac[N],unfac[N];
ll power(ll x,ll t)
{
ll b=1;
while(t)
{
if(t&1) b=b*x%mod; x=x*x%mod; t>>=1;
}
return b;
}
ll c(ll x)
{
return x*(x-1)/2;
}
void init(int n)
{
fac[0]=1;
for(int i=1; i<=n; i++) fac[i]=fac[i-1]*i%mod;
unfac[n]=power(fac[n],mod-2);
for(int i=n-1; i>=0; i--) unfac[i]=unfac[i+1]*(i+1)%mod;
}
ll C(ll x,ll y)
{
if(y>x) return 0;
return fac[x]*unfac[y]%mod*unfac[x-y]%mod;
}
ll A(ll x,ll y)
{
if(y>x) return 0;
return fac[x]*unfac[x-y]%mod;
}
ll G(ll n,ll m)
{
ll yjy=0;
for(int i=0; i<=min(n,m-n); i++)
{
(yjy+=C(m,n-i)*C(m-n+i,2*i)%mod*power(power(2,n-i),mod-2)%mod)%=mod;
}
return yjy*fac[2*n]%mod;
}
int main()
{
scanf("%d%d",&n,&m);
/* if(n<=2000&&m<=2000)
{
if(n==m&&m==0)
{
printf("1"); return 0;
}
f[1][0]=c(m);
for(int i=1; i<n; i++) for(int j=max(2*i-m,0); j<=i; j++) if(f[i][j])
{
(f[i+1][j+2]+=f[i][j]*c(2*i-2*j)%mod)%=mod;
(f[i+1][j+1]+=f[i][j]*(2*i-2*j)%mod*(m-2*i+j)%mod)%=mod;
(f[i+1][j]+=f[i][j]*c(m-2*i+j)%mod)%=mod;
}
for(int i=0; i<=n; i++) (ans+=f[n][i])%=mod;
printf("%lld",ans);
}
else*/
{
ll _1=-1,ans=0;
init(m*2);
for(int i=0; i<=n; i++)
{
_1=-_1;
(ans+=(_1*C(n,i)%mod*A(m,i)%mod*G(n-i,m-i)%mod+mod)%mod)%=mod;
}
printf("%lld",ans*power(power(2,n),mod-2)%mod);
}
}