【BZOJ3622】已經沒有什么好害怕的了 容斥+DP


 【BZOJ3622】已經沒有什么好害怕的了

Description

Input

Output

Sample Input

4 2
5 35 15 45
40 20 10 30

Sample Output

4

HINT

輸入的2*n個數字保證全不相同。

還有輸入應該是第二行是糖果,第三行是葯片

題解:好吧這題不是神題,而是套路題,容斥+DP的套路在很多題中都用到過,不過我雖然知道套路,卻被這題的第一步卡住了。

我們將兩個序列從小到大排序。

好吧這步看起來可能很水,正常人看到無序的序列都會先想到排序,然而為什么要兩個都從小到大排呢?排序的意義何在?一會講。

題中給的是(糖果>葯片)=(葯片>糖果)+k,我們只需要用一點小學數學的知識就能算出(糖果>葯片)的具體數量。下面是套路部分:我們設f[i][j]表示枚舉到前i個,(糖果>葯片)數至少為j的方案數。然后我們預處理出最大的k,滿足葯片k<糖果i,那么方程就是:

$f[i][j]=f[i-1][j]+f[i-1][j-1]*(k-j+1)$

現在知道排序的意義了吧?因為后面的i的決策區間一定包含前面的i的決策區間,所以只需要將其減去即可防止重復。

那么最后答案是什么呢?套路:ans=至少有k個的方案數-至少有k+1個的+至少有k+2個的方案數-。。。

所以答案=$\sum\limits_{j=k}^nf[n][j](-1)^{j-k}C_j^k$

P.S:這里解釋一下容斥系數是$C_j^k$的原理吧,首先我們用f[i]代表上面的f[n][i],用g[i]代表恰好有i個符合條件的方案數。根據定義有:$f[i]=\sum\limits_{j=i}^ng[i]C_j^i$。所以我們上面得到的最終式子可以轉化成:$\sum\limits_{j=k}^nf[j](-1)^{j-k}C_j^k=\sum\limits_{i=k}^ng[i]\sum\limits_{j=k}^i(-1)^{j-k}C_i^jC_j^k\\=\sum\limits_{i=k}^ng[i]\sum\limits_{j=k}^i(-1)^{j-k}C_i^kC_{i-k}^{j-k}\\=\sum\limits_{i=k}^ng[i]C_i^k\sum\limits_{j=k}^i(-1)^{j-k}C_{i-k}^{j-k}$

根據組合恆等式后面那個東西只在i=k的時候=1,其余時候=0,所以我們就得到了g[k]。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll P=1000000009;
int n,m;
ll ans;
ll f[2010][2010],c[2010][2010],jc[2010];
int a[2010],b[2010];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd(),m=rd();
	if((n^m)&1)
	{
		printf("0");
		return 0;
	}
	m=(n+m)>>1;
	int i,j,k;
	for(jc[0]=i=1;i<=n;i++)	jc[i]=jc[i-1]*i%P;
	for(i=1;i<=n;i++)	a[i]=rd();
	for(i=1;i<=n;i++)	b[i]=rd();
	for(i=0;i<=n;i++)
	{
		c[i][0]=1;
		for(j=1;j<=i;j++)	c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
	}
	sort(a+1,a+n+1),sort(b+1,b+n+1);
	f[0][0]=1;
	for(i=1;i<=n;i++)
	{
		for(k=1;k<=n&&b[k]<a[i];k++);
		k--;
		for(j=1;j<=i;j++)	f[i][j]=(f[i-1][j]+f[i-1][j-1]*max(k-j+1,0))%P;
		f[i][0]=f[i-1][0];
	}
	ll tmp=1;
	for(i=m;i<=n;i++)	f[n][i]=(f[n][i]*jc[n-i])%P,ans=(ans+tmp*f[n][i]*c[i][m]%P+P)%P,tmp=-tmp;
	printf("%lld",(ans+P)%P);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM