专栏文章
题解:AT_joisc2017_c 手持ち花火 (Sparklers)
AT_joisc2017_c题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio8dnkr
- 此快照首次捕获于
- 2025/12/02 15:02 3 个月前
- 此快照最后确认于
- 2025/12/02 15:02 3 个月前
AT_joisc2017_c 手持ち花火
前言
校内模拟赛搬了这道题,来写个题解。
正文
最优的方法是所有人朝着 走,与 相遇时就一起走,当 的火把熄灭时再把其他同位置的一个火把点燃,相当于每个火把加了 秒的总燃烧时间。因为所有人速度一样,因此相对位置不会变,即 时,若 能被点燃,那 也一定会被点燃过,右侧同理。得出可点燃的火把一定是一个区间 。
接下来求区间 能否能拓展至 或 。首先考虑 是否合法,若全都能点燃,其总燃烧时长为 秒(最后一个点燃后直接结束),而所有的人聚在一起的时间即为 与 相遇的时间(所有人的相对位置不变),即 。得到不等式 ,当满足该不等式时,区间 是合法的。
继续拆解不等式,得到 。
发现 具有单调性(若 可行则 也可行),因此考虑二分。于是问题就变成了给定一个非负整数 ,初始 ,每次可以 或 ,且需满足 ,问是否可拓展至 。
AC Code
CPP#include <bits/stdc++.h>
#define int __int128
using namespace std;
const int N = 1e5 + 5 , inf = 1e18 + 7 , INF = inf * inf;
int x[N];
namespace Check
{
int n , m;
int a[N] , b[N] , prex1[N] , prey1[N] , nxtx1[N] , nxty1[N] , prex2[N] , prey2[N] , nxtx2[N] , nxty2[N];
bool check1 (int px , int py)
{
if (px == 0 || py == 0) return 1;
if (a[prex2[px]] < b[prey2[py]]) return check1 (prex2[px] - 1 , py);
if (a[prex1[px]] < b[prey1[py]]) return check1 (px , prey1[py] - 1);
return 0;
}
bool check2 (int px , int py)
{
if (px == n + 1 || py == m + 1) return 1;
if (a[nxtx2[px]] < b[nxty2[py]]) return check2 (nxtx2[px] + 1 , py);
if (a[nxtx1[px]] < b[nxty1[py]]) return check2 (px , nxty1[py] + 1);
return 0;
}
bool check (int p , int siz , int t , int v)
{
a[0] = b[0] = -INF;
n = p , m = siz - p + 1;
a[n + 1] = b[m + 1] = INF;
for (int i = p;i >= 1;i --) a[p - i + 1] = 2 * t * v * i - x[i];
for (int i = p;i <= siz;i ++) b[i - p + 1] = 2 * t * v * i - x[i] + 1;
prex2[0] = nxtx2[n + 1] = n + 1 , prey2[0] = nxty2[m + 1] = m + 1;
for (int i = 1;i <= n;i ++)
{
prex1[i] = prex1[i - 1];
if (a[prex1[i]] < a[i]) prex1[i] = i;
prex2[i] = prex2[i - 1];
if (a[prex2[i]] > a[i]) prex2[i] = i;
}
for (int i = n;i >= 1;i --)
{
nxtx1[i] = nxtx1[i + 1];
if (a[nxtx1[i]] < a[i]) nxtx1[i] = i;
nxtx2[i] = nxtx2[i + 1];
if (a[nxtx2[i]] > a[i]) nxtx2[i] = i;
}
for (int i = 1;i <= m;i ++)
{
prey1[i] = prey1[i - 1];
if (b[prey1[i]] < b[i]) prey1[i] = i;
prey2[i] = prey2[i - 1];
if (b[prey2[i]] > b[i]) prey2[i] = i;
}
for (int i = m;i >= 1;i --)
{
nxty1[i] = nxty1[i + 1];
if (b[nxty1[i]] < b[i]) nxty1[i] = i;
nxty2[i] = nxty2[i + 1];
if (b[nxty2[i]] > b[i]) nxty2[i] = i;
}
if (a[prex2[n]] >= b[prey2[m]] || b[prey1[m]] <= a[prex1[n]]) return 0;
return check1 (n , m) && check2 (1 , 1);
}
}
int n , k , t;
void read (int &X)
{
long long A;
cin >> A;
X = A;
}
signed main ()
{
ios::sync_with_stdio(0); cin.tie(0),cout.tie(0);
read (n) , read (k) , read (t);
for (int i = 1;i <= n;i ++)
read (x[i]);
int l = 0 , r = 1e9 , mid;
while (l < r)
{
mid = l + r >> 1;
if (Check::check (k , n , t , mid)) r = mid;
else l = mid + 1;
}
cout << (long long)r;
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...