10.2 总结

T1 躲避技能

赛时拿的是暴力的 \(40\) 分,没开 long。

40pts

用 LCA 乱搞,枚举每一个人去哪里,复杂度 \(\mathcal O(m! \log n)\)

AC

给每一个躲避点打上 \(-1\) 标记,当前点打上 \(1\) 标记,每一次向上转移边长乘子树标记和绝对值即可。

#include <string.h>
#include <algorithm>
#include <fstream>
#include <vector>

using namespace std;
class BigInt {
 private:
  static const int kMaxN = 201;
  int Len = 0, Num[kMaxN] = {};
  bool Neg = 0;

 public:
  BigInt() {
    Len = 0, Neg = 0;
    fill(Num, Num + kMaxN, 0);
  }
  BigInt(string WUYIXUAN_) {
    if (WUYIXUAN_[0] == '-') {
      WUYIXUAN_ = WUYIXUAN_.substr(1);
      Neg = 1;
    }
    Len = WUYIXUAN_.size();
    for (int i = 1, j = Len - 1; i <= Len; i++, j--) {
      Num[i] = WUYIXUAN_[j] - '0';
    }
  }
  BigInt(int WUYIXUAN_) {
    string s = to_string(WUYIXUAN_);
    if (s[0] == '-') {
      s = s.substr(1);
      Neg = 1;
    }
    Len = s.size();
    for (int i = 1, j = Len - 1; i <= Len; i++, j--) {
      Num[i] = s[j] - '0';
    }
  }
  BigInt(long long WUYIXUAN_) {
    string s = to_string(WUYIXUAN_);
    if (s[0] == '-') {
      s = s.substr(1);
      Neg = 1;
    }
    Len = s.size();
    for (int i = 1, j = Len - 1; i <= Len; i++, j--) {
      Num[i] = s[j] - '0';
    }
  }
  BigInt(const char *s) {
    Len = strlen(s);
    for (int i = 1, j = Len - 1; i <= Len; i++, j--) {
      Num[i] = s[j] - '0';
    }
  }
  int Size() {
    while (!Num[Len]) {
      Len--;
    }
    Len += !Len;
    return Len;
  }
  BigInt SubInt(int start, int len) {
    len = len == 0 ? Len - len + 1 : len;
    BigInt ans;
    int end = start + len;
    ans.Len = end - start + 1;
    for (int i = 1, j = start; i <= ans.Len; i++, j++) {
      ans.Num[i] = this->Num[j];
    }
    end = ans.Size();
    return ans;
  }
  bool CanSub(BigInt WUYIXUAN_, int pos) {
    BigInt o = *this;
    if (o.Len < pos + WUYIXUAN_.Len) {
      return 0;
    }
    return this->SubInt(pos, WUYIXUAN_.Len) >= WUYIXUAN_;
  }
  friend BigInt operator+(BigInt WUYIXUAN_, BigInt WYX) {
    if (WUYIXUAN_.Neg && !WYX.Neg) {
      WUYIXUAN_.Neg = 0;
      return WYX - WUYIXUAN_;
    } else if (!WUYIXUAN_.Neg && WYX.Neg) {
      WYX.Neg = 0;
      return WUYIXUAN_ - WYX;
    }
    BigInt ans;
    ans.Len = max(WUYIXUAN_.Len, WYX.Len);
    for (int i = 1; i <= ans.Len; i++) {
      ans.Num[i] = WUYIXUAN_.Num[i] + WYX.Num[i];
    }
    for (int i = 1; i <= ans.Len; i++) {
      ans.Num[i + 1] += ans.Num[i] / 10, ans.Num[i] %= 10;
    }
    if (ans.Num[ans.Len + 1]) {
      ans.Len++;
    }
    return ans;
  }
  BigInt operator+=(BigInt WUYIXUAN_) {
    *this = *this + WUYIXUAN_;
    return *this;
  }
  friend bool operator<(BigInt WUYIXUAN_, BigInt WYX) {
    if (WUYIXUAN_.Neg ^ WYX.Neg) {
      return WUYIXUAN_.Neg != 1;
    }
    if (WUYIXUAN_.Len != WYX.Len) {
      return WUYIXUAN_.Len < WYX.Len;
    }
    for (int i = 1; i <= WUYIXUAN_.Len; i++) {
      if (WUYIXUAN_.Num[i] != WYX.Num[i]) {
        return WUYIXUAN_.Num[i] < WYX.Num[i];
      }
    }
    return 0;
  }
  friend bool operator==(BigInt WUYIXUAN_, BigInt WYX) {
    if (WUYIXUAN_.Len != WYX.Len) {
      return 0;
    }
    for (int i = 1; i <= WUYIXUAN_.Len; i++) {
      if (WUYIXUAN_.Num[i] != WYX.Num[i]) {
        return 0;
      }
    }
    return 1;
  }
  friend bool operator>(BigInt WUYIXUAN_, BigInt WYX) {
    return !(WUYIXUAN_ < WYX);
  }
  friend bool operator<=(BigInt WUYIXUAN_, BigInt WYX) {
    return WUYIXUAN_ < WYX || WUYIXUAN_ == WYX;
  }
  friend bool operator>=(BigInt WUYIXUAN_, BigInt WYX) {
    return WUYIXUAN_ > WYX || WUYIXUAN_ == WYX;
  }
  friend ostream &operator<<(ostream &cout, BigInt num) {
    if (num.Neg) {
      cout.put('-');
    }
    for (int i = num.Len; i >= 1; i--) {
      cout.put(num.Num[i] + '0');
    }
    return cout;
  }
  friend BigInt operator-(BigInt WUYIXUAN_, BigInt WYX) {
    if (WUYIXUAN_.Neg && !WYX.Neg) {
      WUYIXUAN_.Neg = 0;
      BigInt ret = WUYIXUAN_ + WYX;
      ret.Neg = 1;
      return ret;
    }
    if (WYX.Neg) {
      WYX.Neg = 0;
      return WUYIXUAN_ + WYX;
    } else if (WUYIXUAN_.Neg) {
      WUYIXUAN_.Neg = 0;
      return WYX - WUYIXUAN_;
    }
    if (WUYIXUAN_ < WYX) {
      BigInt ret = WYX - WUYIXUAN_;
      ret.Neg = 1;
      return ret;
    }
    BigInt ans;
    ans.Len = WUYIXUAN_.Len;
    for (int i = 1; i <= ans.Len; i++) {
      ans.Num[i] = WUYIXUAN_.Num[i] - WYX.Num[i];
    }
    for (int i = 1; i <= ans.Len; i++) {
      if (ans.Num[i] < 0) {
        ans.Num[i + 1]--, ans.Num[i] += 10;
      }
    }
    while (ans.Len && !ans.Num[ans.Len]) {
      ans.Len--;
    }
    if (!ans.Len) {
      ans.Len++;
    }
    return ans;
  }
  BigInt operator-=(BigInt WUYIXUAN_) {
    *this = *this - WUYIXUAN_;
    return *this;
  }
  friend BigInt operator*(BigInt WUYIXUAN_, BigInt WYX) {
    BigInt ans;
    ans.Len = WUYIXUAN_.Len + WYX.Len;
    for (int i = 1; i <= WUYIXUAN_.Len; i++) {
      for (int j = 1; j <= WYX.Len; j++) {
        ans.Num[i + j - 1] += WUYIXUAN_.Num[i] * WYX.Num[j];
      }
    }
    for (int i = 1; i <= ans.Len; i++) {
      ans.Num[i + 1] += ans.Num[i] / 10, ans.Num[i] %= 10;
    }
    while (!ans.Num[ans.Len]) {
      ans.Len--;
    }
    ans.Len += !ans.Len;
    ans.Neg = WUYIXUAN_.Neg ^ WYX.Neg;
    return ans;
  }
  BigInt operator*=(BigInt WUYIXUAN_) {
    *this = *this * WUYIXUAN_;
    return *this;
  }
  BigInt operator<<(int WUYIXUAN_) {
    BigInt o = *this;
    for (int i = 0; i < WUYIXUAN_; i++) {
      o *= 2;
    }
    return o;
  }
  BigInt operator<<=(int WUYIXUAN_) {
    *this = *this << WUYIXUAN_;
    return *this;
  }
  BigInt &operator++() {
    *this += 1;
    return *this;
  }
  BigInt operator++(int) {
    BigInt temp = *this;
    *this += 1;
    return temp;
  }
  BigInt &operator--() {
    *this -= 1;
    return *this;
  }
  BigInt operator--(int) {
    BigInt temp = *this;
    *this -= 1;
    return temp;
  }
  friend istream &operator>>(istream &cin, BigInt &num) {
    char c = cin.get();
    while (!isdigit(c) && c != '-') {
      c = cin.get();
    }
    if (isdigit(c)) {
      num = c - '0';
    } else {
      num.Neg = 1;
    }
    c = cin.get();
    while (isdigit(c)) {
      num = num * 10 + (c - '0');
      c = cin.get();
    }
    return cin;
  }
};
using pa = pair<int, BigInt>;

const int kMaxN = 1e6 + 1;

ifstream cin("skill.in");
ofstream cout("skill.out");

int n, m, sz[kMaxN];
vector<pa> g[kMaxN];
BigInt ans;

void Dfs(int x, int fa) {
  for (auto i : g[x]) {
    if (i.first != fa) {
      Dfs(i.first, x);
      sz[x] += sz[i.first];
      ans += i.second * abs(sz[i.first]);
    }
  }
}

int main() {
  cin >> n >> m;
  for (int i = 1, x; i <= m; i++) {
    cin >> x, sz[x]++;
  }
  for (int i = 1, x; i <= m; i++) {
    cin >> x, sz[x]--;
  }
  for (int i = 1, u, v, x; i < n; i++) {
    string w;
    cin >> u >> v >> w;
    reverse(w.begin(), w.end());
    g[u].push_back({v, BigInt(w)});
    g[v].push_back({u, BigInt(w)});
  }
  Dfs(1, 0);
  cout << ans << '\n';
  return 0;
}

T2 奶茶兑换券

暴力不会。

AC

首先把所有 \(b_i\) 大于 \(m\) 的处理了,然后给每一个 \(b_i \bmod m\),然后可以对剩下进行排序然后双指针 \(b_i \ge \lfloor \dfrac{d}{2} \rfloor\)\(b_i \le \lfloor \dfrac{d}{2} \rfloor\) 的两个部分。

#include <algorithm>
#include <fstream>

using namespace std;
using ll = long long;

const int kMaxN = 1e5 + 5;

ifstream cin("tea.in");
ofstream cout("tea.out");

struct Node {
  int a, b;
} p[kMaxN];

int main() {
  int n, m;
  cin >> n >> m;
  ll ans = 0;
  for (int i = 1; i <= n; i++) {
    cin >> p[i].a >> p[i].b;
    p[i].b %= m;
    if (!p[i].b) {
      --i, --n;
      continue;
    }
    ans += (ll)p[i].a * (m - p[i].b);
  }
  sort(p + 1, p + n + 1, [](Node a, Node b) { return a.b < b.b; });
  int i = 1, j = n;
  while (i < j) {
    if (p[i].b + p[j].b > m) {
      --j;
      continue;
    }
    int t = min(p[i].a, p[j].a);
    p[i].a -= t, p[j].a -= t, ans -= (ll)t * m;
    if (!p[i].a) {
      i++;
    }
    if (!p[j].a) {
      --j;
    }
  }
  if (p[i].b * 2 <= m) {
    ans -= (ll)p[i].a / 2 * m;
  }
  cout << ans << '\n';
  return 0;
}

T3 帮助

40 pts

枚举每两个同学,看看能不能互帮互助,复杂度 \(\mathcal O(n^2)\)

AC

先把 \(t_i,a_i, b_i, c_i, d_i\) 全部离散化,然后排序,预处理出每个人能帮助的区间和给予帮助的区间(因为排了序是一段连续的区间),用差分+树状数组维护每个人的贡献。

#include <algorithm>
#include <fstream>
#include <vector>

using namespace std;
using ll = long long;

const int kMaxN = 1e5 + 5;

ifstream cin("help.in");
ofstream cout("help.out");

int f[kMaxN], t[kMaxN], num[kMaxN], c[kMaxN], d[kMaxN];
ll ans[kMaxN], sum[kMaxN];
vector<int> h[kMaxN], g[kMaxN];
int len;

int lowbit(int x) {
  return x & -x;
}
void Add(int x, int val) {
  while (x <= len + 1) {
    sum[x] += val, x += lowbit(x);
  }
}
ll Modify(int x) {
  ll ret = 0;
  while (x > 0) {
    ret += sum[x], x -= lowbit(x);
  }
  return ret;
}
int main() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; ++i) {
    cin >> f[i];
  }
  for (int i = 1; i <= n; ++i) {
    cin >> t[i], num[i] = t[i];
  }
  sort(num + 1, num + n + 1);
  len = unique(num + 1, num + n + 1) - num - 1;
  for (int i = 1; i <= n; i++) {
    int a, b;
    t[i] = lower_bound(num + 1, num + len + 1, t[i]) - num;
    h[t[i]].push_back(i);
    cin >> a >> b;
    a = lower_bound(num + 1, num + len + 1, a) - num;
    b = upper_bound(num + 1, num + len + 1, b) - num - 1;
    if (a <= b) {
      g[b].push_back(i);
      g[a - 1].push_back(-i);
    }
    cin >> c[i] >> d[i];
    c[i] = lower_bound(num + 1, num + len + 1, c[i]) - num;
    d[i] = upper_bound(num + 1, num + len + 1, d[i]) - num - 1;
    if (!(a <= t[i] && t[i] <= b && c[i] <= t[i] && t[i] <= d[i])) {
      ans[i] = f[i];
    }
  }
  for (int i = 1; i <= len; ++i) {
    for (auto j : h[i]) {
      if (c[j] <= d[j]) {
        Add(c[j], f[j]);
        Add(d[j] + 1, -f[j]);
      }
    }
    for (auto j : g[i]) {
      int flag = (j < 0) ? -1 : 1;
      j = abs(j);
      ans[j] += Modify(t[j]) * flag;
    }
  }
  for (int i = 1; i <= n; ++i) {
    cout << ans[i] << ' ';
  }
  return 0;
}

T4 神奇的变换

Subtask 1

暴力即可

Subtask 2

不会。

Subtack 3

先算出每一个 \(a_i\) 的每一个约数的个数,然后询问时用前缀和算出来即可,复杂度 \(\mathcal O(1000(n+q))\)

Subtask 4

用前缀积然后计算即可。

posted @ 2024-10-02 14:27  GenesisCrystal  阅读(25)  评论(0)    收藏  举报