Loading

2022.10.22 总结

1. 逐月 P5101

逐月 P5101

题意

每天都有 \(n\) 头奶牛会在农场中过马路,第 \(i\) 头奶牛会从 \((a_i, 0)\) 走到 \((b_i, 0)\)

当一头奶牛的行走路线不会和任意一头奶牛的路线相交时,这头奶牛就是 安全的

请你求出这 \(n\) 头奶牛中,有多少头奶牛是安全的。

思路

58 分

首先,要知道什么样的路线算作相交。

\(a_i < a_j, b_i > b_j\) 时,这两条路线是相交的。

所以可以直接暴力枚举两头奶牛的路线,直接判断即可。

时间复杂度

枚举两头奶牛,\(O(n ^ 2)\)

空间复杂度

数组存储 \(a_i\)\(b_i\)\(O(n)\)

100 分

在暴力上加上前缀后缀优化即可。

\(i\) 是安全的奶牛且已经按照 \(a_i\) 从小到大排序时,\(\max \{b_j\} < b_i, \min \{b_k\} > b_i\) \(j < i, k > i\)

就这样。

时间复杂度

排序,\(O(n \log n)\)

前缀最大值和后缀最小值,\(O(n)\)

求答案,\(O(n)\)

总时间复杂度为 \(O(n)\)

空间复杂度

数组记录前缀最大值和后缀最小值,\(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int n, sum1[N], sum2[N], cnt;

struct C{
  int a, b;
} a[N];

bool cmp(const C &i, const C &j){
  return i.a < j.a;
}

int main(){
  freopen("crossings.in", "r", stdin);
  freopen("crossings.out", "w", stdout);
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i].a >> a[i].b;
  }
  sort(a + 1, a + n + 1, cmp);
  sum1[0] = INT_MIN;
  for (int i = 1; i <= n; i++) {
    sum1[i] = max(sum1[i - 1], a[i].b);
  }
  sum2[n + 1] = INT_MAX;
  for (int i = n; i >= 1; i--) {
    sum2[i] = min(sum2[i + 1], a[i].b);
  }
  for (int i = 1; i <= n; i++) {
    cnt += (sum1[i - 1] <= a[i].b && sum2[i + 1] >= a[i].b);
  }
  cout << cnt;
  return 0;
}

2. 逐月 P5082

逐月 P5082

题意

有一个有 \(w\) 个单词的字典,还有 \(n\) 次查询,每次查询会给出 \(k\) 和前缀 \(i\),也就是要查询有前缀 \(i\) 的按字典序排列的第 \(k\) 个单词,如果没有,输出 \(-1\)

思路

70 分

先按照字典序排序,排序暴力做 \(n\) 次查询,每次枚举所有的单词,找到满足要求的。

时间复杂度

排序,\(O(w \log w)\)

查询,\(O(n)\)

寻找,\(O(w \times 20)\),前缀长度不会超过 \(20\)

总时间复杂度为 \(O(w \log w + n \times w)\)

空间复杂度

存储 \(w\) 个单词,\(O(w)\)

100 分

因为每次都是从头开始找单词的,时间复杂度太高了,所以要降低这里。

首先,因为是按照字典序排序,所以有同样前缀的单词在排好序的单词序列中一定是连续的一段。

那么,如果给出的 \(n\) 段前缀也是按照字典序排序的,那么每次就只要从上一次查询到的位置开始找即可。

但是,前缀并不是按照字典序排序的,所以需要把所有的前缀先按字典序排一遍序,再求解。

时间复杂度

排序单词,\(O(w \log w)\)

排序前缀,\(O(n \log n)\)

求解,\(O(n \times 20 + w)\)

空间复杂度

存储 \(w\) 个单词,\(O(w)\)

存储前缀,\(O(n)\)

记录答案,\(O(n)\)

总空间复杂度为 \(O(w + n)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int W = 1e6 + 10, N = 1e4 + 10;

int w, n, ans[N];

struct wr{
  string s;
  int id, k;
} s[W], q[N];

bool cmp(const wr &i, const wr &j){
  if (i.s == j.s) {
    return i.id < j.id;
  }
  return i.s < j.s;
}

bool P(const string &i, const string &j){  // 判断前缀
  int a = i.size(), b = j.size();
  if (a < b) {
    return 0;
  }
  for (int k = 0; k < b; k++) {	
    if (i[k] != j[k]) {
      return 0;
    }
  }
  return 1;
}

int main(){
  freopen("auto.in", "r", stdin);
  freopen("auto.out", "w", stdout);
  cin >> w >> n;
  for (int i = 1; i <= w; i++) {
    cin >> s[i].s;
    s[i].id = i;
  }
  sort(s + 1, s + w + 1, cmp);
  for (int i = 1; i <= n; i++) {
    cin >> q[i].k >> q[i].s;
    q[i].id = i;
  }
  sort(q + 1, q + n + 1, cmp);
  for (int i = 1, j = 1; i <= n; i++) {
    for ( ; j <= w && s[j].s < q[i].s; j++) {  
			
    }
    int _ = j + q[i].k - 1;
    ans[q[i].id] = (_ <= w && P(s[_].s, q[i].s) ? s[_].id : -1);  // 记录答案
  }
  for (int i = 1; i <= n; i++) {
    cout << ans[i] << endl;
  }
  return 0;
}
posted @ 2023-03-02 22:44  chengning0909  阅读(12)  评论(0编辑  收藏  举报