A - AAA

POJ - 3321

给你一颗树,支持两种操作

1.修改某一节点的权值

2.查询子树的权值(子树中节点的个数)

很显然可以用树状数组/线段树维护

B - BBB

CodeForces - 978A

存一下出现次数即可

  1. int a[100], st[1100];
  2. int main() {
  3. cin.tie(nullptr)->sync_with_stdio(false);
  4. int n;
  5. cin >> n;
  6. int cnt = 0;
  7. for (int i = 1; i <= n; ++i) {
  8. cin >> a[i];
  9. st[a[i]] += 1;
  10. }
  11. for (int i = 1; i <= 1000; ++i) if (st[i]) cnt += 1;
  12. cout << cnt << "\n";
  13. int ccnt = 0;
  14. for (int i = 1; i <= n; ++i) {
  15. if (st[a[i]] == 1) {
  16. cout << a[i];
  17. ccnt += 1;
  18. if (ccnt != cnt)cout << " ";
  19. } else st[a[i]] -= 1;
  20. }
  21. }

C - CCC

CodeForces - 978C

两种做法,写前缀和 + 二分就找到楼层序号位置

  1. const int N = 2e5 + 10;
  2. ll a[N], s[N];
  3. int n, m;
  4. int main() {
  5. cin.tie(nullptr)->sync_with_stdio(false);
  6. cin >> n >> m;
  7. for (int i = 1; i <= n; ++i) cin >> a[i], s[i] = s[i - 1] + a[i];
  8. while (m--) {
  9. ll t; cin >> t;
  10. int l = 1, r = n, cnt = 0;
  11. while (l <= r) {
  12. int mid = (l + r) / 2;
  13. if (s[mid] < t) l = mid + 1, cnt = mid;
  14. else r = mid - 1;
  15. }
  16. cout << cnt + 1 << " " << t - s[cnt] << "\n";
  17. }
  18. }

D - DDD

CodeForces - 978D

题意:
给你一组数,然后给你三种操作,分别是+1,-1,不变,然后判断能否通过操作将这组数变成等差数列,若能则输出最小改变次数,若不行则输出-1。
思路:
乍一看题,以为是DFS的题,使劲想怎么搜,后来搜超时了555。下面说正解,其实根据等差数列的性质,只需要处理前两项枚举所有可能结果,暴力找出最小次数即可。

  1. const int N = 1e5 + 10, inf = 0x3f3f3f3f;
  2. ll a[N], b[N];
  3. int n;
  4. int main() {
  5. cin.tie(nullptr)->sync_with_stdio(false);
  6. cin >> n;
  7. for (int i = 0; i < n; ++i) cin >> a[i];
  8. int cnt = inf;
  9. for (int i = -1; i <= 1; ++i)
  10. for (int j = -1; j <= 1; ++j) {
  11. b[0] = a[0] + i;
  12. b[1] = a[1] + j;
  13. int d = b[1] - b[0];
  14. bool f = false;
  15. int t = abs(i) + abs(j);
  16. for (int r = 2; r < n; ++r) {
  17. b[r] = b[r - 1] + d;
  18. if (abs(b[r] - a[r]) > 1) {f = true; break;}
  19. else {
  20. if (b[r] != a[r]) t += 1;
  21. }
  22. }
  23. if (!f) cnt = min(cnt, t);
  24. }
  25. if (cnt == inf) cout << "-1\n";
  26. else cout << cnt << "\n";
  27. }

E - EEE

CodeForces - 978E

题意:

给你一个含有n个整数的数组,每一个数a[i]代表汽车在站i时,车上增多了a[i]个人,如果a[i]为负,代表减少了人数。

并告诉你这个汽车的最大承载力为w个人,

请你判断初始时汽车上有多少个人,才满足整个数组的情况,。

如果某一个情况,车上的人数为负,或者人数大于w,那么说明这个数组时不合理的,。这时请输出0

思路:

可以抽象为,求这个数组的前缀和数组中的最大值和最小值,。只要最大值不大于容量,再判断下最低值的绝对值不大于容量。就可以说明是合理的。

然后可以的方案数中初始的人数一定是连续的,那么这些人数中的最大值是 Codeforces Round #481 (Div. 3) 经典几道思维题 GOod - 图1#card=math&code=min%28w-maxsum%2Cw%29) ,即不让过程中容量大于 Codeforces Round #481 (Div. 3) 经典几道思维题 GOod - 图2 的最大值。

最小值是 Codeforces Round #481 (Div. 3) 经典几道思维题 GOod - 图3#card=math&code=max%280%2C-1%2Aminsum%29),然后最大值减去最小值 Codeforces Round #481 (Div. 3) 经典几道思维题 GOod - 图4 就是答案了。

  1. const int N = 1e3 + 10;
  2. ll a[N], s[N];
  3. int main() {
  4. cin.tie(nullptr)->sync_with_stdio(false);
  5. ll n, m; cin >> n >> m;
  6. ll sum = 0, Max = 0, Min = 0;
  7. for (int i = 1; i <= n; ++i) {
  8. cin >> a[i];
  9. sum += a[i];
  10. Max = max(sum, Max);
  11. Min = min(sum, Min);
  12. }
  13. if (Min < 0) Min = llabs(Min);
  14. sum = m - Max - Min + 1;
  15. if (sum < 0) cout << 0 << "\n";
  16. else cout << sum << "\n";
  17. }

F - FFF

CodeForces - 978F

题意:

给定 Codeforces Round #481 (Div. 3) 经典几道思维题 GOod - 图5 个人员skill值,并给出 Codeforces Round #481 (Div. 3) 经典几道思维题 GOod - 图6 个有矛盾的对,对于每个人,可以做skill值比自己小且没有矛盾人的导师。输出每一个人可做多少人的导师。

思路:

  • 排序后对每个人的skill值二分查找,存储到ans[]中。
  • 对于每个矛盾对,skill值大的ans减1即可。
  1. const int N = 2e5 + 10;
  2. ll a[N], b[N], c[N];
  3. int n, m;
  4. int main() {
  5. cin.tie(nullptr)->sync_with_stdio(false);
  6. cin >> n >> m;
  7. for (int i = 1; i <= n; ++i) cin >> a[i], b[i] = a[i];
  8. while (m--) {
  9. int x, y;
  10. cin >> x >> y;
  11. if (a[x] > a[y]) c[x] += 1;
  12. else c[y] += 1;
  13. }
  14. sort(b + 1, b + 1 + n);
  15. for (int i = 1; i <= n; ++i) {
  16. int t = lower_bound(b + 1, b + 1 + n, a[i]) - b - 1;
  17. cout << t - c[i] << " ";
  18. }
  19. }

G - GGG

CodeForces - 978G

题意:

给你N天,和M个考试,

每一个考试有三个参数。

s是考试可以开始准备的日期。

e是考试日期(这一天必须考试,不能准备)

v,这个考试需要多少天。

每一天最多只能做一件事,要么这一天休息,要么准备考试,要么参加考试。

每一个考试必须在考试之前严格的准备了v天才能通过。

请你确定你是否能能过这M个考试,

如果不可以,只需要输出-1

否则输出每一天i是做什么事情,休息是0,考试是m+1,准备是准备的那个考试编号。

思路:

贪心题,

按照每一个考试的考试日期由近到远排序。

然后枚举每一个天,1~n

如果这一天没有被使用,去检查最近1~m哪一个考试在第 i 天准备。

如果可以填就填,这样贪心搞。

  1. const int N = 1e2 + 10;
  2. struct node {int s, d, c, id;} p[N];
  3. int n, m, Day[N];
  4. bool cmp(node a, node b) {return a.d < b.d;}
  5. int main() {
  6. cin.tie(nullptr)->sync_with_stdio(false);
  7. cin >> n >> m;
  8. for (int i = 1; i <= m; ++i) {
  9. cin >> p[i].s >> p[i].d >> p[i].c;
  10. p[i].id = i;
  11. Day[p[i].d] = m + 1;
  12. }
  13. sort(p + 1, p + 1 + m, cmp);
  14. for (int i = 1; i <= m; ++i) {
  15. int day = 0;
  16. for (int j = p[i].s; j <= n; ++j) {
  17. if (Day[j] == 0) day += 1, Day[j] = p[i].id;
  18. if (day == p[i].c) break;
  19. if (j >= p[i].d) {
  20. cout << -1 << "\n";
  21. return 0;
  22. }
  23. }
  24. }
  25. for (int i = 1; i <= n; ++i) cout << Day[i] << " \n"[i == n];
  26. }