1. 程式人生 > >bzoj5010: [Fjoi2017]矩陣填數

bzoj5010: [Fjoi2017]矩陣填數

void ret 以及 clu 兩種 c++ 最大 n) type

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+7; int T,h,w,m,n; int xs[33],ys[33],xp,yp,vs[33],vp,ts[33]; int rc[33][5],mv[33][33],as[33][33]; void mins(int&a,int b){if(a>b)a=b;} int pw(int a,int n){ int v=1; for(;n;n>>=1,a=i64(a)*a%P)if(n&1)v=i64(v)*a%P; return v; } int main(){
for(scanf("%d",&T);T;--T){ int ans=0; scanf("%d%d%d%d",&h,&w,&m,&n); xp=yp=vp=0; xs[xp++]=1; xs[xp++]=h+1; ys[yp++]=1; ys[yp++]=w+1; vs[vp++]=m; for(int i=0;i<n;++i){ for(int j=0;j<5;++j)scanf("%d",rc[i]+j); xs[xp++]=rc[i][0]; xs[xp++]=rc[i][2]+1; ys[yp++]=rc[i][1]; ys[yp++]=rc[i][3]+1; vs[vp++]=rc[i][4]; vs[vp++]=rc[i][4]-1; } std::sort(xs,xs+xp); xp=std::unique(xs,xs+xp)-xs-1; std::sort(ys,ys+yp); yp=std::unique(ys,ys+yp)-ys-1; std::sort(vs,vs+vp); vp=std::unique(vs,vs+vp)-vs; for(int i=0;i<xp;++i) for(int j=0;j<yp;++j)as[i][j]=(xs[i+1]-xs[i])*(ys[j+1]-ys[j]); for(int t=0;t<n;++t){ rc[t][0]=std::lower_bound(xs,xs+xp,rc[t][0])-xs; rc[t][2]=std::lower_bound(xs,xs+xp,rc[t][2]+1)-xs; rc[t][1]=std::lower_bound(ys,ys+yp,rc[t][1])-ys; rc[t][3]=std::lower_bound(ys,ys+yp,rc[t][3]+1)-ys; rc[t][4]=std::lower_bound(vs,vs+vp,rc[t][4])-vs; } for(int S=0;S<(1<<n);++S){ for(int i=0;i<xp;++i) for(int j=0;j<yp;++j)mv[i][j]=vp-1; int s=1; for(int t=0;t<n;++t){ int v=rc[t][4]; if(S>>t&1)s=-s,--v; for(int i=rc[t][0];i<rc[t][2];++i) for(int j=rc[t][1];j<rc[t][3];++j)mins(mv[i][j],v); } for(int i=0;i<vp;++i)ts[i]=0; for(int i=0;i<xp;++i) for(int j=0;j<yp;++j)ts[mv[i][j]]+=as[i][j]; for(int i=0;i<vp;++i)s=i64(s)*pw(vs[i],ts[i])%P; ans=(ans+s)%P; } printf("%d\n",(ans+P)%P); } return 0; }

bzoj5010: [Fjoi2017]矩陣填數