BZOJ4221 kangaroo

Problem

BZOJ

Solution

想了一个下午不会做,然后发现有这么两篇题解,感觉思路好奇妙:
claris
penth

可以这样想,把袋鼠拆成两个点,上面是体积,下面是袋子,如果袋鼠a放到袋鼠b里去,则必须满足 a x ≤ b y a_x\leq b_y axby,即相当于在二分图上从上向下连线。那么其实这个就是要求最后局面中没有连线的 min ⁡ a > max ⁡ b \min a>\max b mina>maxb

由于 a i > b i a_i>b_i ai>bi,所以可以保证自己不会连向自己,不妨对a和b分别进行排序。我们可以考虑枚举体积s和能放下它的最小袋子t,显然存在三种匹配方法:小于s和小于t的匹配,大于s的和大于t的匹配,小于s的和大于t的跨立匹配。j个跨立匹配贡献是 j ! j! j!,然后对左右分别dp匹配的方案数即可。

时间复杂度 O ( n 3 ) O(n^3) O(n3)

写得比较丑所以常数略大……penth的题解常数小很多,思路有点类似,搞个滚动数组也能把空间复杂度优化到 O ( n 2 ) O(n^2) O(n2),但是状态设得好奇妙啊_(:зゝ∠)_

Code

#include 
#include 
#include 
#define rg register
using namespace std;
typedef long long ll;
const int maxn=310,mod=1e9+7;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,ca,cb,l,r,ans,fac[maxn],a[maxn],b[maxn];
int ta[maxn],tb[maxn],f[maxn],g[maxn],dp[maxn][maxn];
inline int pls(int x,int y){return x+y>=mod?x+y-mod:x+y;}
void dp1()
{
	int p;
	memset(dp,0,sizeof(dp));
	dp[ca+1][0]=1;
	for(rg int i=ca+1;i>1;i--)
	{
		p=0;
		for(rg int j=cb;j;j--){if(ta[i-1]<tb[j]) ++p;else break;}
		for(rg int j=0;j<=ca;j++)
		{
			dp[i-1][j]=pls(dp[i-1][j],dp[i][j]);
			dp[i-1][j+1]=pls(dp[i-1][j+1],(ll)dp[i][j]*(p-j)%mod);
		}
	}
	for(rg int i=0;i<=ca;i++) f[i]=dp[1][i];
}
void dp2()
{
	int p;
	memset(dp,0,sizeof(dp));
	dp[0][0]=1;
	for(rg int i=0;i<cb;i++)
	{
		p=0;
		for(rg int j=1;j<=ca;j++){if(ta[j]<tb[i+1]) ++p;else break;}
		for(rg int j=0;j<=cb;j++)
		{
			dp[i+1][j]=pls(dp[i+1][j],dp[i][j]);
			dp[i+1][j+1]=pls(dp[i+1][j+1],(ll)dp[i][j]*(p-j)%mod);
		}
	}
	for(rg int i=0;i<=cb;i++) g[i]=dp[cb][i];
}
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	read(n);fac[0]=1;
	for(rg int i=1;i<=n;i++){read(a[i]);read(b[i]);fac[i]=(ll)fac[i-1]*i%mod;}
	sort(a+1,a+n+1);sort(b+1,b+n+1);
	for(rg int i=1;i<=n;i++)
	{
		ca=cb=0;
		for(rg int j=1;j<i;j++) ta[++ca]=a[j];
		for(rg int j=1;b[j]<=a[i]&&j<=n;j++) tb[++cb]=b[j];
		dp1();l=ca;
		ca=cb=0;
		for(rg int j=i+1;j<=n;j++) ta[++ca]=a[j];
		for(rg int j=1;j<=n;j++) if(b[j]>a[i]) tb[++cb]=b[j];
		dp2();r=cb;
		for(rg int j=0;j<=l&&j<=r;j++)
		  ans=pls(ans,(ll)f[l-j]*g[r-j]%mod*fac[j]%mod);
	}
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(=====动态规划=====,好题集,BZOJ)