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\) 这些状态的矩 ...
随机推荐
- BP浅谈
之前一直对BP的理解不透彻,这可不行,这个可是超经典的广泛应用在ML中的求偏导的方法.本博来自<神经网络与机器学习>P86页. 在用到bp的地方我们都是为了使用梯度下降法,并求出他的偏导数 ...
- 【强化学习】python 实现 q-learning 例三(例一改写)
本文作者:hhh5460 本文地址:https://www.cnblogs.com/hhh5460/p/10139738.html 例一的代码是函数式编写的,这里用面向对象的方式重新撸了一遍.好处是, ...
- TiDB入门(四):从入门到“跑路”
前言 前面三章基本把 TiDB 的环境弄好了,也做了一下简单测试,有兴趣的同学可以看一下: TiDB 入门(一):TiDB 简介 TiDB 入门(二):虚拟机搭建 TiDB-Ansible 部署方案 ...
- ABPZero中的Name和SurName处理,以及EmailAddress解决方案(完美)。
使用ABPzero的朋友们都知道,User表中有Name和Surname两个字段,这两个字段对于国内的用户来说相当的不友好. 以及我们的一些系统中是不会涉及到EmailAddress字段.也就是说不会 ...
- Rancher + k8s + docker 部署资料
一.k8s 文档: https://jimmysong.io/kubernetes-handbook/concepts/deployment.html 命令行大全 https://kubernetes ...
- zabbix监控-基本原理介绍
一.Linux下开源监控系统简单介绍1)cacti:存储数据能力强,报警性能差2)nagios:报警性能差,存储数据仅有简单的一段可以判断是否在合理范围内的数据长度,储存在内存中.比如,连续采样数据存 ...
- 树莓派3代b型静态IP设置,和ssh的wlan配置
https://blog.csdn.net/qq_36305492/article/details/78607557
- Echarts学习求教
有没有人用过百度的Echarts?刚开始接触,下面这段代码怎么理解啊,新手求指教: myChart.showLoading();$.get('data/asset/data/les-miserable ...
- 基于SSH框架的在线考勤系统开发的质量属性
我要开发的是一个基于SSH框架的在线考勤系统. 质量属性是指影响质量的相关因素,下面我将分别从6个系统质量属性(可用性,易用性,可修改性,性能,安全性,可测试性)来分析我的系统,以及如何实现这些质量属 ...
- 转【c语言】两个堆栈组成一个队列
假设有两个堆栈,分别是s1,s2,现在有数列“1,2,3,4,5”,要让这个数列实现先进先出的功能,也就是用两个堆栈组成一个队列,如何实现? 分析: 先将数列压入栈s1,数列在栈中由顶到底的元素为“5 ...