「USACO 2020.12 Platinum」Sleeping Cows

「USACO 2020.12 Platinum」Sleeping Cows

写容斥就输了。。

为每个牛棚考虑牛,从大到小,考虑每一个牛棚是否匹配

(dp_{i,j,f})表示后(i)个牛棚中有(j)个钦定要匹配但是还未匹配的牛棚,(f=0/1)表示是否存在一个牛棚未选

每次移动(i),会有一部分牛不能继续匹配

如果(f=1),那么这部分牛必须被全部后面的(j)个牛棚中某一些匹配,否则不合法

如果(f=0),这一部分可以随便匹配一定数量的牛

用组合数维护转移权值即可


const int N=3010,P=1e9+7;

int n;
int dp[N][N][2],I[N],J[N],C[N][N];
int A[N],B[N];
void Add(int &u,int x){
	u+=x,Mod1(u);
}
ll qpow(ll x,ll k=P-2) {
	ll res=1;
	for(;k;k>>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}

int main(){
	freopen("cow.in","r",stdin),freopen("cow.out","w",stdout);
	n=rd();
	rep(i,1,n) B[i]=rd();
	rep(i,1,n) A[i]=rd();
	sort(A+1,A+n+1),sort(B+1,B+n+1);
	int p=n;
	dp[n+1][0][0]=1;
	rep(i,0,n) rep(j,C[i][0]=1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
	rep(i,J[0]=1,n) J[i]=1ll*J[i-1]*i%P;
	I[n]=qpow(J[n]);
	drep(i,n,1) I[i-1]=1ll*I[i]*i%P;
	
	drep(i,n,0) {
		int c=0;
		while(p && B[p]>A[i]) c++,p--;
		rep(j,0,n-i) {
			rep(k,0,min(j,c)) {
				int t=1ll*dp[i+1][j][0]*C[c][k]%P*C[j][k]%P*J[k]%P;
				Add(dp[i][j-k][1],t),Add(dp[i][j-k+1][0],t);
				if(k==c) {
					t=1ll*dp[i+1][j][1]*C[j][k]%P*J[k]%P;
					Add(dp[i][j-k][1],t),Add(dp[i][j-k+1][1],t);
				}
			}
		}
	}
	int ans=(dp[0][0][0]+dp[0][0][1])%P;
	printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/chasedeath/p/14428947.html