bzoj 5010: [Fjoi2017]矩阵填数

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 后的值。

Sample Input

2
3 3 2 2
1 1 2 2 2
2 2 3 3 1
4 4 4 4
1 1 2 3 3
2 3 4 4 2
2 1 4 3 2
1 2 3 4 4

Sample Output

28
76475
————————————————————————————
这道题是道比较复杂的容斥 就奇减偶加 QAQ 写起来一堆细节而已QAQ
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using std::sort;
using std::unique;
using std::lower_bound;
const int M=25,mod=1e9+7,N=507;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m,k,ly,cnt;
struct pos{int x1,y1,x2,y2,w;}q[M];
int xs[M],xp,ys[M],yp,vs[M],vp;
int ans[M][M],mv[M][M],h[M];
int pmod(LL a,int b){
    LL sum=1;
    while(b){
        if(b&1) sum=sum*a%mod;
        a=a*a%mod; b>>=1;
    }
    return sum;
}
void mins(int &x,int y){if(x>y) x=y;}
int main(){
    int T=read();
    while(T--){
        cnt=0; 
        xp=yp=vp=0;
        n=read(); m=read(); k=read(); ly=read();
        xs[xp++]=1; xs[xp++]=n+1;
        ys[yp++]=1; ys[yp++]=m+1;
        vs[vp++]=k;
        for(int i=0;i<ly;i++){
            q[i].x1=read(); q[i].y1=read();
            q[i].x2=read(); q[i].y2=read();
            q[i].w=read();
            xs[xp++]=q[i].x1; xs[xp++]=q[i].x2+1;
            ys[yp++]=q[i].y1; ys[yp++]=q[i].y2+1;
            vs[vp++]=q[i].w; vs[vp++]=q[i].w-1;
        }    
        sort(xs,xs+xp); xp=unique(xs,xs+xp)-xs-1;
        sort(ys,ys+yp); yp=unique(ys,ys+yp)-ys-1;
        sort(vs,vs+vp); vp=unique(vs,vs+vp)-vs;
        for(int i=0;i<xp;i++) for(int j=0;j<yp;j++) ans[i][j]=(xs[i+1]-xs[i])*(ys[j+1]-ys[j]);
        for(int i=0;i<ly;i++){
            q[i].x1=lower_bound(xs,xs+xp,q[i].x1)-xs;
            q[i].x2=lower_bound(xs,xs+xp,q[i].x2+1)-xs;
            q[i].y1=lower_bound(ys,ys+yp,q[i].y1)-ys;
            q[i].y2=lower_bound(ys,ys+yp,q[i].y2+1)-ys;
            q[i].w=lower_bound(vs,vs+vp,q[i].w)-vs;
        }
        for(int S=0;S<(1<<ly);S++){
            for(int i=0;i<xp;i++) for(int j=0;j<yp;j++) mv[i][j]=vp-1;
            int sum=1;
            for(int k=0;k<ly;k++){
                int v=q[k].w;
                if(S>>k&1) sum=-sum,--v;
                for(int i=q[k].x1;i<q[k].x2;i++)
                for(int j=q[k].y1;j<q[k].y2;j++) mins(mv[i][j],v);
            }
            for(int i=0;i<vp;i++) h[i]=0;
            for(int i=0;i<xp;i++) for(int j=0;j<yp;j++) h[mv[i][j]]+=ans[i][j];
            for(int i=0;i<vp;i++) sum=(LL)sum*pmod(vs[i],h[i])%mod;
            cnt=(LL)(cnt+sum)%mod;
        }
        printf("%d\n",(cnt+mod)%mod);
    }
    return 0;
}
View Code

 

posted @ 2017-09-12 20:36  友人Aqwq  阅读(164)  评论(0编辑  收藏  举报