EGOI

QOJ 9182

题目描述

在一个环形跑道上,有 \(N\) 名参赛者,分别编号 \(0\)\(N-1\),你的编号为 \(0\)。一开始所有参赛者都在起跑线后,你是其中最靠后的一个。就像这样:

\includegraphics[width=0.7\textwidth ]{track}

你知道在什么时候你超越了 \(A\),或 \(A\) 超越了你。并且这些超越都不会在起跑线上发生。

没有人往后跑,并且参赛者的速度不恒定。求你至少越过了几次起跑线。

思路

我们记录哪些人还在你前面(你到起跑线之间)。如果你超过了在你前面的人,那么他就会到你后面。但如果你超越了在你后面的人,则说明你越过了一次起跑线,并且所有人都在你前面,除了你超过的人。

时空复杂度 \(O(Q)\)

代码

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 200001;

int n, q, ans, vis[MAXN], tot = 1;

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> q;
  for(int i = 1, x; i <= q; ++i) {
    cin >> x;
    if(x < 0) {
      vis[-x] = 0;
    }else if(vis[x] == tot) {
      ans++;
      tot++;
      vis[x] = tot;
    }else {
      vis[x] = tot;
    }
  }
  cout << ans;
  return 0;
}

QOJ 9183

题目描述

有一排 \(N\) 朵花。如果你摘了第 \(i\) 朵花,那么它左边 \(l_i\) 朵,右边 \(r_i\) 朵花都不能摘。求最多能摘多少朵花。

思路

\(dp_i\) 表示最后摘下的花为 \(i\) 时最多能摘多少朵花。

如果 \(j>i+r_i 且 i<j-l_j\),那么 \(dp_j\leftarrow dp_i+1\)

由于要同时维护两个东西,所以我们一个直接用下标,另一个用树状数组维护。

我们在 \(i+r_i+1\) 的位置插入 \((dp_i,i)\)。这样就满足了第一个条件。

而第二个条件就可以用树状数组记录前缀最大值即可。

空间复杂度 \(O(N)\),时间复杂度 \(O(N\log N)\)

代码

#include<bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;

const int MAXN = 200005;

int n, l[MAXN], r[MAXN], dp[MAXN], tr[MAXN], ans;
vector<pii> ve[MAXN];

int lowbit(int x) {
  return x & -x;
}

void update(int p, int x) {
  for(; p <= n; tr[p] = max(tr[p], x), p += lowbit(p)) {
  }
}

int Getsum(int p) {
  int sum = 0;
  for(; p; sum = max(sum, tr[p]), p -= lowbit(p)) {
  }
  return sum;
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n;
  for(int i = 1, l, r; i <= n; ++i) {
    cin >> l >> r;
    for(auto [id, val] : ve[i]) {
      update(id, val);
    }
    dp[i] = Getsum(max(0, i - l - 1)) + 1;
    ans = max(ans, dp[i]);
    if(i + r + 1 <= n) {
      ve[i + r + 1].emplace_back(i, dp[i]);
    }
  }
  cout << ans;
  return 0;
}
posted @ 2024-09-25 20:41  Yaosicheng124  阅读(7)  评论(0编辑  收藏  举报