【洛谷P4859】已经没有什么好害怕的了
题目
题目链接:https://www.luogu.com.cn/problem/P4859
已经使 Madoka 有签订契约,和自己一起战斗的想法后,Mami 忽然感到自己不再是孤单一人了呢。
于是,之前的谨慎的战斗作风也消失了,在对 Charlotte 的傀儡使用终曲——Tiro Finale 后,Mami 面临着即将被 Charlotte 的本体吃掉的局面。
这时,已经多次面对过 Charlotte 的 Homura 告诉了学 OI 的你这样一个性质:Charlotte 的结界中有两种具有能量的元素,一种是“糖果”,另一种是“药片”,各有 \(n\) 个。在 Charlotte 发动进攻前,“糖果”和“药片”会两两配对,若恰好糖果比药片能量大的组数比“药片”比“糖果”能量大的组数多 \(k\) 组,则在这种局面下,Charlotte 的攻击会丟失,从而 Mami 仍有消灭 Charlotte 的可能。
你必须根据 Homura 告诉你的“糖果”和“药片”的能量的信息迅速告诉 Homura 这种情况的个数.
\(n,k\leq 2000\)。
思路
先把 \(a,b\) 从小到大排序,记 \(\mathrm{last}_i\) 表示小于 \(a_i\) 中 \(b_j\) 最大值的下标。
同时不难发现,\(a>b\) 比 \(a<b\) 多恰好 \(k\) 组等价于 \(a>b\) 的为 \(\frac{n-k}{2}+k\) 组。下面令 \(k\gets \frac{n-k}{2}+k\)。
我们先只考虑选择 \(a>b\) 的,不管其他如何匹配。设 \(f_{i,j}\) 表示 \(a\) 的前 \(i\) 项中,匹配了 \(j\) 组 \(a>b\) 的情况的方案数。
因为我们不考虑除 \(a>b\) 以外的匹配,那么有
我们再设 \(g_i\) 表示至少有 \(i\) 组 \(a>b\) 的匹配的方案数。那么有
因为剩余 \(n-i\) 组可以两两匹配。
但是显然 \(g\) 会计算重复,不可以直接用 \(g_k-g_{k+1}\)。
我们设 \(h_i\) 表示恰好有 \(i\) 组 \(a>b\) 的方案数。
根据二项式反演
直接求出 \(h_k\) 即可。时间复杂度 \(O(n^2)\)。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2010,MOD=1e9+9;
int n,m,a[N],b[N],last[N];
ll ans,f[N][N],g[N],fac[N],inv[N];
ll fpow(ll x,ll k)
{
ll ans=1;
for (;k;k>>=1,x=x*x%MOD)
if (k&1) ans=ans*x%MOD;
return ans;
}
ll C(int n,int m)
{
return fac[n]*fpow(fac[m],MOD-2)%MOD*fpow(fac[n-m],MOD-2)%MOD;
}
int main()
{
scanf("%d%d",&n,&m);
if ((n-m)&1) return printf("0"),0;
m=(n-m)/2+m;
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<=n;i++) scanf("%d",&b[i]);
sort(a+1,a+1+n); sort(b+1,b+1+n);
fac[0]=f[0][0]=1;
for (int i=1,j=1;i<=n;i++)
{
while (j<=n && b[j]<a[i]) j++;
last[i]=j-1;
fac[i]=fac[i-1]*i%MOD;
f[i][0]=1;
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
f[i][j]=(f[i-1][j]+f[i-1][j-1]*max(0,last[i]-j+1))%MOD;
for (int i=0;i<=n;i++)
g[i]=f[n][i]*fac[n-i]%MOD;
for (int i=m;i<=n;i++)
ans=(ans+C(i,m)*fpow(-1,i-m)*g[i])%MOD;
printf("%lld",(ans%MOD+MOD)%MOD);
return 0;
}