Problem
Solution
想了一个下午不会做,然后发现有这么两篇题解,感觉思路好奇妙:
claris
penth
可以这样想,把袋鼠拆成两个点,上面是体积,下面是袋子,如果袋鼠a放到袋鼠b里去,则必须满足 a x ≤ b y a_x\leq b_y ax≤by,即相当于在二分图上从上向下连线。那么其实这个就是要求最后局面中没有连线的 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 <algorithm>
#include <cstring>
#include <cstdio>
#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;
}