bzoj5010: [Fjoi2017]矩阵填数

Posted ccz181078

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj5010: [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 后的值。
 
对限制条件容斥,转为每个子矩阵内不超过某个数,由于不同的坐标很少,对坐标离散化后可以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]矩阵填数的主要内容,如果未能解决你的问题,请参考以下文章

bzoj5010:[FJOI2017]矩阵填数

BZOJ5010: [Fjoi2017]矩阵填数

FJOI2017 矩阵填数

P3813 [FJOI2017]矩阵填数

bzoj1002: [FJOI2007]轮状病毒(基尔霍夫矩阵)

[BZOJ1002] [FJOI2007] 轮状病毒 (基尔霍夫矩阵)