简化题意:
两个数列 \(\{a_n\}\),\(\{b_n\}\),求 \(a_i>b_i\) 的组数恰好比 \(b_i>a_i\) 的组数多 \(k\) 组的情况个数。
可以转化一下题目所求,也是为了方便:
令 \(k=\frac{n+k}{2}\),即有恰好 \(k\) 组糖果比药片大(\(a_i>b_i\))。
显然要将 \(a_i,b_i\) 从小到大排序。
考虑 \(a_i\) 造成的影响:
所以,我们 \(Dp\) 时先考虑第一种的 \(a_i\) ,第二种的最后统一分配。
设 \(g_{i,j}\) 表示前 \(i\) 个 \(a\),有 \(j\) 个第一种的方案数。
状态转移方程为:
\[
g_{i,j}=g_{i-1,j}+(r_i-(j-1))g_{i-1,j-1}(r_i表示b中小于a_i的个数)
\]
然后,我们可以令
\[
f_i=(n-i)!g_{n,i}
\]
也就是把 \(n-i\) 个没有匹配的任意分配,得到至少 \(i\) 个的答案 \(f_i\)。
那么恰好 \(i\) 个的答案可以从大往小递推得到:
\[
ans_i=f_i-\sum^{n}_{j=i+1}C^i_jans_j
\]
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=2110,mod=1e9+9;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++='\n';
}
}
using IO::read;
using IO::write;
inline ll Quick_power(ll a,ll b)
{
ll ans=1;
while (b)
{
if (b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll fac[maxn],inv[maxn];
inline ll C(int n,int m)
{
if (m==-1) return n==-1;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int a[maxn],b[maxn],r[maxn];
ll g[maxn][maxn],f[maxn],ans[maxn];
int main()
{
int n,K;read(n);read(K);
fac[0]=1;
for (int i=1; i<=maxn-1; ++i) fac[i]=fac[i-1]*i%mod;
inv[maxn-1]=Quick_power(fac[maxn-1],mod-2);
for (int i=maxn-2; i>=0; --i) inv[i]=inv[i+1]*(i+1)%mod;
if ((n+K)&1) return puts("0"),0;
K=(n+K)>>1;
for (int i=1; i<=n; ++i) read(a[i]);
for (int i=1; i<=n; ++i) read(b[i]);
std::sort(a+1,a+n+1);
std::sort(b+1,b+n+1);
for (int i=1, c=0; i<=n; ++i)
{
while (c<n && b[c+1]<a[i]) ++c;
r[i]=c;
}
g[0][0]=1;
for (int i=1; i<=n; ++i)
for (int j=0; j<=i; ++j) g[i][j]=(g[i-1][j]+(j ? 1ll*(r[i]-j+1)*g[i-1][j-1]%mod : 0ll))%mod;
for (int i=0; i<=n; ++i) f[i]=g[n][i]*fac[n-i]%mod;
for (int i=n; i>=K; --i)
{
ans[i]=f[i];
for (int j=i+1; j<=n; ++j) ans[i]=(ans[i]-ans[j]*C(j,i)%mod+mod)%mod;
}
write(ans[K]);
IO::flush();
return 0;
}
原文:https://www.cnblogs.com/G-hsm/p/11374121.html