2023NOIP A层联测17 爆炸

2023-10-25 04:04
文章标签 17 爆炸 联测 2023noip

本文主要是介绍2023NOIP A层联测17 爆炸,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意

有一个 n × m n\times m n×m的网格图,其中一些格子上有一个炸弹,一些格子上有一个水晶,剩下的格子为空地。

炸弹可以引爆,每当一个炸弹被引爆,它必须选择:引爆它所在的这一行或者引爆它所在的这一列。水晶被引爆后会消失(即如果一个水晶所在的行列均被引爆,也只计算一次),炸弹被引爆后,会产生连锁反应,被引爆的炸弹也会选择引爆它所在的行或者列,如此下去直到没有新的炸弹被引爆。

现在你可以选择一个炸弹和其引爆的方向,请你求出最多可以引爆多少个水晶。

k k k个水晶, b b b个炸弹。

1 ≤ n , m ≤ 3000 , 0 ≤ k + b ≤ n m 1\leq n,m\leq 3000,0\leq k+b\leq nm 1n,m3000,0k+bnm

时间限制 3000 m s 3000ms 3000ms,空间限制 512 M B 512MB 512MB


题解

一个炸弹引爆之后,它的方向是固定的,如果被竖着引爆,那么应该选择横着引爆,否则选择竖着引爆。

那么,我们把每一行和每一列都看作一个点,则总共有 n + m n+m n+m个点。对于每个炸弹,设炸弹的位置为 ( x , y ) (x,y) (x,y),那么就将第 x x x行对应的点和第 y y y列对应的点连边,表示第 x x x行被炸到时,通过这个炸弹可以炸到第 y y y列。

建好了图,引爆一个炸弹就相当于遍历这个炸弹所在的行或列对应的点所在的连通块,对于所有能遍历到的点,判断这些点对应的行和列总共能涉及到哪些水晶。

当然,我们发现这种做法有一些问题,因为被引爆的炸弹的行和列对应的点是被这个炸弹作为边连接的,所以我们引爆炸弹实际上是将这个点所在的行和列都引爆了。下面,我们考虑如何减去多计算的贡献。

  • 如果一个炸弹在这一行爆炸之后可以通过若干次引爆再炸到自己这一行(也就是图上的一个点被遍历多次,等价于图上存在环),那么我们可以将引爆的炸弹设为这一行上的一个炸弹,将这个炸弹所在列引爆,那么这一行在最终还是会被引爆的,所以并没有多算贡献
  • 如果一个炸弹在这一列爆炸之后可以通过若干次引爆再炸到自己这一列,与上面相同,也没有多算贡献
  • 如果上面两个条件都不满足,也就是说这个图存在至少两个点的度为 1 1 1(这个图没有环,也就是是一棵树,而且点的数量大于等于 2 2 2,由边的总数为 n − 1 n-1 n1可得点的度的总和为 2 n − 2 2n-2 2n2,一定存在至少两个点的度为 1 1 1),则这些度为 1 1 1的点对应的行或列上就没有别的炸弹,那我们可以不选这些度为 1 1 1的点对应的行或列,对于行或列上的每个水晶,判断如果没有这次引爆这个水晶是否还会消失,用上面算出的值减去原本会消失而去掉这一行或列后不会消失的水晶数量来更新答案即可

对于第三种情况,如果引爆对应的行或列更优(也就是只得到这一行或列的水晶比连锁反应所能得到的水晶更多),那这部分的贡献怎么没有体现呢?

因为度为 1 1 1的点的数量大于等于 2 2 2,所以假如引爆度为 1 1 1的点 u u u对应的行或列会更优,则在不引爆另一个度为 1 1 1的点 v v vd对应的行或列时,点 u u u对应的行或列是会被引爆的,那它对答案的贡献就体现出来了。

所以,这样做是可行的。

那如何求一个原本会消失的水晶在去掉一行或一列之后是否还会消失呢?我们只需要记录每个水晶被引爆的次数,之后在去掉一行或一列时,遍历这一行或这一列上的每个水晶,如果水晶只被引爆了一次,则这个水晶就不会消失;否则,这个水晶还会消失。

时间复杂度为 O ( ( n + m ) 2 ) O((n+m)^2) O((n+m)2)

code

#include<bits/stdc++.h>
using namespace std;
const int N=3000;
int n,m,K,B,tot=0,d[2*N*N+5],l[2*N*N+5],r[2*N+5];
int cl=0,fl,now,mx,ans=0,wt[2*N+5],cm[2*N+5],z[N+5][N+5],hv[N+5][N+5];
char ch;
vector<int>v[2*N+5];
void add(int xx,int yy){l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
void dfs1(int u,int fa){cm[u]=1;if(u<=n){for(int i=0;i<v[u].size();i++){if(z[u][v[u][i]]!=cl){z[u][v[u][i]]=cl;hv[u][v[u][i]]=0;++now;}++hv[u][v[u][i]];}}else{for(int i=0;i<v[u].size();i++){if(z[v[u][i]][u-n]!=cl){z[v[u][i]][u-n]=cl;hv[v[u][i]][u-n]=0;++now;}++hv[v[u][i]][u-n];}}for(int i=r[u];i;i=l[i]){if(cm[d[i]]){if(d[i]!=fa) fl=1;continue;}dfs1(d[i],u);}
}
void dfs2(int u){cm[u]=2;if(u<=n&&wt[u]==1){int tmp=now;for(int i=0;i<v[u].size();i++){if(hv[u][v[u][i]]==1) --tmp;}mx=max(mx,tmp);}else if(u>n&&wt[u]==1){int tmp=now;for(int i=0;i<v[u].size();i++){if(hv[v[u][i]][u-n]==1) --tmp;}mx=max(mx,tmp);}for(int i=r[u];i;i=l[i]){if(cm[d[i]]==2) continue;dfs2(d[i]);}
}
int main()
{
//	freopen("boom.in","r",stdin);
//	freopen("boom.out","w",stdout);scanf("%d%d%d%d",&n,&m,&K,&B);for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){ch=getchar();while(ch!='.'&&ch!='k'&&ch!='b') ch=getchar();if(ch=='b'){add(i,n+j);add(n+j,i);++wt[i];++wt[n+j];}else if(ch=='k'){v[i].push_back(j);v[n+j].push_back(i);}}}for(int i=1;i<=n+m;i++){if(wt[i]&&!cm[i]){fl=0;now=0;++cl;dfs1(i,0);mx=0;dfs2(i);if(fl) ans=max(ans,now);else ans=max(ans,mx);}}printf("%d",ans);return 0;
}

这篇关于2023NOIP A层联测17 爆炸的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/279905

相关文章

17 通过ref代替DOM用来获取元素和组件的引用

重点 ref :官网给出的解释是: ref: 用于注册对元素或子组件的引用。引用将在父组件的$refs 对象下注册。如果在普通DOM元素上使用,则引用将是该元素;如果在子组件上使用,则引用将是组件实例: <!-- vm.$refs.p will be the DOM node --><p ref="p">hello</p><!-- vm.$refs.child will be the c

react笔记 8-17 属性绑定 class绑定 引入图片 循环遍历

1、绑定属性 constructor(){super()this.state={name:"张三",title:'我是一个title'}}render() {return (<div><div>aaaaaaa{this.state.name}<div title={this.state.title}>我是一个title</div></div></div>)} 绑定属性直接使用花括号{}   注

【全网最全】2024年数学建模国赛A题30页完整建模文档+17页成品论文+保奖matla代码+可视化图表等(后续会更新)

您的点赞收藏是我继续更新的最大动力! 一定要点击如下的卡片,那是获取资料的入口! 【全网最全】2024年数学建模国赛A题30页完整建模文档+17页成品论文+保奖matla代码+可视化图表等(后续会更新)「首先来看看目前已有的资料,还会不断更新哦~一次购买,后续不会再被收费哦,保证是全网最全资源,随着后续内容更新,价格会上涨,越早购买,价格越低,让大家再也不需要到处买断片资料啦~💰💸👋」�

算法练习题17——leetcode54螺旋矩阵

题目描述 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。  代码 import java.util.*;class Solution {public List<Integer> spiralOrder(int[][] matrix) {// 用于存储螺旋顺序遍历的结果List<Integer> result = new ArrayList

标准库标头 <filesystem> (C++17)学习

此头文件是文件系统支持库的一部分。本篇介绍filesystem命名空间的一些函数。 函数 在命名空间 std::filesystem 定义 absolute (C++17) 组成一个绝对路径 (函数) canonicalweakly_canonical (C++17) 组成一个规范路径 (函数) relativeproximate (C++17) 组成一个相对路径 (函数) copy (C

C++基础:折叠表达式(C++17)

C++基础:折叠表达式(C++17) 简介语法展开 示例 简介 C++17 引入了一种新的语法特性,叫做折叠表达式,它允许编译器在模板参数包展开时进行元编程操作。折叠表达式的引入极大地简化了元编程代码,使其变得更为直观和简介。 语法 折叠表达式,简单来说,就是以二元运算符对形参包进行折叠,总共有以下四种类型: 一元右折叠一元左折叠二元右折叠二元左折叠 其对应的语法如下:

javaweb-day01-2(00:17:48 XML 的作用 和 语法)

XML: 描述 可扩展标记语言,w3c  2000年发布的 XML 1.0 版本规范。 用来描述数据之间的关系。 经常用作 软件  的配置文件,描述 模块与模块 之间的关系。 还用作    软件启动  的配置文件,描述 启动模块之间的 依赖 关系。 语法 一个XML文件分为如下几部分内容: 文档声明元素属性注释CDATA区、转义字符处

PostgreSQL 17即将发布,新功能Top 3

按照计划,PostgreSQL 17 即将在 2024 年 9 月 26 日发布,目前已经发布了第一个 RC 版本,新版本的功能增强可以参考 Release Notes。 本文给大家分享其中 3 个重大的新增功能。 MERGE 语句增强 MERGE 语句是 PostgreSQL 15 增加的一个新功能,它可以在单个语句中实现 INSERT、UPDATE 以及 DELETE 操作,非常适合数据

关于LLC知识17

1、如何判断一个元器件是不是源? 对于Lr,Lm,Cr这三个元器件,在工作过程中,能量是不断变化的,如果某个元器件的能量增大,说明它在充电,不是源,如果某个元器件的能量是在慢慢减小,说明是在放电就是一个源。 对于一个理想变压器来说,到副边始终是传输能量,能量是透传的,所以不存在充电和放电的问题。 2、判断透传电流正负的方法 Lm压差为上正下负时候,副边D1导通,副边从同名端出,原边也从

VMware workstation 17

附上VMware 17下载地址: vm17pro 转载: 从0开始:Vmware Workstation pro 17 安装使用教程(详细图文)