BZOJ5010 FJOI2017矩阵填数(容斥原理)
如果只考虑某个子矩阵的话,其最大值为v的方案数显然是vsize-(v-1)size。问题在于处理子矩阵间的交叉情况。
如果两个交叉的子矩阵所要求的最大值不同,可以直接把交叉部分划给所要求的最大值较小的子矩阵。那么,所要求最大值不同的格子彼此间是独立的。于是现在可以只考虑要求相同的格子。
直接计算似乎很麻烦。由于n很小,考虑一个很套路的容斥:至少0个不满足限制的方案数-至少1个不满足限制的方案数+至少2个不满足限制的方案数……于是我们可以枚举哪些矩阵不满足限制,剩下的随便填(当然要在所限制的最大值之内)。
计算这些矩形的交和并也是一个有点麻烦的问题。可以离散化后暴力统计。这里离散化后应该每个位置表示一段区间比较方便,所以读入时++x2,++y2。由于数据范围实在太小怎么做都行。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define P 1000000007
#define N 13
#define y1 y3
#define y2 y4
int T,r,c,n,m,row[N<<],line[N<<],flag[N<<][N<<],ans,sum,nw,nv;
bool choose[N];
struct data
{
int x1,y1,x2,y2,v,size;
int tag[N<<][N<<];
bool operator <(const data&a) const
{
return v>a.v;
}
}a[N];
int ksm(int a,int k)
{
if (k==) return ;
int tmp=ksm(a,k>>);
if (k&) return 1ll*tmp*tmp%P*a%P;
else return 1ll*tmp*tmp%P;
}
int calc(int v)
{
memset(flag,,sizeof(flag));
for (int i=;i<=n;i++)
if (a[i].v==v&&!choose[i])
for (int j=a[i].x1;j<a[i].x2;j++)
for (int k=a[i].y1;k<a[i].y2;k++)
if (a[i].tag[j][k]) flag[j][k]=;
for (int i=;i<=n;i++)
if (choose[i])
for (int j=a[i].x1;j<a[i].x2;j++)
for (int k=a[i].y1;k<a[i].y2;k++)
if (a[i].tag[j][k]) flag[j][k]=-;
int s1=,s2=;
for (int i=;i<nw;i++)
for (int j=;j<nv;j++)
if (flag[i][j]==) s1+=(row[i+]-row[i])*(line[j+]-line[j]);
else if (flag[i][j]==-) s2+=(row[i+]-row[i])*(line[j+]-line[j]);
return 1ll*ksm(v,s1)*ksm(v-,s2)%P;
}
void dfs(int k,int s,int v)
{
if (k>n)
{
if (s&) sum=(sum-calc(v)+P)%P;
else sum=(sum+calc(v))%P;
return;
}
if (a[k].v==v) choose[k]=,dfs(k+,s+,v);
choose[k]=;dfs(k+,s,v);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj5010.in","r",stdin);
freopen("bzoj5010.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();
while (T--)
{
r=read(),c=read(),m=read(),n=read();
for (int i=;i<=n;i++)
a[i].x1=read(),a[i].y1=read(),a[i].x2=read()+,a[i].y2=read()+,a[i].v=read(),a[i].size=,memset(a[i].tag,,sizeof(a[i].tag));
int w=,v=;
for (int i=;i<=n;i++)
row[++w]=a[i].x1,row[++w]=a[i].x2,line[++v]=a[i].y1,line[++v]=a[i].y2;
row[++w]=,row[++w]=r+;line[++v]=,line[++v]=c+;
sort(row+,row+w+);sort(line+,line+v+);
nw=unique(row,row+w+)-row-,nv=unique(line,line+v+)-line-;
for (int i=;i<=n;i++)
a[i].x1=lower_bound(row+,row+nw+,a[i].x1)-row,a[i].x2=lower_bound(row+,row+nw+,a[i].x2)-row,
a[i].y1=lower_bound(line+,line+nv+,a[i].y1)-line,a[i].y2=lower_bound(line+,line+nv+,a[i].y2)-line;
sort(a+,a+n+);
memset(flag,,sizeof(flag));
for (int i=;i<=n;i++)
for (int j=a[i].x1;j<a[i].x2;j++)
for (int k=a[i].y1;k<a[i].y2;k++)
flag[j][k]=a[i].v;
for (int i=;i<=n;i++)
for (int j=;j<nw;j++)
for (int k=;k<nv;k++)
if (flag[j][k]==a[i].v) a[i].size++,a[i].tag[j][k]=;
ans=;
for (int i=;i<nw;i++)
for (int j=;j<nv;j++)
if (flag[i][j]==) ans=1ll*ans*ksm(m,(row[i+]-row[i])*(line[j+]-line[j]))%P;
for (int i=;i<=n;i++)
{
sum=;int t=i;
while (a[t+].v==a[i].v) t++;
memset(choose,,sizeof(choose));
dfs(i,,a[i].v);
ans=1ll*ans*sum%P;
i=t;
}
cout<<ans<<endl;
}
return ;
}
BZOJ5010 FJOI2017矩阵填数(容斥原理)的更多相关文章
- [BZOJ5010][FJOI2017]矩阵填数(状压DP)
5010: [Fjoi2017]矩阵填数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 90 Solved: 45[Submit][Status][ ...
- bzoj5010: [Fjoi2017]矩阵填数
Description 给定一个 h*w 的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w.在这个矩阵中你需要在每 个格子中填入 1..m 中的某个数.给这个矩阵填数的时候有一 ...
- P3813 [FJOI2017]矩阵填数(组合数学)
P3813 [FJOI2017]矩阵填数 shadowice1984说:看到计数想容斥........ 这题中,我们把图分成若干块,每块的最大值域不同 蓝后根据乘法原理把每块的方案数(互不相干)相乘. ...
- [FJOI2017]矩阵填数——容斥
参考:题解 P3813 [[FJOI2017]矩阵填数] 题目大意: 给定一个 h∗w 的矩阵,矩阵的行编号从上到下依次为 1...h ,列编号从左到右依次 1...w . 在这个矩阵中你需要在每个格 ...
- [luogu P3813] [FJOI2017] 矩阵填数 解题报告 (容斥原理)
题目链接: https://www.luogu.org/problemnew/show/P3813 题目: 给定一个 h*w的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w. ...
- bzoj 5010: [Fjoi2017]矩阵填数
Description 给定一个 h*w 的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w.在这个矩阵中你需要在每 个格子中填入 1..m 中的某个数.给这个矩阵填数的时候有一 ...
- 【BZOJ】5010: [Fjoi2017]矩阵填数
[算法]离散化+容斥原理 [题意]给定大矩阵,可以每格都可以任意填1~m,给定n个子矩阵,要求满足子矩阵内的最大值为vi,求方案数. n<=10,h,w<=1w. [题解] 此题重点之一在 ...
- P3813 [FJOI2017]矩阵填数
传送门 矩阵很大,但是发现 $n$ 很小,从这边考虑,对于一个一堆小矩阵放在一起的情况 考虑把每一块单独考虑然后方案再乘起来 但是这些奇怪的东西很不好考虑 所以暴力一点,直接拆成一个个小块 但是这样我 ...
- [FJOI2017]矩阵填数
[Luogu3813] [LOJ2280] 写得很好的题解 \(1.\)离散化出每一块内部不互相影响的块 \(2.\)\(dp[i][j]\)为前 \(i\) 种重叠块其中有 \(j\) 这些状态的矩 ...
随机推荐
- android ActionBarSherlock使用说明
源代码地址:https://github.com/JakeWharton/ActionBarSherlock 1.添加项目依赖包 2.修改AndroidManifest.xml中的主题(或者继承该主题 ...
- SkylineGlobe 如何二次开发实现天际线分析功能
天际线效果: 示例代码: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <h ...
- day88
ContentType 场景需求:比方说我们现有两种商品,但是他们对应着一个价格策略表,为了防止数据库的浪费,我们在价格策略中加入一个表名字段,一个表明对应的id字段,这样的设计既优化了数据库,还不怕 ...
- 一篇文章让你彻底掌握 shell 语言
一篇文章让你彻底掌握 shell 语言 由于 bash 是 Linux 标准默认的 shell 解释器,可以说 bash 是 shell 编程的基础. 本文主要介绍 bash 的语法,对于 linux ...
- 针对django2.2报错:UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: ill....
1.报错: File "D:\Python\Python37-32\lib\site-packages\django\views\debug.py", line 332, in g ...
- FreeCAD源码初步了解
FreeCAD简介 FreeCAD是基于OpenCASCADE的开源CAD/CAE软件,完全开源(GPL的LGPL许可证),官方源码地址,详情可参考维基百科,百度百科等等. 如果要编译FreeCAD, ...
- Centos下安装破解Jira7的操作记录
Jira是一个集项目计划.任务分配.需求管理.错误跟踪于一体的工具,可以作为一个bug管理系统,可以将在测试过程中所发现的bug录入.分配给开发人员.前面介绍了Confluence在Centos下的安 ...
- Docker容器学习梳理 - 应用程序容器环境部署
关于国内Docker镜像,可以参考:Docker容器学习梳理--基础知识(2) 的Docker镜像使用. 如果我们需要在Docker环境下部署tomcat.redis.mysql.nginx.php等 ...
- rsync同步时,删除目标目录比源目录多余文件的方法(--delete)
在日常运维工作中,我们经常用到rsync这个同步神器.有时在同步两个目录时,会要求删除目标目录中比源目录多出的文件,这种情况下,就可用到rsync的--delete参数来实现这个需求了. 实例说明:在 ...
- C_数据结构_数组的修改和删除
#include<stdio.h> typedef struct Node { int a,b; }node; node c[]; int n; void print() { int i; ...