kangaroo - ShinriiTin's Blog - 博主是sb
loneliness
Invatation

kangaroo

ShinriiTin posted @ 2015年6月17日 18:21 in 未分类 with tags DP 某不科学的三千元系列 , 681 阅读

题意:

有n(n<=300)只袋鼠,袋鼠i的体积为ai,口袋大小为bi(ai>bi)。

把袋鼠i放入袋鼠j的口袋里。

要求此时袋鼠i和j的口袋里没有袋鼠,且袋鼠i,j不在其它袋鼠口袋里。

不断操作直到不能操作为止,有多少种不同的终止状态,对109+7取模。

 

分析:

考虑一种合法的终止状态。

一定存在一只袋鼠,比它小的袋鼠都被装了,能装它的袋鼠都装了其它袋鼠。

先将a和b分别排序。

然后枚举这只倒霉的袋鼠i,dp算出方案数。

将a和b都按是否大于ai分成左右两边。

用f[i][j]表示a中左边前i个与b中左边匹配j对的方案数。

用g[i][j]表示b中右边前i个与a中右边匹配j对的方案数。

枚举a中左边与b中右边匹配的对数k,则这k对有k!种匹配方法。

再乘上ab两边分别匹配的方案数,就是所有的方案数。

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>inline void Scan(Q&x){
	char c; while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

#define rep(i,a,b) for(int i=a;i<b;++i)
#define dat(i,a,b) for(int i=a;i>b;--i)

const int MAXN=305;
const int Mod=1e9+7;

int n,ans;

int fac[MAXN];

int f[MAXN][MAXN],g[MAXN][MAXN];

int a[MAXN],b[MAXN];

inline void Init(){
	Scan(n);
	rep(i,1,n+1){
		Scan(a[i]),Scan(b[i]);
	}
	sort(a+1,a+1+n);
	sort(b+1,b+1+n);
	fac[0]=1;
	rep(i,1,n+1)
		fac[i]=1ll*fac[i-1]*i%Mod;
}

inline void Solve(){
	rep(wuke,1,n+1){
		memset(f,0,sizeof(f));
		memset(g,0,sizeof(g));
		int r=upper_bound(b+1,b+n+1,a[wuke])-b;
		f[0][0]=1;
		rep(i,1,r)
			rep(j,0,i+1){
				f[i][j]=f[i-1][j];
				int x=lower_bound(a+1,a+wuke,b[i])-a-1;
				if(j&&x-j+1>0){
					f[i][j]=(f[i][j]+1ll*f[i-1][j-1]*(x-j+1)%Mod)%Mod;
				}
			}
		g[n+1][0]=1;
		dat(i,n,wuke)
			rep(j,0,n-i+2){
				g[i][j]=g[i+1][j];
				int x=n-(upper_bound(b+r,b+n+1,a[i])-b)+1;
				if(j&&x-j+1>0){
					g[i][j]=(g[i][j]+1ll*g[i+1][j-1]*(x-j+1)%Mod)%Mod;
				}
			}
		int s=min(wuke-1,n-r+1);
		rep(i,0,s+1){
			ans=(ans+1ll*f[r-1][wuke-1-i]*g[wuke+1][n-r+1-i]%Mod*fac[i]%Mod)%Mod;
		}
	}
	printf("%d\n",ans);
}

int main(){
	freopen("kangaroo.in","r",stdin);
	freopen("kangaroo.out","w",stdout);
	Init(); Solve(); return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter