JZOJ3206. 【HNOI模拟题】Axonometric Projection

Description

让我们来考虑一个单位立方体建成的模型。这个建筑的底是一个n m的单位正方形网格。在每个正方形上面,堆着若干个(可能是0)个单位立方体。每个立方体属于其中一个立方体堆。

给出了一个建筑的左视图和正视图。请计算有多少种建筑,符合给出的左视图和正视图。答案可能很大,只要返回它除以10^9 + 9的余数即可。

Input

第一行是整数n。第二行描述了建筑的左视图。第i个数表示了由上往下看时第i行最高的立方体堆的高度。第三行是整数m。第四行描述了建筑的正视图。第i个数表示了由上往下看时第i列最高的立方体堆的高度。

Data Constraint

对于100%的数据,1 <= n,m <= 50,所有出现的数不超过10^4。

Solution

  • 对于一个左视图或正视图,如果将它的排列顺序调换也没有关系,所以我们可以从小到大排序。
  • 如果我们的两个数组排好了序:
    在这里插入图片描述
  • 将其排成n*m的矩阵,每个位置取最小值,我们发现这个图形变成了很多个L型(或退化的L型)。
  • 针对L型进行DP
  1. 每个L型显然是独立、互不影响的。对于每一个L型设F[i][j]表示做完了i行,其中有j列满足,然后枚举又多出来几列满足,其它的只要满足行至少有一个达到上限,剩下的随便选。
  2. 考虑容斥,枚举至少i行不满足,j列不满足。容斥系数就是
    (-1)(i+j)*dg(i,j) *(d+1)(s-g(i,j)) *C(a,i)*C(b,j)
    d表示这一个L型的限制,s表示总点数,g表示i行j列的总点数,a表示L型行的个数,b表示列的个数。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 51
#define ll long long 
#define mo 1000000009
using namespace std;

int n,m,i,j,k,x,y,u,v,g,s,d;
int a[maxn],b[maxn],map[maxn][maxn];
ll ans,f,sum,jc[maxn],ny[maxn];

int check0(int x,int y,int c){
	for(int i=y;i<=m;i++) if (map[x][i]!=c) return 0;
	return 1;
}
int check1(int x,int y,int c){
	for(int i=x;i<=n;i++) if (map[i][y]!=c) return 0;
	return 1;
}

ll ksm(ll x,ll y){
	ll s=1;
	for(;y;y/=2,x=x*x%mo) if (y&1)
		s=s*x%mo;
	return s;
}

ll C(ll n,ll m){return jc[n]*ny[n-m]%mo*ny[m]%mo;}

int main(){
	scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	scanf("%d",&m);
	for(i=1;i<=m;i++) scanf("%d",&b[i]);
	sort(a+1,a+1+n),sort(b+1,b+1+m);
	if (a[n]!=b[m]){printf("0");return 0;}
	for(i=1;i<=n;i++) for(j=1;j<=m;j++)
		map[i][j]=min(a[i],b[j]);
	jc[0]=ny[0]=1;
	for(i=1;i<=max(n,m);i++) jc[i]=jc[i-1]*i%mo,ny[i]=ny[i-1]*ksm(i,mo-2)%mo;
	ans=1;
	for(x=0,y=0;!(x>=n&&y>=m);x=u,y=v){
		d=map[x+1][y+1];
		for(u=x+1;u<=n&&check0(u,y+1,d);u++); u--;
		for(v=y+1;v<=m&&check1(x+1,v,d);v++); v--;
		s=(u-x)*(m-y)+(n-x)*(v-y)-(u-x)*(v-y),sum=0;
		for(i=0;i<=u-x;i++) for(j=0;j<=v-y;j++) {
			g=i*(m-y)+j*(n-x)-i*j;
			f=ksm(d,g)*ksm(d+1,s-g)%mo*C(u-x,i)%mo*C(v-y,j)%mo;
			if ((i+j)&1) sum=(sum-f+mo)%mo; else sum=(sum+f)%mo;
		}
		ans=ans*sum%mo;
	}
	printf("%lld",ans);
}
posted @ 2019-01-29 08:04  Deep_Thinking  阅读(175)  评论(0编辑  收藏  举报