矩阵填数

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. python学习笔记03:python的核心数据类型

    从根本上讲,Python是一种面向对象的语言.它的类模块支持多态,操作符重载和多重继承等高级概念,并且以Python特有的简洁的语法和类型,OOP十分易于使用.Python的语法简单,容易上手. Py ...

  2. 访问需要HTTP Basic Authentication认证的资源的各种开发语言的实现

    什么是HTTP Basic Authentication?直接看http://en.wikipedia.org/wiki/Basic_authentication_scheme吧. 在你访问一个需要H ...

  3. PAT 1035 插入与归并

    https://pintia.cn/problem-sets/994805260223102976/problems/994805286714327040 据维基百科的定义: 插入排序是迭代算法,逐一 ...

  4. mysqlslap工具测试mysql DB的性能

    mysqlslap的一个主要工作场景就是对数据库服务器做基准测试.     测试方法 1.测试工具:mysqlslap,mysqlslap是MySQL5.1.4之后自带的benchmark基准测试工具 ...

  5. cacti 添加mysql 监控 (远程服务器)

    监控主机 192.168.24.69 ,以下用A表示 被监控主机 192.168.24.79,以下用B标识   记得在A服务器的cacti中导入监控mysql的templates文件   1.在B上安 ...

  6. Jira & SVN & Chrome extensions

    Jira & SVN & Chrome extensions Plugins SVN & Jira Plugins ok selector bug document.query ...

  7. coreldraw x5提示盗版警告解决方法

    CorelDRAW是一款图形图像软件,大多数用户使用的都是coreldraw x5破解版,所以基本上都收到了coreldraw x5提示盗版警告,导致不能用,没关系,绿茶小编有解决方法. coreld ...

  8. TDDL剖析

    前言 在开始讲解淘宝的TDDL(Taobao Distribute Data Layer)技术之前,请允许笔者先吐槽一番.首先要开喷的是淘宝的社区支持做的无比的烂,TaoCode开源社区上面,几乎从来 ...

  9. Spring编程式事务管理及声明式事务管理

    本文将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. Spring 事务属性分析 事务管理 ...

  10. [BZOJ3380] [USACO2004 Open]Cave Cows 1 洞穴里的牛之一

    Description ​ 很少人知道其实奶牛非常喜欢到洞穴里面去探险. ​ 洞窟里有N(1≤N≤100)个洞室,由M(1≤M≤1000)条双向通道连接着它们.每对洞室间 至多只有一条双向通道.有K( ...