![bzoj5010: [Fjoi2017]矩阵填数 bzoj5010: [Fjoi2017]矩阵填数](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
Description
给定一个 h*w 的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w。在这个矩阵中你需要在每
个格子中填入 1..m 中的某个数。给这个矩阵填数的时候有一些限制,给定 n 个该矩阵的子矩阵,以及该子矩阵的
最大值 v,要求你所填的方案满足该子矩阵的最大值为 v。现在,你的任务是求出有多少种填数的方案满足 n 个限
制。两种方案是不一样的当且仅当两个方案至少存在一个格子上有不同的数。由于答案可能很大,你只需要输出答
案 对 1,000,000,007 的取模即可。
Input
输入数据的第一行为一个数 T,表示数据组数。
对于每组数据,第一行为四个数 h,w,m,n。
接下来 n 行,每一行描述一个子矩阵的最大值 v。每行为五个整
数 x1,y1,x2,y2,v,表示一个左上角为(x1,y1),右下角为(x2,y2)的子矩阵的最大
值为 v ( 1≤x1≤x2≤h, 1≤y1≤y2≤w)
T≤5,1≤h,w,m≤10000,1≤v≤m,1≤n≤10
Output
对于每组数据输出一行,表示填数方案 mod 1,000,000,007 后的值。
对限制条件容斥,转为每个子矩阵内不超过某个数,由于不同的坐标很少,对坐标离散化后可以O(n^2)暴力统计。
#include<bits/stdc++.h>
typedef long long i64;
const int P=1e9+;
int T,h,w,m,n;
int xs[],ys[],xp,yp,vs[],vp,ts[];
int rc[][],mv[][],as[][];
void mins(int&a,int b){if(a>b)a=b;}
int pw(int a,int n){
int v=;
for(;n;n>>=,a=i64(a)*a%P)if(n&)v=i64(v)*a%P;
return v;
}
int main(){
for(scanf("%d",&T);T;--T){
int ans=;
scanf("%d%d%d%d",&h,&w,&m,&n);
xp=yp=vp=;
xs[xp++]=;
xs[xp++]=h+;
ys[yp++]=;
ys[yp++]=w+;
vs[vp++]=m;
for(int i=;i<n;++i){
for(int j=;j<;++j)scanf("%d",rc[i]+j);
xs[xp++]=rc[i][];
xs[xp++]=rc[i][]+;
ys[yp++]=rc[i][];
ys[yp++]=rc[i][]+;
vs[vp++]=rc[i][];
vs[vp++]=rc[i][]-;
}
std::sort(xs,xs+xp);
xp=std::unique(xs,xs+xp)-xs-;
std::sort(ys,ys+yp);
yp=std::unique(ys,ys+yp)-ys-;
std::sort(vs,vs+vp);
vp=std::unique(vs,vs+vp)-vs;
for(int i=;i<xp;++i)
for(int j=;j<yp;++j)as[i][j]=(xs[i+]-xs[i])*(ys[j+]-ys[j]);
for(int t=;t<n;++t){
rc[t][]=std::lower_bound(xs,xs+xp,rc[t][])-xs;
rc[t][]=std::lower_bound(xs,xs+xp,rc[t][]+)-xs;
rc[t][]=std::lower_bound(ys,ys+yp,rc[t][])-ys;
rc[t][]=std::lower_bound(ys,ys+yp,rc[t][]+)-ys;
rc[t][]=std::lower_bound(vs,vs+vp,rc[t][])-vs;
}
for(int S=;S<(<<n);++S){
for(int i=;i<xp;++i)
for(int j=;j<yp;++j)mv[i][j]=vp-;
int s=;
for(int t=;t<n;++t){
int v=rc[t][];
if(S>>t&)s=-s,--v;
for(int i=rc[t][];i<rc[t][];++i)
for(int j=rc[t][];j<rc[t][];++j)mins(mv[i][j],v);
}
for(int i=;i<vp;++i)ts[i]=;
for(int i=;i<xp;++i)
for(int j=;j<yp;++j)ts[mv[i][j]]+=as[i][j];
for(int i=;i<vp;++i)s=i64(s)*pw(vs[i],ts[i])%P;
ans=(ans+s)%P;
}
printf("%d\n",(ans+P)%P);
}
return ;
}