应该是本人做过的第一道DP+容斥了,容斥原理博大精深啊……
原题问的是至多k对女比男高的情况,我们可以先考虑 至少 k对女比男高的情况,然后用容斥来转化。
首先,让男生女生按身高排序。
设
d[i][j]
d
[
i
]
[
j
]
为前
i
i
个女生中已经确定有个女生比对应的男生高的情况下,这
j
j
个女生的配对情况数,其它女生暂时不考虑。
则得出d[i][j]的转移方程:
其中, p p 是比第i个女生矮的男生个数。
然后,我们得出了,然而这仅仅是比它们的舞伴高的
j
j
个女生的配对情况,还有剩下对男女生没有考虑。
那么他们该怎么办呢?自由配对不就行了,情况共有
(n−j)!
(
n
−
j
)
!
种
于是我们就得到了至少i对女比男高的情况数,姑且设为
f[i]
f
[
i
]
:
然而是错的,上述表达式中,多于k对的情况中有很多是重复的,如下图:
其中红色线为原本已确定的女比男高的配对。
因此,我们不能直接通过
f[i]−f[i+1]
f
[
i
]
−
f
[
i
+
1
]
来得到恰好
i
i
对的情况,这时候又怎么办呢?如何将多于对的情况去掉?
通过观察我们可以发现,如上图,一个恰好3对的情况,对
f[2]
f
[
2
]
贡献了
C23=3
C
3
2
=
3
种重复的情况。
以此类推,我们可以发现,一个恰好
i
i
对的情况,会对贡献
Cji
C
i
j
种重复的情况,于是可以得出恰好
i
i
对的情况数
最后记住要写高精度,包括高精度加法减法,高精度乘int,高精度乘高精度,好恶心啊
具体细节见代码。
代码如下:
#include <bits/stdc++.h>
#define LL long long
#define MOD 100000000
#define N 100
using namespace std;
struct BigI
{
LL a[N<<1];
bool flag;
inline LL& operator [](int x) {return a[x];}
inline BigI(LL n=0)
{
memset(this,0,sizeof(*this));
a[0]=n;
}
BigI friend inline operator+(BigI a1,BigI a2)
{
if(a1.flag^a2.flag)
{
a2.flag^=1;
return a1-a2;
}
for(int i=0,j=0;i<N;i++)
{
a1[i]+=a2[i]+j;
j=a1[i]/MOD;
a1[i]%=MOD;
}
return a1;
}
BigI friend inline operator*(BigI a1,int n1)
{
for(LL i=0,j=0;i<N;i++)
{
a1[i]*=n1;
a1[i]+=j;
j=a1[i]/MOD;
a1[i]%=MOD;
}
return a1;
}
BigI friend inline operator*(BigI a1,BigI a2)
{
BigI a3;
a3.flag=a1.flag^a2.flag;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
a3[i+j]=a3[i+j]+a1[i]*a2[j];
}
}
for(int i=0;i<N;i++)
{
a3[i+1]+=a3[i]/MOD;
a3[i]%=MOD;
}
return a3;
}
BigI friend inline operator-(BigI a1,BigI a2)
{
BigI a3(a1);
if(a1.flag^a2.flag)
{
a2.flag^=1;
return a1+a2;
}
for(int i=0;i<N;i++)
{
a1[i]-=a2[i];
if(a1[i]<0)a1[i+1]--,a1[i]+=MOD;
}
if(a1.a[N]<0)
{
a1=a2-a3;
a1.flag^=1;
}
return a1;
}
friend void print(BigI a)
{
string str="00000000";
int i=N-1;
for(;!a[i];i--);
cout<<a[i];
for(i--;i>=0;i--)
{
str="00000000";
for(int j=7;j>=0;j--)
{
str[j]=a[i]%10+'0';
a[i]/=10;
}
cout<<str;
}
cout<<endl;
}
}d[201],fac(1),c[201][201],ans;
int n,m,b[210],g[210];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1;i<=n;i++)cin>>g[i];
sort(b+1,b+n+1);
sort(g+1,g+n+1);
d[0]=BigI(1);
for(int i=1,k=1;i<=n;i++)
{
while(b[k]<g[i]&&k<=n)k++;
for(int j=i;j;j--)
{
d[j]=d[j]+d[j-1]*max(k-j,0);
// cout<<i<<' '<<j<<" "<<d[j][0]<<endl;
}
}
for(int i=n;i>=0;i--,fac=fac*(n-i))d[i]=d[i]*fac;
c[0][0]=BigI(1);
for(int i=1;i<=n;i++)
{
c[i][0]=BigI(1);
for(int j=1;j<=i;j++)
{
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
for(int i=n;i>=0;i--)
{
for(int j=i+1;j<=n;j++)
{
d[i]=d[i]-c[j][i]*d[j];
}
if(i<=m)ans=ans+d[i];
}
print(ans);
return 0;
}