【算法】离散化+容斥原理

【题意】给定大矩阵,可以每格都可以任意填1~m,给定n个子矩阵,要求满足子矩阵内的最大值为vi,求方案数。

n<=10,h,w<=1w。

【题解】

此题重点之一在于离散化,因为有效坐标很少,离散化后遵循左闭右开计算矩阵点数。

然后对于每个格,能填的最大值是min(m,vi),vi为覆盖到该点的所有小矩阵,就此算出总方案数。

现在多考虑了一些情况,就是每个小矩阵中至少要有一个格子是最大值,不符合的情况需要剔除。

考虑容斥原理,奇加偶减,不过这里是总方案-容斥部分,所以是奇减偶加。

2^n枚举子集,然后对于选中的矩阵为min(vi-1),未选中的矩阵为min(vi),其它为m,即强制选中的矩阵不符合条件。

复杂度O(2^n*[n*n^2+n^2*log n])。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=,M=; int h,w,m,n,x1[maxn],y1[maxn],x2[maxn],y2[maxn],vx[maxn];
int x[maxn],y[maxn],totx,toty,totv;
int mat[maxn][maxn],map[maxn][maxn],ans,s; int pow(int x,int k){
int as=;
while(k){
if(k&)as=1ll*as*x%M;
x=1ll*x*x%M;
k>>=;
}
return as;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&h,&w,&m,&n);
totx=toty=totv=;
x[++totx]=;x[++totx]=h+;
y[++toty]=;y[++toty]=w+;
for(int i=;i<=n;i++){
scanf("%d%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i],&vx[i]);
x[++totx]=x1[i];x[++totx]=x2[i]+;
y[++toty]=y1[i];y[++toty]=y2[i]+;
}
sort(x+,x+totx+);totx=unique(x+,x+totx+)-x-;
sort(y+,y+toty+);toty=unique(y+,y+toty+)-y-;
for(int i=;i<totx;i++)for(int j=;j<toty;j++)mat[i][j]=(x[i+]-x[i])*(y[j+]-y[j]);
for(int i=;i<=n;i++){
x1[i]=lower_bound(x+,x+totx+,x1[i])-x;
x2[i]=lower_bound(x+,x+totx+,x2[i]+)-x;
y1[i]=lower_bound(y+,y+toty+,y1[i])-y;
y2[i]=lower_bound(y+,y+toty+,y2[i]+)-y;
}
ans=;
for(int S=;S<(<<n);S++){
int num=;
for(int i=;i<totx;i++)for(int j=;j<toty;j++)map[i][j]=m;
for(int k=;k<=n;k++){
int mx=vx[k];
if(S&(<<(k-))){mx--;num++;}
for(int i=x1[k];i<x2[k];i++)for(int j=y1[k];j<y2[k];j++)map[i][j]=min(map[i][j],mx);
}
if(num&)s=-;else s=;
for(int i=;i<totx;i++)for(int j=;j<toty;j++)s=1ll*s*pow(map[i][j],mat[i][j])%M;
ans=(ans+s)%M;
}
printf("%d\n",(ans+M)%M);
}
return ;
}

可以优化一下,统计每个策略时本来是枚举所有点,改为枚举所有权值,因为快速幂取模很慢,所以速度得到了巨大的提升……

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=,M=; int h,w,m,n,x1[maxn],y1[maxn],x2[maxn],y2[maxn],vx[maxn];
int x[maxn],y[maxn],v[maxn],totx,toty,totv;
int mat[maxn][maxn],map[maxn][maxn],ans,s,c[maxn]; int pow(int x,int k){
int as=;
while(k){
if(k&)as=1ll*as*x%M;
x=1ll*x*x%M;
k>>=;
}
return as;
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&h,&w,&m,&n);
totx=toty=totv=;
x[++totx]=;x[++totx]=h+;
y[++toty]=;y[++toty]=w+;
v[++totv]=m;
for(int i=;i<=n;i++){
scanf("%d%d%d%d%d",&x1[i],&y1[i],&x2[i],&y2[i],&vx[i]);
x[++totx]=x1[i];x[++totx]=x2[i]+;
y[++toty]=y1[i];y[++toty]=y2[i]+;
v[++totv]=vx[i];v[++totv]=vx[i]-;
}
sort(x+,x+totx+);totx=unique(x+,x+totx+)-x-;
sort(y+,y+toty+);toty=unique(y+,y+toty+)-y-;
sort(v+,v+totv+);totv=unique(v+,v+totv+)-v-;
for(int i=;i<totx;i++)for(int j=;j<toty;j++)mat[i][j]=(x[i+]-x[i])*(y[j+]-y[j]);
for(int i=;i<=n;i++){
x1[i]=lower_bound(x+,x+totx+,x1[i])-x;
x2[i]=lower_bound(x+,x+totx+,x2[i]+)-x;
y1[i]=lower_bound(y+,y+toty+,y1[i])-y;
y2[i]=lower_bound(y+,y+toty+,y2[i]+)-y;
vx[i]=lower_bound(v+,v+totv+,vx[i])-v;
}
ans=;
for(int S=;S<(<<n);S++){
int num=;
for(int i=;i<totx;i++)for(int j=;j<toty;j++)map[i][j]=totv;
for(int k=;k<=n;k++){
int mx=vx[k];
if(S&(<<(k-))){mx--;num++;}
for(int i=x1[k];i<x2[k];i++)for(int j=y1[k];j<y2[k];j++)map[i][j]=min(map[i][j],mx);
}
if(num&)s=-;else s=;
for(int i=;i<=totv;i++)c[i]=;
for(int i=;i<totx;i++)for(int j=;j<toty;j++)c[map[i][j]]+=mat[i][j];
for(int i=;i<=totv;i++)s=1ll*s*pow(v[i],c[i])%M;
ans=(ans+s)%M;
}
printf("%d\n",(ans+M)%M);
}
return ;
}

【BZOJ】5010: [Fjoi2017]矩阵填数的更多相关文章

  1. bzoj 5010: [Fjoi2017]矩阵填数

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

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

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

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

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

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

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

  5. bzoj5010: [Fjoi2017]矩阵填数

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

  6. [luogu P3813] [FJOI2017] 矩阵填数 解题报告 (容斥原理)

    题目链接: https://www.luogu.org/problemnew/show/P3813 题目: 给定一个 h*w的矩阵,矩阵的行编号从上到下依次为 1..h,列编号从左到右依次1..w. ...

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

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

  8. P3813 [FJOI2017]矩阵填数

    传送门 矩阵很大,但是发现 $n$ 很小,从这边考虑,对于一个一堆小矩阵放在一起的情况 考虑把每一块单独考虑然后方案再乘起来 但是这些奇怪的东西很不好考虑 所以暴力一点,直接拆成一个个小块 但是这样我 ...

  9. [FJOI2017]矩阵填数

    [Luogu3813] [LOJ2280] 写得很好的题解 \(1.\)离散化出每一块内部不互相影响的块 \(2.\)\(dp[i][j]\)为前 \(i\) 种重叠块其中有 \(j\) 这些状态的矩 ...

随机推荐

  1. [转]Visual Studio 项目类型 GUID 清单

    转自:https://www.codeproject.com/Reference/720512/List-of-Visual-Studio-Project-Type-GUIDs Complete li ...

  2. 30分钟快速搭建Web CRUD的管理平台--django神奇魔法

    加上你的准备的时间,估计30分钟完全够用了,因为最近在做爬虫管理平台,想着快速开发,没想到python web平台下有这么非常方便的框架,简洁而优雅.将自己的一些坑总结出来,方便给大家的使用. 准备环 ...

  3. 失败的尝试,使用继承扩展数组,以及ES6的必要性

    我们都知道直接在原生对象上扩展对象是很不好的.所以prototype这样的库广受非议. 一些库,比如lodash采用了工具包形式的扩展方式,绕开了对象的继承. 由于es6的class的出现,我尝试以A ...

  4. [HNOI2004]打鼹鼠

    鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的.根据这个特点阿牛编写了一个打鼹鼠的游戏:在一个\(n*n\)的网格中,在某些时刻鼹鼠会在某一个网格探出头来透透气.你 ...

  5. 【java并发编程实战】第八章:线程池的使用

    1.线程饥饿锁 定义:在线程池中,如果任务的执行依赖其他任务,那么可能会产生线程饥饿锁.尤其是单线程线程池. 示例: public class ThreadDeadStarveTest { publi ...

  6. DOM操作相关案例 模态对话框,简易留言板,js模拟选择器hover,tab选项卡,购物车案例

    1.模态框案例 需求: 打开网页时有一个普通的按钮,点击当前按钮显示一个背景图,中心并弹出一个弹出框,点击X的时候会关闭当前的模态框 代码如下: <!DOCTYPE html> <h ...

  7. MySQL性能分析和优化-part 1

    MySQL性能优化 平时我们在使用MySQL的时候,怎么评估系统的运行状态,怎么快速定位系统瓶颈,又如何快速解决问题呢? 本文总结了多年来MySQL优化的经验,系统介绍MySQL优化的方法. OS性能 ...

  8. HDFS伪分布式

    (一).HDFS shell操作 以上已经介绍了如何搭建伪分布式的Hadoop,既然环境已经搭建起来了,那要怎么去操作呢?这就是本节将要介绍的内容: HDFS自带有一些shell命令,通过这些命令我们 ...

  9. erc20代币合约

    看这篇文章需要对以太坊,智能合约,代币等概念有基本的了解. 什么是ERC20 可以把ERC20简单理解成以太坊上的一个代币协议,所有基于以太坊开发的代币合约都遵守这个协议.遵守这些协议的代币我们可以认 ...

  10. AM5728通过GPMC接口与FPGA高速数据通信实现

    硬件:AM5728开发板:Artix-7开发板软件:Linux am57xx-evm 4.4.19:Vivado 2015.2作者:杭州矢志信息科技有限公司邮箱:admin@sysjoint.com ...