「题解」Codeforces Round 895 (Div. 3)

A. Two Vessels

Problem

题目

Sol & Code

签到题

#include <bits/stdc++.h>

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T, a, b, c;

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d %d", &a, &b, &c);
    double res = std::abs(b - a) / 2.0;
    printf("%d\n", (int)std::ceil(res / c));
  }
  return 0;
}

B. The Corridor or There and Back Again

Problem

题目

Sol & Code

对于每个陷阱(不考虑其他陷阱)求最多能平安到达的位置,最后对每个陷阱取最小值。

#include <bits/stdc++.h>
#define N 101

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T, n, a[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1, x, y; i <= n; ++i) {
      scanf("%d %d", &x, &y);
      a[i] = x + (int)std::floor((y - 1) / 2.0);
    }
    int ans = 114514;
    for (int i = n; i >= 1; --i) ans = min(ans, a[i]);
    printf("%d\n", ans);
  }
  return 0;
}

C. Non-coprime Split

Problem

题目

Sol & Code

考虑 \([l,r]\) 这个区间的长度。若长度为 \(2\)\(l,r\) 一奇一偶,讨论可知 \([1,2],[2,3]\) 无解,其他情况答案可为将 \(l,r\) 中偶数分为两半。
若长度为 \(3\),讨论可知 \([1,3]\) 无解,有解的情况答案容易得出不再详细说。长度大于 \(3\) 肯定有解,答案也容易得出。若长度为 \(1\),考虑是 \(a+b =l\) 的情况,若 \(gcd(a,b) = 1\) 说明\(a,b\) 无公共质因数,可以根据算数基本定理可知不存在整除 \(l\) 且小于 \(l\) 的质数故 \(l\) 为质数,有解的情况即 \(l\) 不为质数,找个公共的质因子 \(p\),令 \(a = p,b = l - p\) 即可。

#include <bits/stdc++.h>
#define N 10000001

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

bool vis[N];
int T, l, r, cnt, pri[N];

int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }

void getprime() {
  for (int i = 2; i < N; ++i) {
    if (!vis[i]) pri[++cnt] = i;
    for (int j = 1; j <= cnt; ++j) {
      if (1ll * i * pri[j] >= N) break;
      vis[i * pri[j]] = true;
      if (i % pri[j] == 0) break;
    }
  }
}

int main() {
  scanf("%d", &T);
  getprime();
  while (T--) {
    scanf("%d %d", &l, &r);
    if (r - l + 1 == 3) {
      if (l == 1) puts("-1");
      else {
        if (l & 1) printf("%d %d\n", (l + 1) / 2, (l + 1) / 2);
        else printf("%d %d\n", (l + 2) / 2, (l + 2) / 2);
      }
    } else if (r - l + 1 == 2) {
      if (l == 1 || l == 2) puts("-1");
      else {
        if (l & 1) printf("%d %d\n", (l + 1) / 2, (l + 1) / 2);
        else printf("%d %d\n", l / 2, l / 2);
      }
    } else if (l == r) {
      if (l & 1) {
        if (vis[l]) {
          int prt = 0;
          for (int i = 1; i <= cnt; ++i) {
            if (l % pri[i] == 0) {
              if ((l / pri[i]) & 1) { prt = pri[i]; break; }
            }
          }
          if (!prt) puts("-1");
          else printf("%d %d\n", prt, l - prt);
        } else puts("-1");
      } else {
        if (l != 2) printf("%d %d\n", l / 2, l / 2);
        else puts("-1");
      }
    } else {
      if (r & 1) printf("%d %d\n", (r - 1) / 2, (r - 1) / 2);
      else printf("%d %d\n", r / 2, r / 2);
    }
  }
  return 0;
}

D. Plus Minus Permutation

Problem

题目

Sol & Code

根据题意可知 \(x\) 的贡献有 \(\lfloor \dfrac{n}{x}\rfloor\) 个数记作 \(a\)\(y\) 的贡献有 \(\lfloor \dfrac{n}{x}\rfloor\) 个数记作 \(b\),其中两者共同的贡献有 \(\lfloor \dfrac{n}{\operatorname{lcm}(x,y)}\rfloor\)(其中 \(\operatorname{lcm}(x,y)\)\(x,y\) 的最小公倍数)个数记作 \(c\)

所以答案为 \(n + (n - 1) + \dots + [n - (a - c) + 1] - [1 + 2 + \dots + (b - c)]\)

#include <bits/stdc++.h>

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T;
ll n, x, y;

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } 
ll lcm(ll a, ll b) { return a / gcd(a, b) * b; }

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%lld %lld %lld", &n, &x, &y);
    ll num1 = n / x - n / lcm(x, y), num2 = n / y - n / lcm(x, y);
    printf("%lld\n", (n + n - num1 + 1) * num1 / 2 - (1 + num2) * num2 / 2);
  }
  return 0;
}

E. Data Structures Fan

Problem

题目

Sol & Code

线段树可做

#include <bits/stdc++.h>
#define N 100001
#define lson now << 1
#define rson now << 1 | 1 

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

std::string s;
int T, n, q, w[N];
struct Node {
  int l, r, xor0, xor1, lazy;
}t[N << 2];

void build(int l, int r, int now) {
  t[now].l = l, t[now].r = r, t[now].xor0 = 0, t[now].xor1 = 0, t[now].lazy = 0;
  if (l == r) {
    if (s[l - 1] == '0') t[now].xor0 = w[l];
    else t[now].xor1 = w[l];
    return;
  }
  int mid = (l + r) >> 1;
  build(l, mid, lson), build(mid + 1, r, rson);
  t[now].xor0 = t[lson].xor0 ^ t[rson].xor0;
  t[now].xor1 = t[lson].xor1 ^ t[rson].xor1;
}

void pushdown(int now) {
  if (t[now].l == t[now].r) return;
  t[lson].lazy ^= 1, t[rson].lazy ^= 1;
  int tmp1 = t[lson].xor0, tmp2 = t[rson].xor0;
  t[lson].xor0 = t[lson].xor1, t[lson].xor1 = tmp1;
  t[rson].xor0 = t[rson].xor1, t[rson].xor1 = tmp2;
  t[now].lazy = 0;
}

void fix(int x, int y, int now) {
  if (t[now].l >= x && t[now].r <= y) {
    t[now].lazy ^= 1;
    int tmp = t[now].xor0;
    t[now].xor0 = t[now].xor1;
    t[now].xor1 = tmp;
    return ;
  }
  if (t[now].lazy) pushdown(now);
  int mid = (t[now].l + t[now].r) >> 1;
  if (x <= mid) fix(x, y, lson);
  if (y > mid) fix(x, y, rson);
  t[now].xor0 = t[lson].xor0 ^ t[rson].xor0;
  t[now].xor1 = t[lson].xor1 ^ t[rson].xor1;
}

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &w[i]);
    std::cin >> s;
    build(1, n, 1);
    scanf("%d", &q);
    for (int i = 1, opt, x, y; i <= q; ++i) {
      scanf("%d %d", &opt, &x);
      if (opt == 1) {
        scanf("%d", &y);
        fix(x, y, 1);
      } else printf("%d ", x ? t[1].xor1 : t[1].xor0);
    }
    puts("");
  }
  return 0;
}

F. Selling a Menagerie

Problem

题目

sol&Code

如果 \(a\) 害怕 \(b\) 则由 \(a\)\(b\) 连边。之后拓扑序 \(dp\) 可解。

#include <bits/stdc++.h>
#define N 100001

typedef long long ll;

int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }

int T, n, c[N], f[N], rd[N];
int head = 1, tail, q[N];

void solve(int u) {
  int minn = c[u], flag = u, now = f[u];
  while (now != u) {
    if (c[now] < minn) {
      minn = c[now];
      flag = now;
    }
    now = f[now];
  }
  now = f[flag];
  while (now !=flag) {
    --rd[now];
    printf("%d ", now);
    now = f[now];
  }
  --rd[now];
  printf("%d ", now);
}

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
      scanf("%d", &f[i]);
      ++rd[f[i]];
    }
    head = 1, tail = 0;
    for (int i = 1; i <= n; ++i) {
      if (rd[i] == 0) q[++tail] = i;
      scanf("%d", &c[i]);
    }
    while (head <= tail) {
      int tp = q[head++];
      --rd[f[tp]];
      if (rd[f[tp]] == 0) q[++tail] = f[tp];
      printf("%d ", tp);
    }
    for (int i = 1; i <= n; ++i) {
      if (rd[i] != 0) solve(i);
    }
    puts("");
  }
  return 0;
}

G. Replace With Product

Problem

题目

Sol & Code

全部加和的最大值 \(max = 200000000000000\)

用这个最大值除以非 \(1\) 的数,如果小于等于 \(1\) 了就说明乘积的贡献非常大,就将除去两侧 \(1\) 的部分做乘积。

\(max\) 约为 \(2^{48}\) 说明不符合上述情况的数列,非 \(1\) 的数最多 \(47\) 个。

\(47^2\) 的时间枚举左右边界取最大即可。

枚举

#include <bits/stdc++.h>
#define N 200001

int T, n, cnt, a[N], p[N];
long long premul[N], presum[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    premul[0] = 1, presum[0] = 0, cnt = 0;
    for (int i = 1; i <= n; ++i) {
      scanf("%d", &a[i]);
      if (a[i] > 1) p[++cnt] = i;
      premul[i] = premul[i - 1] * a[i];
      presum[i] = presum[i - 1] + a[i];
    }
    bool okay = false;
    double now = 200000000000000;
    for (int i = 1; i <= cnt; ++i) {
      now /= a[p[i]] * 1.0;
      if (now <= 1.0) okay = true;
    }
    if (cnt >= 48 || okay) {
      int l = 0, r = 0;
      for (int i = 1; i <= n; ++i) {
        if (a[i] != 1) { l = i; break; }
      }
      for (int i = n; i; --i) {
        if (a[i] != 1) { r = i; break; }
      }
      printf("%d %d\n", l, r);
    } else {
      long long maxx = presum[n], l = 1, r = 1;
      for (int i = 1; i <= cnt; ++i) {
        for (int j = i; j <= cnt; ++j) {
          if (presum[n] - presum[p[j]] + presum[p[i] - 1] + premul[p[j]] / premul[p[i] - 1] > maxx) {
            maxx = presum[n] - presum[p[j]] + presum[p[i] - 1] + premul[p[j]] / premul[p[i] - 1];
            l = p[i], r = p[j];
          }
        }
      }
      printf("%lld %lld\n", l, r);
    }
  }
  return 0;
}

总结

C. 分类讨论好像复杂了。

E. 现在是只会暴力数据结构的 fw 了(甚至数据结构都不会),异或前缀和。

posted @ 2023-10-01 16:07  yu__xuan  阅读(24)  评论(0编辑  收藏  举报