1. 程式人生 > 實用技巧 >2020 Multi-University Training Contest 1 部分題解

2020 Multi-University Training Contest 1 部分題解

目錄

Distinct Sub-palindromes

簽到,發現長度 \(>3\) 只能形如 \(abcabcabc...\),算下 \(3\) 的答案即可。

Code

int main() {
  ans[1] = 26, ans[2] = 26 * 26, ans[3] = 26 * 25 * 24 + 26 * 25 + 26 * 25 + 26 * 25 + 26; 
  for (ri tt = read(); tt; --tt) {
    int n = read();
    if (n <= 3) cout << ans[n] << '\n';
    else cout << 26 * 25 * 24 << '\n'; 
  }
  return 0;
}    

Fibonacci Sum

等比數列求和,要特判 \(1\)
場上過了的賽後被卡常了...卡了一波終於過了。

Code

int main() {
  A = mul(iv2, add(1, bas)), B = mul(iv2, dec(1, bas));
  init(100000);
  for (ri tt = read(), tp = mul(Inv(A), B); tt; --tt) {
    n = readl(), c = readl() % (mod - 1), k = read();
    int res = 0, n1 = (n + 1) % (mod - 1), n2 = (n + 1) % mod;
    int mt = ksm(tp, c), Mt = ksm(ksm(A, c), k);
    for (ri t, i = 0; i <= k; ++i) {
      if (Mt == 1) t = n2;
      else t = mul(dec(ksm(Mt, n1), 1), Inv(dec(Mt, 1)));
      (i & 1 ? Dec : Add) (res, mul(t, C(k, i)));
      Mul(Mt, mt);
    }
    cout << mul(res, pw[k]) << '\n';
  }
  return 0;
}

Finding a MEX

寫了個根號分治套 \(\text{set}\) 居然過了是我沒想到的,不過由於實現不好會被重邊卡,調了一年...
實際上可以用連結串列做到優美的 \(O(n\sqrt n)\)比賽的時候假胡了一下沒實現,如果不行不要噴我

Code

inline void ins(int x, int v) {
  if (v > n) return;
  ++cnt[x][v];
  if (cnt[x][v] > 1) return;
  set <pii> :: iterator it = sg[x].upper_bound(pii(v, n));
  --it;
  pii t = *it;
  sg[x].erase(it);
  if (t.fi < v) sg[x].insert(pii(t.fi, v - 1));
  if (v < t.se) sg[x].insert(pii(v + 1, t.se));
}
inline void del(int x, int v) {
  if (v > n) return;
  --cnt[x][v];
  if (cnt[x][v]) return;
  set <pii> :: iterator it = sg[x].upper_bound(pii(v, n));
  int l = v, r = v;
  if (it != sg[x].begin()) {
    --it;
    if (it -> se == v - 1) l = it -> fi;
    ++it;
  }
  if (it != sg[x].end()) {
    if (it -> fi == v + 1) r = it -> se; 
  }
  sg[x].erase(pii(l, v - 1));
  sg[x].erase(pii(v + 1, r));
  sg[x].insert(pii(l, r));
}
inline void upd(int x, int v) {
  for (ri i = 1; i <= tot; ++i) if (vs[i][x]) {
    del(i, a[x]);
    ins(i, v);
  }
  a[x] = v;
}
inline int qry(int x) {
  static bool vs[N];
  if (id[x]) {
    x = id[x];
    return sg[x].begin() -> fi;
  }
  else {
    for (ri i = 0; i <= blo; ++i) vs[i] = 0;
    for (ri i = 0; i < e[x].size(); ++i) {
      int v = a[e[x][i]];
      if (v <= blo) vs[v] = 1;
    }
    for (ri i = 0; i <= blo; ++i) if (!vs[i]) return i; 
  }
}
int main() {
  n = read(), m = read();
  for (ri i = 1; i <= n; ++i) a[i] = read(), e[i].clear(), id[i] = 0;
  for (ri i = 1, u, v; i <= m; ++i) {
    u = read(), v = read();
    e[u].pb(v), e[v].pb(u);
  }
  tot = 0;
  int mx = 0;
  for (ri i = 1; i <= n; ++i) mx = max(mx, (int) e[i].size());
  for (ri i = 1; i <= n; ++i) {
    sort(e[i].begin(), e[i].end());
    e[i].erase(unique(e[i].begin(), e[i].end()), e[i].end());
    if (e[i].size() >= blo) {
      id[i] = ++tot, sg[tot].clear();
      for (ri j = 0; j <= n; ++j) cnt[tot][j] = vs[tot][j] = 0;
      sg[tot].insert(pii(0, n));
      for (ri j = 0; j < e[i].size(); ++j) {
        int v = a[e[i][j]];
        vs[tot][e[i][j]] = 1;
        ins(tot, v);
      }
    }
  }
  for (ri tt = read(), op, x; tt; --tt) {
    op = read(), x = read();
    if (op == 1) upd(x, read());
    else cout << qry(x) << '\n';
  }
  return 0;
}

Leading Robots

模擬題意,對給出的二次函式維護出最大值的輪廓就行了。

Code

inline db Cross(int x, int y) { return (B[y] - B[x]) / (K[x] - K[y]); }
inline bool chk(int x, int y, int z) {
  db x_0 = Cross(x, y);
  return K[x] * x_0 + B[x] <= K[z] * x_0 + B[z];
}
inline bool cmp(int x, int y) { return B[x] < B[y] || (B[x] == B[y] && K[x] < K[y]); }
int main() {
  scanf("%d", &n);
  for (ri i = 1; i <= n; ++i) scanf("%lf%lf", &B[i], &K[i]), id[i] = i, ban[i] = 0;
  sort(id + 1, id + n + 1, cmp);
  top = 0;
  for (ri i = 1, p; i <= n; ++i) {
    p = id[i];
    if (top) {
      if (make_pair(K[p], B[p]) == make_pair(K[q[top]], B[q[top]])) {
        ban[p] = ban[q[top]] = 1;
        continue;
      }
      while (top > 1 && chk(q[top], q[top - 1], p)) --top;
      if (top == 1 && K[top] >= K[q[top]]) --top;
    }
    q[++top] = p;
  }
  int res = 0;
  for (ri i = 1; i <= top; ++i) if (!ban[q[i]]) ++res;
  cout << res << '\n';
  return 0;
}

Minimum Index

邊做 \(\text{Lyndon}\) 分解邊統計答案即可。

Code

int main() {
  n = Read(s);
  int ss = 0;
  for (ri i = 1; i <= n; ++i) vs[i] = 0;
  for (ri i = 1, iv = Inv(1112), j, k, mt = 1; i <= n; ) {
    j = i, k = i + 1;
    if (!vs[i]) len[i] = 1, vs[i] = 1, Add(ss, mul(mt, i)), Mul(mt, 1112);
    for (; k <= n && s[j] <= s[k]; ++k) {
      j = s[j] < s[k] ? i : j + 1;
      if (!vs[k]) {
        vs[k] = 1;
        if (i == j) len[k] = k - i + 1;
        else len[k] = len[j - 1];
        Add(ss, mul(mt, k - len[k] + 1)), Mul(mt, 1112);
      }
    }
    for (; i <= j; i += k - j);
  }
  cout << ss << '\n';
  return 0;
}