CodeForces Gym 101741 简要题解

本文精选了多项算法竞赛题目并提供了详细的解决方案,涵盖了包括贪心算法、动态规划、图论等在内的多种算法类型。

Three Arrays:

枚举 aiai ,求出当前 bb 的合法区间和 c 的合法区间,并且要求 bb 中的数在 c 中的合法区间与枚举的 aa 中的数的合法区间有交,然后用前缀和维护一下。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 500005;

int d, p, q, r, a[N], b[N], c[N], u[N], v[N];
LL ans, L[N], R[N];

int Main() {
  ans = 0;
  for (int i = 1; i <= p; ++i) {
    Read(a[i]);
  }
  for (int i = 1; i <= q; ++i) {
    Read(b[i]);
  }
  for (int i = 1; i <= r; ++i) {
    Read(c[i]);
  }
  for (int i = 1, c_l = 1, c_r = 0; i <= q; ++i) {
    for (; c_l <= r && c[c_l] < b[i] - d; ++c_l);
    for (; c_r < r && c[c_r + 1] <= b[i] + d; ++c_r);
    u[i] = c_l, v[i] = c_r;
    L[i] = L[i - 1] + c_l;
    R[i] = R[i - 1] + c_r;
  }
  for (int i = 1, b_l = 1, b_r = 0, c_l = 1, c_r = 0, pos = 0; i <= p; ++i) {
    for (; c_l <= r && c[c_l] < a[i] - d; ++c_l);
    for (; c_r < r && c[c_r + 1] <= a[i] + d; ++c_r);
    for (; b_l <= q && (v[b_l] < c_l || b[b_l] < a[i] - d); ++b_l);
    for (; b_r < q && b[b_r + 1] <= a[i] + d && u[b_r + 1] <= c_r; ++b_r);
    for (; pos < q && b[pos + 1] <= a[i]; ++pos);
    if (b_l <= pos) {
      ans += R[pos] - R[b_l - 1];
      ans -= 1LL * (c_l - 1) * (pos - b_l + 1);
    }
    if (pos + 1 <= b_r) {
      ans += 1LL * (c_r + 1) * (b_r - pos);
      ans -= L[b_r] - L[pos];
    }
  }
  printf("%lld\n", ans);
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  while (~scanf("%d %d %d %d", &d, &p, &q, &r)) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Expected Shopping:

留坑,不打算填。

Cover the Paths:

贪心放即可。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 100005;

vector <int> adj[N];
set <int> s[N];
int n, m, tot;
bool ans[N];

inline void DFS(int x, int p) {
  for (auto y : adj[x]) {
    if (y != p) {
      DFS(y, x);
      if (s[x].size() < s[y].size()) {
        swap(s[x], s[y]);
      }
      for (auto i : s[y]) {
        if (s[x].find(i) != s[x].end()) {
          ans[x] = true;
          break;
        } else {
          s[x].insert(i);
        }
      }
    }
  }
  if (ans[x]) {
    ++tot, s[x].clear();
  }
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n);
  for (int i = 1, x, y; i < n; ++i) {
    Read(x), Read(y);
    adj[x].pb(y), adj[y].pb(x);
  }
  Read(m);
  for (int i = 1, x, y; i <= m; ++i) {
    Read(x), Read(y);
    if (x == y) {
      ans[x] = true;
    } else {
      s[x].insert(i), s[y].insert(i);
    }
  }
  DFS(1, 0);
  printf("%d\n", tot);
  for (int i = 1; i <= n; ++i) {
    if (ans[i]) {
      printf("%d", i);
      putchar(--tot ? ' ' : '\n');
    }
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Elevator:

如果 titj,aiaj 那么 ii 是没用的,可以去掉。

fi=min(ti,fj)+2aj+1 ,线段树优化即可。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 200005;

int n, top, a[N], b[N], sta[N];
LL f[N], val[2][N << 2];

inline void Build(int x, int l, int r) {
  val[0][x] = val[1][x] = 1LL << 60;
  if (l == r) {
    return ;
  }
  int mid = l + r >> 1;
  Build(x << 1, l, mid), Build(x << 1 | 1, mid + 1, r);
}

inline void Modify(int o, int x, int l, int r, int ql, int qr, LL v) {
  if (ql > qr) {
    return ;
  }
  if (l == ql && r == qr) {
    CheckMin(val[o][x], v);
    return ;
  }
  CheckMin(val[o][x << 1], val[o][x]), CheckMin(val[o][x << 1 | 1], val[o][x]);
  int mid = l + r >> 1;
  if (qr <= mid) {
    Modify(o, x << 1, l, mid, ql, qr, v);
  } else if (ql > mid) {
    Modify(o, x << 1 | 1, mid + 1, r, ql, qr, v);
  } else {
    Modify(o, x << 1, l, mid, ql, mid, v), Modify(o, x << 1 | 1, mid + 1, r, mid + 1, qr, v);
  }
}

inline LL Query(int o, int x, int l, int r, int p) {
  if (l == r) {
    return val[o][x];
  }
  CheckMin(val[o][x << 1], val[o][x]), CheckMin(val[o][x << 1 | 1], val[o][x]);
  int mid = l + r >> 1;
  if (p <= mid) {
    return Query(o, x << 1, l, mid, p);
  } else {
    return Query(o, x << 1 | 1, mid + 1, r, p);
  }
}

int Main() {
  top = 0;
  for (int i = 1; i <= n; ++i) {
    Read(a[i]), Read(b[i]);
    for (; top && b[sta[top]] <= b[i]; --top);
    sta[++top] = i;
  }
  for (int i = 1; i <= top; ++i) {
    a[i] = a[sta[i]], b[i] = b[sta[i]];
  }
  n = top;
  Build(1, 1, n);
  for (int i = 0; i <= n; ++i) {
    if (i) {
      f[i] = min(Query(0, 1, 1, n, i), Query(1, 1, 1, n, i) + a[i]);
    } else {
      f[i] = 0;
    }
    int pos = lower_bound(a + 1, a + n + 1, (int)min(f[i], 1LL << 30)) - a;
    Modify(0, 1, 1, n, i + 1, pos - 1, f[i] + 2 * b[i + 1]);
    Modify(1, 1, 1, n, pos, n, 2 * b[i + 1]);
  }
  printf("%lld\n", f[n]);
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  while (~scanf("%d", &n)) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Code-Cola Plants:

bba 连两条边,那么第一组边相当于每个点入度为 11 ,第二组边相当于每个点出度为 1

构造一个左边 2n2n 个点,右边 mm 个点的二分图,那么就是要求一个最大匹配。

注意到右边每个点度数都是 2 ,所以直接在左边连边,相当于求一个环套树森林。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 1000005;

int n, m, s, t, ql, qr, cnt, d[N], f[N], q[N], ans[N];
vector <pii> adj[N];
vector <int> seq;
bool v[N];

inline int Find(int x) {
  while (x != f[x]) {
    x = f[x] = f[f[x]];
  }
  return x;
}

int Main() {
  for (int i = 1; i <= n << 1; ++i) {
    f[i] = i, v[i] = false, d[i] = 0, adj[i].clear();
  }
  f[s + n] = t, v[t] = true, cnt = 2, d[t] = d[s + n] = 2;
  adj[t].pb(mp(s + n, 0)), adj[s + n].pb(mp(t, 0));
  adj[t].pb(mp(s + n, 0)), adj[s + n].pb(mp(t, 0));
  for (int i = 1, p, q, x, y; i <= m; ++i) {
    Read(p), Read(q), q += n, x = Find(p), y = Find(q);
    if (x == y) {
      if (!v[x]) {
        adj[p].pb(mp(q, i)), adj[q].pb(mp(p, i)), ++cnt;
        ++d[p], ++d[q], v[x] = true;
      }
    } else if (!v[x] || !v[y]) {
      adj[p].pb(mp(q, i)), adj[q].pb(mp(p, i)), ++cnt;
      ++d[p], ++d[q], f[x] = y, v[y] |= v[x];
    }
    ans[i] = -1;
  }
  if (cnt != n << 1) {
    puts("NO");
    return 0;
  }
  puts("YES"), ql = qr = 0;
  for (int i = 1; i <= n << 1; ++i) {
    if (d[i] == 1) {
      q[++qr] = i;
    }
    v[i] = false;
  }
  while (ql < qr) {
    int x = q[++ql];
    v[x] = true;
    for (auto e : adj[x]) {
      if (!v[e.X]) {
        ans[e.Y] = x > n;
        if (--d[e.X] == 1) {
          q[++qr] = e.X;
        }
      }
    }
  }
  for (int i = 1; i <= n << 1; ++i) {
    if (!v[i]) {
      seq.clear();
      for (int x = i, p; x; ) {
        v[x] = true, seq.pb(x), p = 0;
        for (auto e : adj[x]) {
          if (!v[e.X]) {
            p = e.X;
            break;
          }
        }
        x = p;
      }
      for (int i = 0, m = seq.size(); i < m; ++i) {
        for (auto e : adj[seq[i]]) {
          if (e.X == seq[(i + 1) % m] && !~ans[e.Y]) {
            ans[e.Y] = seq[i] > n;
            break;
          }
        }
      }
    }
  }
  for (int i = 1, t = 0; i <= m; ++i) {
    if (ans[i] == 1) {
      printf("%d%c", i, ++t == n - 1 ? '\n' : ' ');
    }
  }
  for (int i = 1, t = 0; i <= m; ++i) {
    if (!ans[i]) {
      printf("%d%c", i, ++t == n - 1 ? '\n' : ' ');
    }
  }
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  while (~scanf("%d %d %d %d", &n, &m, &s, &t)) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

GCD:

考虑随机一个保留的数 x=aix=ai ,每次随机有 1212 以上的正确率,多次随机即可。

将这个数分解质因数,然后在 gcd(ai,x)gcd(ai,x) 处打上标记,那么每个点实际的标记是它倍数的标记之和。

本质上是一个高维前缀和,单次 σ0(x)×ω(x)σ0(x)×ω(x) 的复杂度可以承受。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 100005;

int n, m, cnt, deg[N];
LL ans, a[N], pri[N];
map <LL, int> val;
vector <LL> seq;

inline int Rand() {
  return rand() << 15 | rand();
}

inline LL RandLL() {
  return (LL)Rand() << 30 | Rand();
}

inline LL Qul(LL x, LL y, LL mod) {
  return ((x * y - (LL)(((LD)x * y + 0.5) / mod) * mod) % mod + mod) % mod;
}

inline LL Qow(LL x, LL y, LL mod) {
  LL r = 1;
  for (; y; y >>= 1, x = Qul(x, x, mod)) {
    if (y & 1) {
      r = Qul(r, x, mod);
    }
  }
  return r;
}

inline bool MillerRabin(LL n) {
  if (n == 2) {
    return true;
  }
  if (n < 2 || !(n & 1)) {
    return false;
  }
  LL a, x, y, u = n - 1;
  int t = 0;
  for (; !(u & 1); u >>= 1, ++t);
  for (int i = 0; i < 10; ++i) {
    a = RandLL() % (n - 1) + 1, x = Qow(a, u, n);
    for (int j = 0; j < t; ++j, x = y) {
      if ((y = Qul(x, x, n)) == 1 && x != 1 && x != n - 1) {
        return false;
      }
    }
    if (x != 1) {
      return false;
    }
  }
  return true;
}

inline LL PollardRho(LL a, LL c) {
  LL k = 2, x = RandLL() % a, y = x, p = 1;
  for (LL i = 1; p == 1; ++i) {
    x = (Qul(x, x, a) + c) % a, p = __gcd(abs(x - y), a);
    if (i == k) {
      y = x, k <<= 1;
    }
  }
  return p;
}

inline void Divide(LL x) {
  if (x == 1) {
    return ;
  }
  if (MillerRabin(x)) {
    pri[cnt++] = x;
    return ;
  }
  LL p = x;
  while (p >= x) {
    p = PollardRho(x, RandLL() % (x - 1));
  }
  Divide(p), Divide(x / p);
}

inline void DFS(int x, LL v) {
  if (x == cnt) {
    val[v] = 0, seq.pb(v);
    return ;
  }
  for (int i = 0; i <= deg[x]; ++i) {
    DFS(x + 1, v), v *= pri[x];
  }
}

inline void Solve(LL x) {
  cnt = 0, Divide(x);
  sort(pri, pri + cnt);
  cnt = unique(pri, pri + cnt) - pri;
  LL tmp = x;
  for (int i = 0; i < cnt; ++i) {
    for (deg[i] = 0; tmp % pri[i] == 0; tmp /= pri[i], ++deg[i]);
  }
  val.clear(), seq.clear(), DFS(0, 1);
  for (int i = 0; i < n; ++i) {
    ++val[__gcd(a[i], x)];
  }
  for (int i = 0; i < cnt; ++i) {
    for (int j = seq.size() - 1; ~j; --j) {
      if (seq[j] % pri[i] == 0) {
        val[seq[j] / pri[i]] += val[seq[j]];
      }
    }
  }
  random_shuffle(seq.begin(), seq.end());
  for (int i = 0; i < seq.size(); ++i) {
    if (val[seq[i]] >= n - m) {
      CheckMax(ans, seq[i]);
    }
  }
}


int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  srand(time(0));
  Read(n), Read(m);
  for (int i = 0; i < n; ++i) {
    Read(a[i]);
  }
  while ((double)clock() / CLOCKS_PER_SEC < 3.5) {
    Solve(a[Rand() % n]);
  }
  printf("%lld\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Berland Post:

二分 TT ,跑差分约束。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 2005;
const int inf = 0x3f3f3f3f;

struct Edge {
  int p, v;
  double w;
} e[N << 1];

int n, m, e_cnt, a[N], b[N], c[N], d[N], cnt[N], hed[N];
double dis[N];
bool vis[N];
char s[N];

inline void AddEdge(int x, int y, double w) {
  e[++e_cnt] = {y, hed[x], w}, hed[x] = e_cnt;
}

inline bool Check(double t) {
  e_cnt = 0;
  for (int i = 0; i <= n; ++i) {
    hed[i] = 0;
  }
  for (int i = 1; i <= n; ++i) {
    if (c[i] != INT_MAX) {
      AddEdge(0, i, c[i]), AddEdge(i, 0, -c[i]);
    }
  }
  for (int i = 1; i <= m; ++i) {
    AddEdge(b[i], a[i], t - d[i]);
  }
  queue <int> q;
  for (int i = 0; i <= n; ++i) {
    dis[i] = 10000000, q.push(i), vis[i] = true, cnt[i] = 0;
  }
  dis[0] = 0;
  while (!q.empty()) {
    int x = q.front();
    q.pop(), vis[x] = false;
    for (int i = hed[x]; i; i = e[i].v) {
      if (CheckMin(dis[e[i].p], dis[x] + e[i].w)) {
        if (++cnt[e[i].p] > n) {
          return false;
        }
        if (!vis[e[i].p]) {
          vis[e[i].p] = true, q.push(e[i].p);
        }
      }
    }
  }
  return true;
}

int Main() {
  for (int i = 1; i <= n; ++i) {
    scanf("%s", s);
    if (s[0] == '?') {
      c[i] = INT_MAX;
    } else {
      sscanf(s, "%d", &c[i]);
    }
  }
  for (int i = 1; i <= m; ++i) {
    Read(a[i]), Read(b[i]), Read(d[i]);
  }
  double l = 0, r = inf;
  while (r - l > 1e-5) {
    double mid = (l + r) / 2;
    if (Check(mid)) {
      r = mid;
    } else {
      l = mid;
    }
  }
  printf("%lf\n", r), Check(r);
  for (int i = 1; i <= n; ++i) {
    printf("%lf%c", dis[i], i == n ? '\n' : ' ');
  }
  return 0;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  while (~scanf("%d %d", &n, &m)) {
    Main();
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Compressed Spanning Subtrees:

考虑每次询问除了 i 点的剩下 n1n−1 个点,可以知道 ii 是不是叶子,这里需要询问 i 次。

任选一个叶子 rootroot 当根,对于剩下的每对叶节点 xx 和非叶节点 y ,问一次 root,x,yroot,x,y 可以知道 yy 是不是 x 的祖先。

将每个非叶节点按照子树大小排序之后可以知道所有边了。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 105;

vector <int> lef, oth, seq, adj[N];
int n, rot, siz[N], par[N];
bool plc[N], anc[N][N];

inline int Query() {
  int cnt = 0, ret = 0;
  for (int i = 1; i <= n; ++i) {
    if (plc[i]) {
      ++cnt;
    }
  }
  printf("? %d", cnt);
  for (int i = 1; i <= n; ++i) {
    if (plc[i]) {
      printf(" %d", i);
    }
  }
  putchar(10);
  fflush(stdout);
  Read(ret);
  return ret;
}

inline int DFS(int x) {
  for (auto y : adj[x]) {
    if (y != par[x]) {
      par[y] = x, DFS(y);
    }
  }
}

int main() {
#ifdef wxh010910
#endif
  Read(n);
  if (n == 2) {
    puts("! 1");
    fflush(stdout);
    return 0;
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
      plc[j] = i != j;
    }
    if (Query() == n - 1) {
      if (!rot) {
        rot = i;
      } else {
        lef.pb(i);
      }
    } else {
      oth.pb(i);
    }
  }
  for (auto x : lef) {
    for (auto y : oth) {
      for (int i = 1; i <= n; ++i) {
        plc[i] = i == rot || i == x || i == y;
      }
      if (Query() == 3) {
        anc[x][y] = true, ++siz[y];
      }
    }
  }
  for (auto x : lef) {
    seq.clear();
    for (int i = 1; i <= n; ++i) {
      if (anc[x][i]) {
        seq.pb(i);
      }
    }
    sort(seq.begin(), seq.end(), [&](const int &x, const int &y) { return siz[x] < siz[y]; });
    par[x] = seq[0], par[seq.back()] = rot;
    for (int i = 1; i < seq.size(); ++i) {
      par[seq[i - 1]] = seq[i];
    }
  }
  for (int i = 1; i <= n; ++i) {
    if (i != rot) {
      adj[par[i]].pb(i), adj[i].pb(par[i]), par[i] = 0;
    }
  }
  DFS(1), putchar('!');
  for (int i = 2; i <= n; ++i) {
    printf(" %d", par[i]);
  }
  putchar(10);
  fflush(stdout);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Prefix-free Queries:

预处理后缀数组,每次询问按字典序排序之后可以建出树,树形DP即可。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 400005;
const int M = 20;

int n, m, q, mod, top, g[N], h[N], L[N], arr[N], siz[N], sta[N], rnk[N], f[M][N];
vector <int> adj[N];
char s[N];

inline void Build() {
  static int a[N], b[N], t[N], cnt_a[N], cnt_b[N];
  for (int i = 1; i <= n; ++i) {
    ++cnt_a[s[i]];
  }
  for (int i = 1; i < 26; ++i) {
    cnt_a[i] += cnt_a[i - 1];
  }
  for (int i = n; i; --i) {
    arr[cnt_a[s[i]]--] = i;
  }
  rnk[arr[1]] = 1;
  for (int i = 2; i <= n; ++i) {
    rnk[arr[i]] = rnk[arr[i - 1]] + (s[arr[i]] != s[arr[i - 1]]);
  }
  for (int l = 1; rnk[arr[n]] < n; l <<= 1) {
    for (int i = 0; i <= n; ++i) {
      cnt_a[i] = cnt_b[i] = 0;
    }
    for (int i = 1; i <= n; ++i) {
      ++cnt_a[a[i] = rnk[i]], ++cnt_b[b[i] = i + l > n ? 0 : rnk[i + l]];
    }
    for (int i = 1; i <= n; ++i) {
      cnt_a[i] += cnt_a[i - 1], cnt_b[i] += cnt_b[i - 1];
    }
    for (int i = n; i; --i) {
      t[cnt_b[b[i]]--] = i;
    }
    for (int i = n; i; --i) {
      arr[cnt_a[a[t[i]]]--] = t[i];
    }
    rnk[arr[1]] = 1;
    for (int i = 2; i <= n; ++i) {
      rnk[arr[i]] = rnk[arr[i - 1]] + (a[arr[i]] != a[arr[i - 1]] || b[arr[i]] != b[arr[i - 1]]);
    }
  }
  for (int i = 1, j = 0; i <= n; ++i) {
    for (j -= j > 0; rnk[i] != 1 && s[i + j] == s[arr[rnk[i] - 1] + j]; ++j);
    h[rnk[i]] = j;
  }
}

inline int LCP(int x, int y) {
  if (x == y) {
    return n - x + 1;
  }
  x = rnk[x], y = rnk[y];
  if (x > y) {
    swap(x, y);
  }
  ++x;
  int k = L[y - x];
  return min(f[k][x], f[k][y - (1 << k) + 1]);
}

struct String {
  int l, r;

  bool operator < (const String &b) const {
    int lcp = min(min(r - l + 1, b.r - b.l + 1), LCP(l, b.l));
    if (b.r - b.l + 1 == lcp) {
      return false;
    } else if (r - l + 1 == lcp) {
      return true;
    } else {
      return s[l + lcp] < s[b.l + lcp];
    }
  }

  bool operator == (const String &b) const {
    return r - l + 1 == b.r - b.l + 1 && LCP(l, b.l) >= r - l + 1;
  }
} str[N];

inline bool Prefix(String a, String b) {
  return a.r - a.l + 1 == min(min(a.r - a.l + 1, b.r - b.l + 1), LCP(a.l, b.l));
}

inline void DFS(int x) {
  g[x] = 1;
  for (auto y : adj[x]) {
    DFS(y), g[x] = 1LL * g[x] * (g[y] + 1) % mod;
  }
  g[x] = (g[x] + siz[x] - 1) % mod;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(q), siz[0] = 1;
  scanf("%s", s + 1), s[n + 1] = 26;
  for (int i = 1; i <= n; ++i) {
    s[i] -= 'a';
  }
  Build();
  for (int i = 1; i <= n; ++i) {
    f[0][i] = h[i];
  }
  for (int j = 1; j < M; ++j) {
    for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
      f[j][i] = min(f[j - 1][i], f[j - 1][i + (1 << j - 1)]);
    }
  }
  for (int i = 2; i <= n; ++i) {
    L[i] = L[i >> 1] + 1;
  }
  for (int i = 1; i <= q; ++i) {
    Read(m), Read(mod);
    for (int i = 1; i <= m; ++i) {
      Read(str[i].l), Read(str[i].r);
    }
    sort(str + 1, str + m + 1);
    sta[top = 1] = 1;
    for (int i = 2; i <= m; ++i) {
      if (!(str[i] == str[i - 1])) {
        sta[++top] = i;
      }
    }
    for (int i = 1; i <= top; ++i) {
      siz[i] = i == top ? m - sta[i] + 1 : sta[i + 1] - sta[i];
    }
    m = top;
    for (int i = 1; i <= m; ++i) {
      str[i] = str[sta[i]];
    }
    top = 0;
    for (int i = 0; i <= m; ++i) {
      adj[i].clear();
    }
    for (int i = 1; i <= m; ++i) {
      for (; top && !Prefix(str[sta[top]], str[i]); --top);
      adj[sta[top]].pb(i), sta[++top] = i;
    }
    DFS(0);
    printf("%d\n", g[0]);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Subsequence Sum Queries:

分治,每次处理跨过 [mid,mid+1][mid,mid+1] 的答案,预处理背包即可。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 200005;
const int M = 25;
const int mod = 1e9 + 7;

struct Node {
  int l, r, i;
} s[N], t[N];

int n, m, q, a[N], ans[N], f[N][M];

inline void Solve(int l, int r, int ql, int qr) {
  if (ql > qr) {
    return ;
  }
  if (l == r) {
    for (int i = ql; i <= qr; ++i) {
      ans[s[i].i] = (!a[l]) + 1;
    }
    return ;
  }
  int mid = l + r >> 1, tl = ql - 1, tr = qr + 1;
  for (int j = 0; j < m; ++j) {
    f[mid][j] = (!j) + (j == a[mid]);
    f[mid + 1][j] = (!j) + (j == a[mid + 1]);
  }
  for (int i = mid - 1; i >= l; --i) {
    for (int j = 0; j < m; ++j) {
      f[i][j] = f[i + 1][j];
    }
    for (int j = 0; j < m; ++j) {
      f[i][(j + a[i]) % m] = (f[i][(j + a[i]) % m] + f[i + 1][j]) % mod;
    }
  }
  for (int i = mid + 2; i <= r; ++i) {
    for (int j = 0; j < m; ++j) {
      f[i][j] = f[i - 1][j];
    }
    for (int j = 0; j < m; ++j) {
      f[i][(j + a[i]) % m] = (f[i][(j + a[i]) % m] + f[i - 1][j]) % mod;
    }
  }
  for (int i = ql; i <= qr; ++i) {
    if (s[i].l <= mid && s[i].r > mid) {
      for (int j = 0; j < m; ++j) {
        ans[s[i].i] = (1LL * f[s[i].l][j] * f[s[i].r][(m - j) % m] + ans[s[i].i]) % mod;
      }
    } else if (s[i].r <= mid) {
      t[++tl] = s[i];
    } else {
      t[--tr] = s[i];
    }
  }
  for (int i = ql; i <= tl; ++i) {
    s[i] = t[i];
  }
  for (int i = tr; i <= qr; ++i) {
    s[i] = t[i];
  }
  Solve(l, mid, ql, tl), Solve(mid + 1, r, tr, qr);
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 1; i <= n; ++i) {
    Read(a[i]), a[i] %= m;
  }
  Read(q);
  for (int i = 1; i <= q; ++i) {
    Read(s[i].l), Read(s[i].r), s[i].i = i;
  }
  Solve(1, n, 1, q);
  for (int i = 1; i <= q; ++i) {
    printf("%d\n", ans[i]);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Consistent Occurrences:

本质不同的长度只有根号个,对于每种长度将哈希值存下来,询问直接查询。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 100005;
const int bas[2] = {2333, 2339};
const int mod[2] = {1000000007, 1000000009};

int n, m, all, cur, l[N], r[N], ans[N], len[N], h[2][N], pwd[2][N];
map <pii, pii> cnt;
char s[N], t[N];

inline void Solve(int len) {
  cnt.clear();
  for (int i = len; i <= n; ++i) {
    pii val = mp((h[0][i] - 1LL * h[0][i - len] * pwd[0][len] % mod[0] + mod[0]) % mod[0], (h[1][i] - 1LL * h[1][i - len] * pwd[1][len] % mod[1] + mod[1]) % mod[1]);
    if (cnt.find(val) == cnt.end()) {
      cnt[val] = mp(1, i);
    } else {
      if (i - cnt[val].Y < len) {
        continue;
      } else {
        ++cnt[val].X, cnt[val].Y = i;
      }
    }
  }
  for (int i = 1; i <= m; ++i) {
    if (r[i] - l[i] + 1 == len) {
      pii cur = mp(0, 0);
      for (int j = l[i]; j <= r[i]; ++j) {
        cur = mp((1LL * cur.X * bas[0] + t[j]) % mod[0], (1LL * cur.Y * bas[1] + t[j]) % mod[1]);
      }
      ans[i] = cnt[cur].X;
    }
  }
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  scanf("%s", s + 1);
  pwd[0][0] = pwd[1][0] = 1;
  for (int j = 0; j < 2; ++j) {
    for (int i = 1; i <= n; ++i) {
      h[j][i] = (1LL * h[j][i - 1] * bas[j] + s[i]) % mod[j];
      pwd[j][i] = 1LL * pwd[j][i - 1] * bas[j] % mod[j];
    }
  }
  for (int i = 1; i <= m; ++i) {
    scanf("%s", t + cur + 1);
    l[i] = cur + 1, len[i] = strlen(t + cur + 1);
    cur += len[i], r[i] = cur;
  }
  sort(len + 1, len + m + 1), all = unique(len + 1, len + m + 1) - len - 1;
  for (int i = 1; i <= all; ++i) {
    Solve(len[i]);
  }
  for (int i = 1; i <= m; ++i) {
    printf("%d\n", ans[i]);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Increasing Costs:

建出最短路DAG,就是询问删掉一条边 11 不能到几个点。

将边拆点,建出灭绝树,就是询问子树点数。

#include <bits/stdc++.h>

using namespace std;

#define X first
#define Y second
#define mp make_pair
#define pb push_back
#define Debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef long double LD;
typedef unsigned int uint;
typedef pair <int, int> pii;
typedef unsigned long long uLL;

template <typename T> inline void Read(T &x) {
  char c = getchar();
  bool f = false;
  for (x = 0; !isdigit(c); c = getchar()) {
    if (c == '-') {
      f = true;
    }
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  if (f) {
    x = -x;
  }
}

template <typename T> inline bool CheckMax(T &a, const T &b) {
  return a < b ? a = b, true : false;
}

template <typename T> inline bool CheckMin(T &a, const T &b) {
  return a > b ? a = b, true : false;
}

const int N = 400005;
const int M = 20;

struct Edge {
  int p, v, w, i;
} e[N << 1];

int n, m, ql, qr, e_cnt, d[N], q[N], ans[N], dep[N], hed[N], f[M][N];
vector <int> adj[N];

inline void Dijkstra() {
  priority_queue <pair <LL, int>> q;
  static bool vis[N];
  static LL dis[N];
  for (int i = 1; i <= n; ++i) {
    dis[i] = LLONG_MAX;
  }
  dis[1] = 0, q.push(mp(0, 1));
  while (!q.empty()) {
    int x = q.top().Y;
    q.pop();
    if (vis[x]) {
      continue;
    }
    for (int i = hed[x]; i; i = e[i].v) {
      if (CheckMin(dis[e[i].p], dis[x] + e[i].w)) {
        q.push(mp(-dis[e[i].p], e[i].p));
      }
    }
  }
  for (int x = 1; x <= n; ++x) {
    for (int i = hed[x]; i; i = e[i].v) {
      if (dis[e[i].p] == dis[x] + e[i].w) {
        adj[e[i].p + m].pb(e[i].i);
        adj[e[i].i].pb(x + m);
        ++d[e[i].i], ++d[x + m];
      }
    }
  }
}

inline int LCA(int x, int y) {
  if (dep[x] < dep[y]) {
    swap(x, y);
  }
  if (dep[x] != dep[y]) {
    for (int i = 0; i < M; ++i) {
      if (dep[x] - dep[y] >> i & 1) {
        x = f[i][x];
      }
    }
  }
  if (x == y) {
    return x;
  }
  for (int i = M - 1; ~i; --i) {
    if (f[i][x] != f[i][y]) {
      x = f[i][x], y = f[i][y];
    }
  }
  return f[0][x];
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 1, u, v, w; i <= m; ++i) {
    Read(u), Read(v), Read(w);
    e[++e_cnt] = {v, hed[u], w, i}, hed[u] = e_cnt;
    e[++e_cnt] = {u, hed[v], w, i}, hed[v] = e_cnt;
  }
  Dijkstra();
  for (int i = m + 1; i <= n + m; ++i) {
    if (!d[i]) {
      q[++qr] = i;
    }
  }
  while (ql <= qr) {
    int x = q[++ql];
    for (auto y : adj[x]) {
      if (!--d[y]) {
        q[++qr] = y;
      }
    }
  }
  for (int i = qr - 1; i; --i) {
    int x = q[i], cur = adj[x][0];
    for (auto y : adj[x]) {
      cur = LCA(cur, y);
    }
    f[0][x] = cur, dep[x] = dep[cur] + 1;
    for (int j = 1; j < M; ++j) {
      f[j][x] = f[j - 1][f[j - 1][x]];
    }
  }
  for (int i = 1; i < qr; ++i) {
    int x = q[i];
    ans[x] += x > m;
    ans[f[0][x]] += ans[x];
  }
  for (int i = 1; i <= m; ++i) {
    printf("%d\n", ans[i]);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值