• 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
    ",(ans+P)%P);
        }
        return 0;
    }
  • 相关阅读:
    《Java程序设计》 第一周学习任务(2)
    《Java程序设计》 第一周学习任务(1)
    Git 提示fatal: remote origin already exists 解决办法
    写给小白的酸酸乳使用方法
    美國Tarrant County College
    硬盘数据恢复工具终身版
    安卓手机系统安装虚拟机
    linux网络基础
    Linux基础命令:read
    Linux shell基础
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7501611.html
Copyright © 2020-2023  润新知