【BZOJ3622】已经没什么好害怕的了 容斥原理+dp

Description

img

Input

img

Output

img

Sample Input

4 2
5 35 15 45
40 20 10 30

Sample Output

4

HINT

img

输入的2*n个数字保证全不相同。

还有输入应该是第二行是糖果,第三行是药片

Sol

先把两个数组排序,能够把题目的分析难度降低一些。

然后我们求出\(r[i]\)表示b中小于\(a[i]\)的最靠右的位置,这样dp的时候就能够\(O(1)\)转移了。

\(f[i][j]\)表示考虑了i位,至少有j个满足a>b的方案数。

显然\(f[i][j]=f[i-1][j]+f[i-1][j-1]*max(0,r[i]-j+1)\)

这样的方案数是“至少”,我们需要求的是“恰好”,所以需要容斥一波。

\(g[i]\)表示恰好i个的方案数,那么我们的计算方法就是用全部情况减去不合法的情况。

显然全部情况是\(f[n][i]*(n-i)!\),阶乘就表示剩下的可以任意选择。

然后我们需要减去的是:\(\sum_{j=i+1}^{n}g[j]*C(j,i)\)

这个式子的意义是:对于每个恰好是j的方案的排列中,任意选择i个数字的方案数,也就是不合法的总方案数。

Code

#include <bits/stdc++.h>
using namespace std;
int n,m,a[2005],b[2005],f[2005][2005],g[2005],d[2005]={1},c[2005][2005],r[2005],P=1e9+9;
int main()
{
	scanf("%d%d",&n,&m);m=(m+n)>>1;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);sort(a+1,a+n+1);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);sort(b+1,b+n+1);
	for(int i=1,j=1;i<=n;r[i]=j-1,i++) for(;j<=n&&b[j]<a[i];j++);
	for(int i=0,j;i<=2000;i++) for(c[i][0]=1,j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%P;
	for(int i=1;i<=2000;i++) d[i]=1ll*d[i-1]*i%P;
	for(int i=0;i<=n;i++) f[i][0]=1;
	for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) f[i][j]=(f[i-1][j]+1ll*f[i-1][j-1]*max(r[i]-j+1,0)%P)%P;
	for(int i=n,j;i>=m;i--) for(g[i]=1ll*f[n][i]*d[n-i]%P,j=i+1;j<=n;j++) g[i]=(g[i]-1ll*c[j][i]*g[j]%P+P)%P;
	printf("%d\n",g[m]);
}
posted @ 2018-08-03 16:35  CK6100LGEV2  阅读(255)  评论(0编辑  收藏  举报