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

【题意】给定大矩阵,可以每格都可以任意填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. linux命令大全(转载)

    在搭建openstack时遇到问题,导致上网查询相关信息.找到一篇不错的文章,希望对大家有用.下附地址: http://blog.csdn.net/junbujianwpl/article/detai ...

  2. JDBC剖析篇(1):java中的Class.forName()

    一.Class.forName() 在Java中我们一般用下面这样的语句来连接数据库(以MySQL为例) Class.forName("com.mysql.jdbc.Driver" ...

  3. 【个人训练】(POJ1276)Cash Machine

    最近的很多题解应该都是dp相关的了,emmm因为dp对我而言思考难度比较大,那么为了理顺自己的思路当然只能通过写blog整理了.愿我能成功搞定dp这个大关!(至少中等难度的dp要能够解决啊o(TヘTo ...

  4. BZOJ1222[HNOI 2001]产品加工

    题面描述 某加工厂有A.B两台机器,来加工的产品可以由其中任何一台机器完成,或者两台机器共同完成.由于受到机器性能和产品特性的限制,不同的机器加工同一产品所需的时间会不同,若同时由两台机器共同进行加工 ...

  5. 梳理 Opengl ES 3.0 (二)剖析一个GLSL程序

    OpenGL ES shading language 3.0 也被称作 GLSL,是个 C风格的编程语言. Opengl ES 3.0内部有两种可编程处理单元,即Vertex processor和Fr ...

  6. C指针分析详解

    局部变量和全局变量初始化区别: 局部变量,在未初始化情况下,初值为随机值.C规范对该初值并没有做规定,具体实现由编译器决定.如VC/VS等编译器,会将初始值值为0xCCCCCCCC, 而GCC等编译器 ...

  7. tensorflow Importing Data

    tf.data API可以建立复杂的输入管道.它可以从分布式文件系统中汇总数据,对每个图像数据施加随机扰动,随机选择图像组成一个批次训练.一个文本模型的管道可能涉及提取原始文本数据的符号,使用查询表将 ...

  8. pandas DataFrame的查询方法(loc,iloc,at,iat,ix的用法和区别)

    pandas DataFrame的增删查改总结系列文章: pandas DaFrame的创建方法 pandas DataFrame的查询方法 pandas DataFrame行或列的删除方法 pand ...

  9. java设计模式之模版方法模式以及在java中作用

    模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有 ...

  10. redis安装与启动

    安装简介: 在安装redis前需要了解redis官方发布时的版本规则,redis官方约定次版本号(即第一个小数点后的数字)为偶数的版本是稳定版(如2.8版,3.0版),奇数版本则为非稳定版本(如2.7 ...