第二题:CANNONBALL
标签:模拟
题意:给定一个从左往右1,2,...,N1,2,...,N1,2,...,N标记的数轴,从其中某个位置SSS开始往右跳,初始能量为111。如果当前能量为kkk,将会从当前位置往前跳kkk的距离。
每个标记的位置,要么是跳板,要么是靶子,每个位置都有值viv_ivi。
跳板:跳到跳板上,当这个位置的值是viv_ivi,当前能量会增加viv_ivi,并反转跳的方向。
靶子:跳到靶子上,如果当前能量大于等于 当前位置的值viv_ivi,将会打破靶子,靶子被破坏掉后,将会一直维持破坏的状态,下次跳到这个位置无法被打破。
假设可以跳无限长的时间,或者离开数轴位置,能打破多少个靶子?(1<=N<=1051<=N<=10^51<=N<=105)
题解:维持当前朝向dirdirdir,当前能量energyenergyenergy,模拟跳的过程,当跳的过程中s<1s<1s<1或者s>ns>ns>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;
}