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

【题意】给定大矩阵,可以每格都可以任意填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 Python等交互式输入回退键出现 ^H^H

    执行:yum install readline readline-devel

  2. performance_schema实现套路

      实现中大量使用多层次嵌套预编译,大量if else,wrapper等 不建议去看这个实现 start_mutex_wait_v1 if (flag_thread_instrumentation) ...

  3. 30分钟玩转css3动画, transition,animation

    其实css3动画是就是2种实现,一种是transition,另一种就是animation.transition实现的话就是只能定制开始帧,和结束2帧:而animation实现的话可以写很多关键帧.没有 ...

  4. 小程序如何去掉button组件的边框

    小程序获取用户授权不再支持wx.getUserInfo方法,改为用button获取,格式如下 <button class="btn btn" open-type=" ...

  5. 【python模块】——logging

    python学习——logging模块

  6. github 初始化操作小记

     Git作为一种越来越重要的工具,github又如此流行,现在就简单记录一下git的基础操作,希望能帮助大家快速体验入门! 1 查看本地是否存在”公钥”和”私钥” 如果没有,则执行: ssh-keyg ...

  7. mysql修改外部访问权限

    mysql>use mysql; mysql>update user set host =’%’ where user=’root’ mysql>select host,user f ...

  8. ASP NET Core ---POST, PUT, PATCH, DELETE,Model 验证

    参照 草根专栏- ASP.NET Core + Ng6 实战:https://v.qq.com/x/page/u0765jbwc6f.html 一.POST 安全性和幂等性 安全性是指方法执行后并不会 ...

  9. Java串口编程学习2-读串口

    如果读串口出现乱码,则: 1.可能是波特率设置不对 2.可能是数据编码格式不对 import gnu.io.*; import java.awt.*; import java.awt.event.Ac ...

  10. 第5讲——cin处理字符输入

    本来这一讲应该是while.for.if之类的,但是,我们可是学过C的男人,再浪费时间搞这个??? 还不如学点C++中的新知识. cin对象支持3种不同模式的单字符输入,其用户接口各不相同. 下面我们 ...