第二题:CANNONBALL
标签:模拟
题意:给定一个从左往右
1
,
2
,
.
.
.
,
N
1,2,...,N
1,2,...,N标记的数轴,从其中某个位置
S
S
S开始往右跳,初始能量为
1
1
1。如果当前能量为
k
k
k,将会从当前位置往前跳
k
k
k的距离。
每个标记的位置,要么是跳板,要么是靶子,每个位置都有值
v
i
v_i
vi。
跳板:跳到跳板上,当这个位置的值是
v
i
v_i
vi,当前能量会增加
v
i
v_i
vi,并反转跳的方向。
靶子:跳到靶子上,如果当前能量大于等于 当前位置的值
v
i
v_i
vi,将会打破靶子,靶子被破坏掉后,将会一直维持破坏的状态,下次跳到这个位置无法被打破。
假设可以跳无限长的时间,或者离开数轴位置,能打破多少个靶子?(
1
<
=
N
<
=
1
0
5
1<=N<=10^5
1<=N<=105)
题解:维持当前朝向
d
i
r
dir
dir,当前能量
e
n
e
r
g
y
energy
energy,模拟跳的过程,当跳的过程中
s
<
1
s<1
s<1或者
s
>
n
s>n
s>n结束。每次按照规则进行模拟跳,跳板的时候增加能量值,反转跳的方向,打靶的时候标记一下靶子是否被破坏过。
如果在同一个能量值跳到 某个位置 两次,那么可以得到以后的循环不会有新的靶子被破坏,再之后就是重复新的一轮了。小估估一下时间复杂度,让它尽量跳,超出轮数默认不会再产生新的打破靶子数。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, s, q[N], v[N], ans = 0;
bool vis[N];
int main() {
cin >> n >> s;
for (int i = 1; i <= n; i++) {
cin >> q[i] >> v[i];
}
int energy = 1, dir = 1; // 能量、朝向
for (int i = 1; i <= 1000 * N; i++) {
if (q[s] == 0) { // 跳板
energy += v[s];
dir *= -1;
}
else { // 靶子
if (!vis[s] && energy >= v[s]) {
vis[s] = 1;
ans++;
}
}
s += dir * energy;
if (s < 1 || s > n) break;
}
cout << ans << endl;
return 0;
}