矩阵填数

Time Limit: 10 Sec  Memory Limit: 128 MB
[Submit][Status][Discuss]

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 。

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

HINT

  T≤5, 1≤h,w,m≤10000, 1≤v≤m, 1≤n≤10

Main idea

  给定一个矩阵,要求若干个子矩阵中最大值必须为Val,询问方案数。

Solution

  显然我们想到了状压DP,令 f[i][j] 表示做到了第i个块状态为j的方案,j表示哪些块满足限制

  由于子矩阵限制可能会重叠,所以我们先预处理,将矩阵分为若干个小块每个小块中仅有一个限制条件(显然就是所有覆盖条件中最小的一个)。

  然后我们记 Val 表示这一块里面的限制值Num 表示这一块的个数,然后我们再记个 op 表示覆盖哪些块的限制值为Val

  之后用状压DP,考虑第 i 块是否取限制值则方案数为 (Val - 1) ^ Num不取则方案数为 Val ^ Num - (Val - 1) ^ Num

  当取限制值时,把对应方案数转移到 f[i + 1][j | op[i + 1]]否则转移到 f[i + 1][j]。最后答案就是 f[cnt][all] 了。

Code

 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<map>
using namespace std;
typedef long long s64; const int ONE=;
const int MOD=1e9+;
const int INF=; int T;
int h,w,m,n,all;
int qx[ONE],x_num,qy[ONE],y_num;
int Num[ONE],Val[ONE],op[ONE],cnt;
int f[ONE][]; struct power
{
int x1,y1;
int x2,y2;
int val;
}a[ONE]; int get()
{
int res=,Q=;char c;
while( (c=getchar())< || c> )
if(c=='-')Q=-;
res=c-;
while( (c=getchar())>= && c<= )
res=res*+c-;
return res*Q;
} s64 Quick(s64 a,int b)
{
s64 res=;
while(b)
{
if(b&) res=res*a%MOD;
a=(s64)a*a%MOD;
b>>=;
}
return res;
} void Deal_first()
{
sort(qx+,qx+x_num+); x_num=unique(qx+,qx+x_num+)-qx-;
sort(qy+,qy+y_num+); y_num=unique(qy+,qy+y_num+)-qy-; cnt=;
for(int i=;i<=x_num;i++)
for(int j=;j<=y_num;j++)
{
int lenx=qx[i]-qx[i-];
int leny=qy[j]-qy[j-];
Num[++cnt]=lenx*leny; Val[cnt]=m; op[cnt]=; for(int l=;l<=n;l++)
if(a[l].x1<=qx[i-] && qx[i]<=a[l].x2 && a[l].y1<=qy[j-] && qy[j]<=a[l].y2)
Val[cnt]=min(Val[cnt],a[l].val); for(int l=;l<=n;l++)
if(a[l].val==Val[cnt])
if(a[l].x1<=qx[i-] && qx[i]<=a[l].x2 && a[l].y1<=qy[j-] && qy[j]<=a[l].y2)
op[cnt]|=(<<l-);
}
} void Deal()
{
memset(f,,sizeof(f));
f[][]=; for(int i=;i<=cnt-;i++)
for(int opt=;opt<=all;opt++)
if(f[i][opt])
{
f[i+][opt|op[i+]] = (f[i+][opt|op[i+]] + (s64)f[i][opt]*(s64)(Quick(Val[i+],Num[i+]) - Quick(Val[i+]-,Num[i+]) + MOD) % MOD) % MOD;
f[i+][opt] = (f[i+][opt] + (s64)f[i][opt]*Quick(Val[i+]-,Num[i+]) % MOD) % MOD; }
} int main()
{
T=get();
while(T--)
{
h=get(); w=get(); m=get(); n=get(); all=(<<n)-;
x_num=y_num=;
for(int i=;i<=n;i++)
{
a[i].x1=get(); a[i].y1=get(); a[i].x2=get(); a[i].y2=get();
a[i].x1--; a[i].y1--;
a[i].val=get();
qx[++x_num]=a[i].x1; qx[++x_num]=a[i].x2;
qy[++y_num]=a[i].y1; qy[++y_num]=a[i].y2;
}
qx[++x_num]=; qx[++x_num]=h;
qy[++y_num]=; qy[++y_num]=w; Deal_first();
Deal(); printf("%d\n",f[cnt][all]);
}
}

【BZOJ5010】【FJOI2017】矩阵填数 [状压DP]的更多相关文章

  1. [BZOJ5010][FJOI2017]矩阵填数(状压DP)

    5010: [Fjoi2017]矩阵填数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 90  Solved: 45[Submit][Status][ ...

  2. 一本通 1783 矩阵填数 状压dp 容斥 计数

    LINK:矩阵填数 刚看到题目的时候感觉是无从下手的. 可以看到有n<=2的点 两个矩形. 如果只有一个矩形 矩形外的方案数容易计算考虑 矩形内的 必须要存在x这个最大值 且所有值<=x. ...

  3. bzoj5010: [Fjoi2017]矩阵填数

    Description 给定一个 h*w 的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w.在这个矩阵中你需要在每 个格子中填入 1..m 中的某个数.给这个矩阵填数的时候有一 ...

  4. BZOJ5010 FJOI2017矩阵填数(容斥原理)

    如果只考虑某个子矩阵的话,其最大值为v的方案数显然是vsize-(v-1)size.问题在于处理子矩阵间的交叉情况. 如果两个交叉的子矩阵所要求的最大值不同,可以直接把交叉部分划给所要求的最大值较小的 ...

  5. [FJOI2017]矩阵填数——容斥

    参考:题解 P3813 [[FJOI2017]矩阵填数] 题目大意: 给定一个 h∗w 的矩阵,矩阵的行编号从上到下依次为 1...h ,列编号从左到右依次 1...w . 在这个矩阵中你需要在每个格 ...

  6. P3813 [FJOI2017]矩阵填数(组合数学)

    P3813 [FJOI2017]矩阵填数 shadowice1984说:看到计数想容斥........ 这题中,我们把图分成若干块,每块的最大值域不同 蓝后根据乘法原理把每块的方案数(互不相干)相乘. ...

  7. BZOJ 2734 [HNOI2012]集合选数 (状压DP、时间复杂度分析)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=2734 题解 嗯早就想写的题,昨天因为某些不可告人的原因(大雾)把这题写了,今天再来写题解 ...

  8. $HNOI2012\ $ 集合选数 状压$dp$

    \(Des\) 求对于正整数\(n\leq 1e5\),{\(1,2,3,...,n\)}的满足约束条件:"若\(x\)在该子集中,则\(2x\)和\(3x\)不在该子集中."的子 ...

  9. 洛谷$P3226\ [HNOI2012]$集合选数 状压$dp$

    正解:$dp$ 解题报告: 传送门$QwQ$ 考虑列一个横坐标为比值为2的等比数列,纵坐标为比值为3的等比数列的表格.发现每个数要选就等价于它的上下左右不能选. 于是就是个状压$dp$板子了$QwQ$ ...

随机推荐

  1. matlab 直方图均衡化(含rgb)

    步骤: 统计原图像素每个像素的个数 统计原图像<每个灰度级的像素的累积个数 家里灰度级得映射规则 将原图每个像素点的灰度映射到新图 代码: clear all I=imread('1.jpg') ...

  2. Delegate(QLabel和QComboBox)

    一.最终效果 二.实现思路 1.createEditor()中create两个控件,分别是QLabel和QComboBox,将其添加到一个widget中,然后返回该widget: 2.setEdito ...

  3. 【IdentityServer4文档】- 欢迎来到 IdentityServer4

    欢迎来到 IdentityServer4 IdentityServer4 是一款包含和实现了 OpenID Connect 和 OAuth 2.0 协议的,适用于 ASP.NET Core 的框架 . ...

  4. 什么是POJO模式

    1.     什么是POJO POJO的名称有多种,pure old java object .plain ordinary java object 等. 按照Martin Fowler的解释是“Pl ...

  5. iOS- UIPickerView餐厅点餐系统

    在餐厅里的点餐系统的核心控件就是UIPickerView 今天晚上在整理以前的项目笔记时,特意把UIPickerView单独拿出来,做了一个简陋的点餐道具. 因为没有素材图片,所有大家将就看看吧 0. ...

  6. 分享几个.Net计划任务组件

    Quartz http://www.quartz-scheduler.net/ Hangfire http://hangfire.io/ Install-Package Hangfire 使用OWIN ...

  7. pyHeatMap生成热力图

    库链接:https://pypi.org/project/pyheatmap/ 现在的linux系统默认都是安装好的py环境,直接用pip进行热力库安装 pip install pyheatmap 或 ...

  8. 实现一个可配置的java web 参数验证器

    当使用java web的servlet来做接口的时候,如果严格一点,经常会对请求参数做一些验证并返回错误码.我发现通常参数验证的代码就在servlet里边,如果参数不正确就返回相应的错误码.如果接口数 ...

  9. A表数据插入到B表(表结构不一致)

    D_A  有E\F\H 3字段 D_B 有 A\B\C\D\E\ID 字段 将 D_B 个别字段插入到D_A  表 INSERT INTO  D_A(E,F,H) select B,A,ID from ...

  10. [LOJ3057] [HNOI2019] 校园旅行

    题目链接 LOJ:https://loj.ac/problem/3057 洛谷:https://www.luogu.org/problemnew/show/P5292 Solution 先膜一发\(m ...