FJOI2017 矩阵填数

题目

给定一个 \(h\times w\) 的矩阵,每个格子中将填入 \(1\)\(m\) 中的某个整数。
一个合法的填数方案须满足 \(n\) 条限制,每条限制形如“以 \((x_1,y_1)\) 为左上角,\((x_2,y_2)\) 为右下角的子矩阵中,最大值必须为 \(v\)”。
求填数方案数,对大质数取模。

把这 \(n\) 条限制按照 \(v\) 从小到大排序。

这样,就可以对每个 \(x\) 求出最小限制为 \(x\) 的区域的答案,最后处理没被限制的区域(这显然是 \(m^{S_R}\)\(S_R\) 没被限制的区域的面积)。

答案就是把这些东西全部乘起来。

接下来考虑对于每个 \(x\) 求出最小限制为 \(x\) 的区域的答案。

\(A\) 为所有 \(v\) 值等于 \(x\) 的限制构成的集合。我们要满足 \(A\) 中所有限制,并不好算,考虑容斥。

改为对 \(A\) 的每个子集 \(B\),求强制让其不满足的方案数,大概是 \((x-1)^{S_B}x^{S_{A-B}}\) ,其中 \(S_A\) 为集合 \(A\) 中所有子矩阵的并的面积去掉其中有更小限制的面积。然后加加减减就行。

发现我们还要求区域面积,当然可以离散化坐标值然后随便搞,但那个细节巨多。考虑更好写的方法:继续容斥。

我们发现本题中所有的面积都可以转为矩形的交和并。

发现矩形交是好求的,而并的就等于其子集的交加加减减,然后就求完了。枚举子集的子集是 \(O(3^n)\) 的。

每组数据的复杂度为 \(O(3^n+2^n\log(hw))\)\(\log\) 来自快速幂。(当然可以 FMT 把 \(3^n\) 优化掉,优化到 \(O(2^nn+2^n\log(hw))\),但没有必要)。

#include<cstdio>
#include<algorithm>
typedef long long ll;
const int N=10,M=1e9+7;
inline int Pow(int a,int m){int s=1;for(;m;m>>=1)m&1?s=(ll)s*a%M:0,a=(ll)a*a%M;return s;}
int x[N],y[N],xx[N],yy[N],mx[N],t[N],n,m,h,w,cnt[1<<N],ans,tmp;ll cup[1<<N],cap[1<<N];
bool Cmp(const int&i,const int&j){return mx[i]<mx[j];}
int main(){
    int a,b,aa,bb,U;
	for(int I=0;I<(1<<N);I++)cnt[I]=cnt[I>>1]+(I&1);
	int T;scanf("%d",&T);for(;T--;){
	scanf("%d%d%d%d",&h,&w,&m,&n);
	for(int i=0;i<n;i++)scanf("%d%d%d%d%d",x+i,y+i,xx+i,yy+i,mx+i),t[i]=i;
	std::sort(t,t+n,Cmp);
	for(int I=0;I<(1<<n);I++){
	  a=b=0,aa=h,bb=w;
	  for(int i=0;i<n;i++)if(I&1<<i){
		a=std::max(a,x[i]);
		b=std::max(b,y[i]);
		aa=std::min(aa,xx[i]);
		bb=std::min(bb,yy[i]);
	  }
	  cap[I]=a>aa||b>bb?0:(ll)(aa-a+1)*(bb-b+1);
	}
	for(int I=0;I<(1<<n);I++){
	  cup[I]=0;
	  for(int J=I;J;J=I&J-1)
		cup[I]=(cup[I]+cap[J]*(cnt[J]&1?1:-1));
	}
	ans=Pow(m,h*w-cup[(1<<n)-1]);
	U=0;
	for(int l=0,r=0,I;r<n;r++)if(r+1==n||mx[t[r]]!=mx[t[r+1]]){
	  I=0;
	  for(int i=l;i<=r;i++)I|=1<<t[i];
	  tmp=Pow(mx[t[r]],cup[I|U]-cup[U]);
	  for(int J=I;J;J=I&J-1)
		tmp=(tmp+(ll)Pow(mx[t[r]]-1,cup[J|U]-cup[U])*Pow(mx[t[r]],cup[I|U]-cup[J|U])%M*(cnt[J]&1?-1:1)+M)%M;
	  ans=(ll)ans*tmp%M;
	  U|=I,l=r+1;
	}
	printf("%d\n",ans);
	}return 0;
}

posted on 2020-02-20 03:27  Dreamunk  阅读(170)  评论(0编辑  收藏  举报

导航