BTS24

B. Back to School '24 P2 - Cheating

题目描述

\(N\) 道题,第 \(i\) 道题的分值为 \(A_i(A_1\le A_2\le \dots\le A_N)\),有 \(M\) 个学生,初始时分数均为 \(0\)。每次会让分数最低的 \(B_i\) 个同学获得 \(A_i\) 分,若有多个分数相同的学生,则让编号更小的学生获得 \(A_i\) 分。求最终每个学生的分数。

思路

由于 \(A_1\le A_2\le \dots \le A_N\),所以让一些学生获得 \(A_i\) 分后,一定比其他学生分都高,因此这些学生的分数一定是递增的。每次对一段区间加 \(A_i\) 即可。

时空复杂度均为 \(O(N+M)\)

代码

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

const int MAXN = 1000005;

int n, m, a[MAXN];
ll sum[MAXN];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
  }
  int pos = 0;
  for(int i = 1, x; i <= n; ++i) {
    cin >> x;
    sum[pos + 1] += a[i];
    sum[min(m + 1, pos + x + 1)] -= a[i];
    if(pos + x > m) {
      sum[1] += a[i], sum[pos + x - m + 1] -= a[i];
    }
    pos = (pos + x > m ? pos + x - m : pos + x);
  }
  for(int i = 1; i <= m; ++i) {
    cout << (sum[i] += sum[i - 1]) << " ";
  }
  return 0;
}

D. Back to School '24 P4 - Candidates

题目描述

\(N\)\(K\) 元组,我们将对其从大到小进行排序,有一个长度为 \(K\) 的排列 \(A\),代表排序时第 \(i\) 个关键字为 \(A_i\)。现在给出排序后的结果,求出字典序最小的 \(A\)

思路

显然第一关键字中 \(N\) 个元组必须单调不升。假如第一关键字为 \([3,2,2,1,1,1]\),那么这将会把数列分成三段,因为第一关键字已经确定不同段间的顺序,所以之后就不需要管断点了。

使用优先队列和拓扑排序求解即可。

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

代码

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

const int MAXN = 100001, MAXK = 300001;

int n, k, p[MAXN], cnt[MAXK];
bool flag[MAXN];
vector<int> a[MAXN], ans;
vector<bool> vis[MAXK];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> k;
  for(int i = 1; i <= n; ++i) {
    cin >> p[i];
  }
  for(int i = 1; i <= n; ++i) {
    a[i].resize(k + 1);
    for(int j = 1; j <= k; ++j) {
      cin >> a[i][j];
    }
  }
  priority_queue<int, vector<int>, greater<int>> pq;
  for(int i = 1; i <= k; ++i) {
    vis[i].resize(n + 1);
    for(int j = 1; j < n; ++j) {
      if(a[p[j]][i] >= a[p[j + 1]][i]) {
        cnt[i]++;
        vis[i][j] = 1;
      }
    }
    if(cnt[i] == n - 1) {
      pq.push(i);
    }
  }
  for(; !pq.empty(); ) {
    int x = pq.top();
    pq.pop();
    ans.emplace_back(x);
    for(int i = 1; i < n; ++i) {
      if(a[p[i]][x] > a[p[i + 1]][x] && !flag[i]) {
        flag[i] = 1;
        for(int j = 1; j <= k; ++j) {
          if(!vis[j][i]) {
            vis[j][i] = 1;
            cnt[j]++;
            if(cnt[j] == n - 1) {
              pq.push(j);
            }
          }
        }
      }
    }
  }
  if(ans.size() != k) {
    cout << -1;
  }else {
    for(int x : ans) {
      cout << x << " ";
    }
  }
  return 0;
}

E. Back to School '24 P5 - Snitching

题目描述

\(N\) 个学生,第 \(i\) 个学生指责学生 \(A_i\)。你要按顺序采访区间 \([l,r]\) 中的学生,并找到第一个被指责 \(k\) 次的学生。如果没有人被指责 \(k\) 次,输出 \(-1\)

思路

使用根号分治。

很容易发现这里 \(r\) 无关紧要,只需找到 \(l\) 后第一个出现 \(k\) 次的学生并判断是否 \(\le r\) 即可。

我们对查询的 \(l\) 从大到小处理。对于 \(k\le \sqrt N\) 的查询,我们令 \(nxt_i\) 表示下一个出现 \(i\) 次的元素位置,每次在开头加入元素时,先用 vector 记录下来,再把 \(\sqrt N\) 以内的 \(nxt_i\)vector 记录的信息全部更新。

对于 \(k> \sqrt N\) 的查询,至多有 \(\sqrt N\) 个数会出现 \(k\) 次,暴力枚举即可。

空间复杂度 \(O(N+Q)\),时间复杂度 \(O((N+Q)\sqrt N)\)

代码

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

const int MAXN = 500001, B = 708, MAXQ = 500001;

struct query {
  int l, r, k, id;
}s[MAXN];

int n, q, a[MAXN], cnt[MAXN], nxt[B + 1], ans[MAXQ];
vector<int> ve, pos[MAXN];

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> q;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
    cnt[a[i]]++;
  }
  for(int i = 1; i <= n; ++i) {
    if(cnt[i] > B) {
      ve.emplace_back(i);
    }
  }
  for(int i = 1; i <= q; ++i) {
    cin >> s[i].l >> s[i].r >> s[i].k;
    s[i].id = i;
  }
  sort(s + 1, s + q + 1, [](const query &a, const query &b) -> bool {
    return a.l < b.l;
  });
  for(int i = 1; i <= B; ++i) {
    nxt[i] = n + 1;
  }
  for(int i = q, j = n; i >= 1; --i) {
    for(; j >= 1 && j >= s[i].l; --j) {
      pos[a[j]].emplace_back(j);
      for(int k = 1; k <= min(B, int(pos[a[j]].size())); ++k) {
        nxt[k] = min(nxt[k], pos[a[j]][pos[a[j]].size() - k]);
      }
    }
    if(s[i].k <= B) {
      ans[s[i].id] = (nxt[s[i].k] <= s[i].r ? a[nxt[s[i].k]] : -1);
    }else {
      int ret = n + 1;
      for(int x : ve) {
        if(pos[x].size() >= s[i].k) {
          ret = min(ret, pos[x][pos[x].size() - s[i].k]);
        }
      }
      ans[s[i].id] = (ret <= s[i].r ? a[ret] : -1);
    }
  }
  for(int i = 1; i <= q; ++i) {
    cout << ans[i] << "\n";
  }
  return 0;
}
posted @ 2024-10-07 11:23  Yaosicheng124  阅读(3)  评论(0编辑  收藏  举报