首页 > 其他分享 >【题解】[ABC318F] Octopus(思维)

【题解】[ABC318F] Octopus(思维)

时间:2023-09-10 19:11:41浏览次数:53  
标签:ABC318F le int 题解 抓取 ch 区间 宝藏 Octopus

【题解】[ABC318F] Octopus

题目链接

F - Octopus

题意概述

有个机器人,它有 \(n\) 个手臂,第 \(i\) 个手臂长度为 \(l_i\)。同时有 \(n\) 个宝藏,第 \(i\) 个宝藏的坐标是 \(x_i\)。

当机器人位于 \(k\) 时,它的第 \(i\) 条手臂可以够到 \([k-l_i,k+l_i]\) 范围内的宝藏。

机器人的每条手臂只能选择一个宝藏。请问总共有多少个整数坐标,能够让机器人在这个坐标能够拿到所有宝藏?

数据范围

  • \(1 \le n \le 200\)
  • \(- 10^{18} \le x_1 < x_2 < \cdots < x_n \le 10^{18}\)
  • \(1 \le l_1 <l_2 <\cdots <l_n \le 10^{18}\)

题目分析

注意到 \(n\) 的范围只有 \(200\),可以想到应该是 \(n^3\) 级别的复杂度。


由于机器人的每条手臂只能选择一个宝藏,我们考虑对于每一个宝藏 \(i(1\le i \le n)\),预处理出来当它被第 \(j(1 \le j \le n)\) 条手臂抓取时,\(k\) 可能的坐标范围 \(ans_{i,j}\),即 \(ans_{i,j}=[x_i-l_j,x_i+l_j]\)。

那么预处理出来所有宝藏 \(i\) 对于每一条手臂 \(j\) 抓取时,\(k\) 可能的坐标范围就是 \(O(n^2)\)。

假如我们已经钦定了哪个宝藏被哪个手臂抓取,那么要抓取到所有的宝藏合法的区间范围,就是对于所有的宝藏 \(i\) 和要抓取它的手臂 \(j\) 对应的 \(k\) 的可能的坐标范围的交集,即假设抓取宝藏 \(i\) 的手臂 \(j=id_i\),那么答案就是 \(res=ans_{1,id_1} \cap ans_{2,id_2} \cap \cdots ans_{n,id_n}\)。

那么总答案就是对于所有宝藏与手臂配对的情况的 \(k\) 的合法范围 \(res\) 取一个并集。

由此可以知道,最终的答案区间是若干个区间的并集,并且这些区间的端点一定是某个 \(x_i-l_j\) 或 \(x_i+l_j\)。

注意:这里的并集是指答案区间的若干个极大区间的并。


【思路一】

可以发现这若干个区间的左端点一定是某个 \(x_i-l_j\),右端点一定是 \(x_i+l_j\)。

那么我们可以分别枚举每个 \(x_i-l_j\) 和 \(x_i+l_j\),看看他们是否能成为某个区间的左端点/右端点。

如果一个 \(L=x_i-l_j\) 满足当 \(L\) 作为 \(k\) 时可以抓取到所有的 \(n\) 个宝藏,而 \(L-1\) 作为 \(k\) 时不能抓取到所有的 \(n\) 个宝藏,那么 \(L=x_i-l_j\) 就是最终答案区间所构成的若干个区间并集中其中一个区间的左端点。反之不是。

同理,如果一个 \(R=x_i-l_j\) 满足当 \(R\) 作为 \(k\) 时可以抓取到所有的 \(n\) 个宝藏,而 \(R+1\) 作为 \(k\) 时不能抓取到所有的 \(n\) 个宝藏,那么 \(R=x_i+l_j\) 就是最终答案区间所构成的若干个区间并集中其中一个区间的右端点。反之不是。

那么我们只需要对于所有的左端点 \(L_i\) 和右端点 \(R_i\) 排序,然后那么最后答案区间的并集中从左向右的第 \(i\) 个区间的大小就为 \(R_i-L_i+1\)。

还有一个问题是当 \(k=k_0\) 时,如何确定是否可以抓取所有的 \(n\) 个宝藏。

比较显然的是可以直接贪心从小到大排序每个宝藏到 \(k\) 的距离 \(|x_i-k|\) 和每个手臂最大能够到的距离 \(l_i\),然后让其一一配对。

那么我们就得到了一个 \(O(n^3 \log n)\) 的做法。


【思路二】

如果我们已经固定了 \(k\),那么就可以直接贪心从小到大排序每个宝藏到 \(k\) 的距离 \(|x_i-k|\) 和每个手臂最大能够到的距离 \(l_i\),然后让其一一配对。

由于 \(x_i\) 的范围太大,不可能直接从 \(-10^{18}\) 枚举到 \(10^{18}\),那么考虑优化。

由于最终答案区间是若干个区间的并,所以区间端点只有 \(n^2\) 级别。那么我们考虑怎么样的点 \(k_0\) 可以作为状态的分界点。

注:

这里状态的定义是指当机器人位于该点时,是否能抓取所有宝藏。

状态的分界点跟区间的端点不同。状态的分界点是指,当机器的位置从 \(k\) 变到 \(k+1\),\(k\) 是否能抓取宝藏与之前不变,但 \(k+1\) 与 \(k\) 的状态不同。

即有两种情况。\(k=k_0\) 可以抓取到所有的 \(n\) 个宝藏,\(k=k_0+1\) 不能抓取所有宝藏;或 \(k=k_0\) 不能抓取所有宝藏,\(k=k_0+1\) 能抓取所有宝藏。

考虑这两种情况:

  1. \(k=k_0\) 满足条件 \(k=k_0+1\) 不满足条件。

    那么一定存在宝藏 \(i\) 和手臂 \(j\) 使得 \(x_i-l_j \le k_0 \le x_i+l_j\) 且 \(k_0+1 > x_i+l_j\),解得 \(k_0=x_i+l_j\)。

  2. \(k=k_0\) 不满足条件 \(k=k_0+1\) 满足条件。

    那么一定存在宝藏 \(i\) 和手臂 \(j\) 使得 \(x_i - l_j \le k_0+1 \le x_i+l_j\) 且 \(k_0<x_i-l_j\)。解得 \(k_0=x_i-l_j-1\)。

所以当且仅当 \(k=x_i+l_j\) 和 \(x_i-l_j-1\) 才有可能是分界点。

那么我们将所有可能的端点排序后放入集合 \(S\) 中,相邻两个分界点内的点的状态一定相同。

枚举每一个可能的分界点 \(k_0\),若 \(k=k_0\) 时能抓取所有宝藏,那么它要么是分界点,即第一种情况,要么不是分界点(\(k=k_0+1\) 满足条件),但不管怎么样从这个点 \(S_i\) 到上一个可能分界点 \(S_{i-1}\) 的这段区域一定都能抓取所有宝藏。那么我们将这段区域的点累加入答案中即可。

时间复杂度同样是 \(O(n^3 \log n)\)。

代码实现

思路一
//F 解法二
//The Way to The Terminal Station…
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
const int maxn=205;
int l[maxn],x[maxn],t[maxn];
int n,ans;

vector<int>ls,rs;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

int check(int k)
{
	for(int i=1;i<=n;i++)t[i]=abs(k-x[i]);
	sort(t+1,t+n+1);
	for(int i=1;i<=n;i++)
	{
		if(t[i]<=l[i])continue;
		return 0;
	}
	return 1;
}

signed main()
{
	n=read();
	for(int i=1;i<=n;i++)x[i]=read();
	for(int i=1;i<=n;i++)l[i]=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			int L=x[i]-l[j],R=x[i]+l[j];
			if(check(L)&&(!check(L-1)))ls.push_back(L);
			if(check(R)&&(!check(R+1)))rs.push_back(R);
		}
	}
	sort(ls.begin(),ls.end());
	ls.erase(unique(ls.begin(),ls.end()),ls.end());
	sort(rs.begin(),rs.end());
	rs.erase(unique(rs.begin(),rs.end()),rs.end());
	for(int i=0;i<ls.size();i++)ans+=rs[i]-ls[i]+1;
	cout<<ans<<'\n';
}
思路二
//F
//The Way to The Terminal Station…
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
const int maxn=205;
int l[maxn],x[maxn],t[maxn];
int n;

vector<int>s;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

int check(int k)
{
	for(int i=1;i<=n;i++)t[i]=abs(k-x[i]);
	sort(t+1,t+n+1);
	for(int i=1;i<=n;i++)
	{
		if(t[i]<=l[i])continue;
		return 0;
	}
	return 1;
}

signed main()
{
	n=read();
	for(int i=1;i<=n;i++)x[i]=read();
	for(int i=1;i<=n;i++)l[i]=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			s.push_back(x[i]+l[j]);
			s.push_back(x[i]-l[j]-1);
		}
	}
	sort(s.begin(),s.end());
	int ans=0;
	for(int i=1;i<s.size();i++)
	{
		if(check(s[i]))ans+=s[i]-s[i-1];
	}
	cout<<ans<<'\n';
	return 0;
}

标签:ABC318F,le,int,题解,抓取,ch,区间,宝藏,Octopus
From: https://www.cnblogs.com/xrkforces/p/ABC318F.html

相关文章

  • [ABC319D] Minimum Width 题解
    [ABC319D]MinimumWidth题解题意分析  给定\(n\)个单词,现在想像“记事本”一样把它们依次地一行一行显示出来。每个字母宽度为一,单词之间需要有空格,宽度也为一。一个单词不可以成两部分显示在两行。如果单词最后一个字母来到行末,直接换行,不用空格。  给定窗口最大高度......
  • [JOISC 2016] 雇佣计划 题解
    [JOISC2016]雇佣计划题解这里补充一篇自己的\(n\logn\)做法。本蒟蒻打了两棵线段树,并且进行了繁琐的分类讨论,完全被标算的树状数组吊打qwq题意:给定一个序列\(a\),有两种操作:将\(c\)位置权值改为\(d\);给定一个权值\(b\),定义集合\(S=\{i|a_i\geb\}\),对于......
  • P8029 [COCI2021-2022#3] Akcija 题解
    注:这篇题解中涉及到的所有概念均会在其第一次出现时用斜体标出,有些概念给出了定义,而有些概念的含义请自行意会。定义状态为选了的物品数\(a\)与相应总价格\(b\)的二元组\((a,b)\)。相应地定义状态之间的大小关系、最优状态与状态和状态的加法运算\((a_1,b_1)+(a_2,b......
  • UVA1030 题解
    思路分析猜想我们可以在题目中看出一下几个突破口:能“看穿”的位置所对应的单位立方体是一定不存在的。如果前视图的右上角的颜色\(A\)和顶视图的的右下角颜色\(B\)不同,那么对应的格子就一定不存在。在删除这个立方体后,我们还可以发现,挖去立方体的左侧和\(B\)左侧的......
  • CF431B 题解
    思路分析答题思路一道纯暴力题!因为我们发现数据最大是\(5\),而枚举全排列的时间复杂度为\(\mathcalO(n!)\),对于这种极小的数据范围是丝毫不用顾虑的,因为我们只需要执行\(120\)次。如何快速求出一个数组的全排列?我们可以使用dfs,一层一层获取这个数组的全排列。但是STL......
  • CF387B 题解
    思路分析因为最终要使得\(a,b\)相同,所以我们应该希望让相同的数字尽量相同。所以,我们需要先对\(a\)和\(b\)进行排序,这样子就可以使用双指针的方法来维护最终值了。我们定义\(l\)指针指向\(a_l\),\(r\)指针指向\(b_r\)。因为题目要求添加数字的次数最少,所以我们希望尽......
  • P9516 题解
    思路分析一道很有洛谷个性的模拟签到题。按照题意,我们只需读入\(a,b,c,d,e\),然后对其进行求和,然后依次根据洛谷咕值系统介绍进行判断即可。这样是不是太没有意思了?今天为大家带来一点干货作为福利!介绍:accumulate()函数!简略分析:这个函数可以求出一段区间内的数字之和。S......
  • P9517 题解
    思路分析我们只需要找到左边第一个大于\(0\)的位置\(l\)与右边第一个大于\(0\)的位置\(r\),输出\(r-l+1\)即可。但是很坑的一点是,如果\(∀i∈[1,n],a_i=0\),那么\(l\)和\(r\)会重合,代码会输出\(1\)!所以,我们需要定义一个\(flag\)来标记是否全部输入为\(0\)。代......
  • UVA11210 题解
    思路分析一道大模拟。一共只有\(34\)种牌,因此可以一次判断是否“听”这些牌。比如,为了判断是否“听”一万,只需要判断自己拿到这张一万后能否可以继续和牌。这样,问题就转化成了给定\(14\)张牌,判断是否可以和牌。为此,我们可以递归求解:首先将两张牌作为“将”,然后每次选\(3\)......
  • UVA1352 题解
    思路分析构造排列表立方体只有\(4\)个,暴力法是可行的。但是如果我们要暴力,首先得清楚一个立方体到底有几种不同的旋转方式。接下来,我们用“姿态”一词代替“旋转方法”。假设\(6\)个面的编号为\(1\sim6\),从中选择一个面作为“顶面”,“顶面”的对面为“底面”。然后我们在......