UOJ Round #12

A

结论:答案是 YES 当且仅当对于任意一个数,\(A\) 中比它小且在它前面的数在 \(B\) 中也在它前面。

证明:必要性显然,充分性考虑直接把 \(A\) 中的数从前往后挪到 \(B\) 中对应的位置,则挪不动时一定与结论矛盾。

那么直接三维数点即可,也可以改变枚举顺序后变成二维数点。

#include <bits/stdc++.h>

#define IL __inline__ __attribute__((always_inline))

#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)

typedef long long LL;

template <class T>
IL bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}

template <class T>
IL bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}

template <class T>
IL T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}

template <class T>
IL T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}

template <class T>
IL T myabs(const T &a) {
  return a > 0 ? a : -a;
}

const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())

const int MAXN = 100000 + 5;

struct BinaryIndexedTree {
  int a[MAXN], n;

#define lowbit(x) ((x) & -(x))
  void modify(int i, int x) {
    for (; i <= n; i += lowbit(i)) {
      a[i] += x;
    }
  }

  int query(int i) {
    int ret = 0;
    for (; i; i -= lowbit(i)) {
      ret += a[i];
    }
    return ret;
  }
} bit;

int a[MAXN], b[MAXN], p[MAXN], q[MAXN], ans[MAXN];

void solve(int l, int r) {
  if (l == r) {
    return;
  }
  int mid = (l + r) >> 1, len = r - l + 1;
  solve(l, mid);
  static int tp[MAXN];
  For(i, l, r) {
    tp[i - l + 1] = i;
  }
  std::sort(tp + 1, tp + len + 1, [&](int a, int b) {
    return p[a] < p[b];
  });
  For(i, 1, len) {
    if (tp[i] <= mid) {
      bit.modify(q[tp[i]], 1);
    } else {
      ans[tp[i]] += bit.query(q[tp[i]]);
    }
  }
  For(i, l, mid) {
    bit.modify(q[i], -1);
  }
  solve(mid + 1, r);
}

int main() {
  int n;
  scanf("%d", &n);
  For(i, 1, n) {
    scanf("%d", &a[i]);
    p[a[i]] = i;
  }
  For(i, 1, n) {
    scanf("%d", &b[i]);
    q[b[i]] = i;
  }
  bit.n = n;
  solve(1, n);
  For(i, 1, n) {
    if (bit.query(p[i]) > ans[i]) {
      puts("NO");
      exit(0);
    }
    bit.modify(p[i], 1);
  }
  puts("YES");
  return 0;
}

B

原图一定是竞赛图,则缩点之后是一条链,答案的期望相当于所有连通块满足“所有与这个连通块相连的边都是从这个连通块连出“的概率之和。

发现同一个大小的连通块的答案可以一起算(只与特殊边有关),考虑状压 DP。

考虑只保留特殊边形成的连通块,则每个连通块至多有 \(m + 1\) 个点,枚举这些点中哪些点在连通块内,贡献可以直接计算,合并连通块做个背包即可。

#include <bits/stdc++.h>

#define IL __inline__ __attribute__((always_inline))

#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)

typedef long long LL;

template <class T>
IL bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}

template <class T>
IL bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}

template <class T>
IL T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}

template <class T>
IL T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}

template <class T>
IL T myabs(const T &a) {
  return a > 0 ? a : -a;
}

const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())

namespace Math {
const int MOD = 998244353;

IL int add(int a, int b) {
  a += b;
  return a >= MOD ? a - MOD : a;
}

template <class ...Args>
IL int add(int a, const Args &...args) {
  a += add(args...);
  return a >= MOD ? a - MOD : a;
}

IL int sub(int a, int b) {
  a -= b;
  return a < 0 ? a + MOD : a;
}

IL int mul(int a, int b) {
  return (LL)a * b % MOD;
}

template <class ...Args>
IL int mul(int a, const Args &...args) {
  return (LL)a * mul(args...) % MOD;
}

IL int quickPow(int a, int p) {
  int ret = 1;
  for (; p; p >>= 1, a = mul(a, a)) {
    if (p & 1) {
      ret = mul(ret, a);
    }
  }
  return ret;
}
}

using namespace Math;

const int MAXN = 40 + 5, MAXM = 20 + 5, MASK = 1 << 20;

using Pair = std::pair<int, int>;

int f[MAXN], g[MAXN], to[MAXN], G[MAXN][MAXN], n, m, cnt;
Pair eg[MAXM];
bool vis[MAXN];

void DFS(int u) {
  OK;
  to[u] = cnt ++;
  vis[u] = 1;
  For(i, 1, n) {
    if (~G[u][i] && !vis[i]) {
      DFS(i);
    }
  }
}

int main() {
  memset(G, -1, sizeof G);
  scanf("%d%d", &n, &m);
  int p = quickPow(10000, MOD - 2);
  For(i, 1, m) {
    int u, v, w;
    scanf("%d%d%d", &u, &v, &w);
    eg[i] = {u, v};
    G[u][v] = mul(w, p), G[v][u] = mul(10000 - w, p);
  }
  f[0] = 1;
  int cur = 0;
  For(i, 1, n) {
    if (!vis[i]) {
      memset(to, -1, sizeof to);
      memset(g, 0, sizeof g);
      cnt = 0;
      DFS(i);
      FOR(S, 0, 1 << cnt) {
        int w = __builtin_popcount(S), c = 1;
        For(j, 1, m) {
          int x = eg[j].first, y = eg[j].second, a = to[x], b = to[y];
          if (!~a || !~b) {
            continue;
          }
          if (((S >> a) & 1) && ((~S >> b) & 1)) {
            c = mul(c, add(G[x][y], G[x][y]));
          } else if (((~S >> a) & 1) && ((S >> b) & 1)) {
            c = mul(c, add(G[y][x], G[y][x]));
          }
        }
        g[w] = add(g[w], c);
      }
      cur += cnt;
      Rep(j, cur, 1) {
        For(k, 1, mymin(j, cnt)) {
          f[j] = add(f[j], mul(f[j - k], g[k]));
        }
      }
    }
  }
  int ans = 0;
  For(i, 1, n) {
    ans = add(ans, mul(f[i], quickPow((MOD + 1) / 2, i * (n - i))));
  }
  printf("%d\n", mul(ans, quickPow(10000, n * (n - 1))));
  return 0;
}

C

每一个时刻每个位置的值一定可以表示成 \(\frac{ax+b}{cx+d}\),即 \(p+\frac{q}{x+r}\) 的形式,其中除了 \(x\) 外都是常数。

那么稍微化一下就是多点求值了。

#include <bits/stdc++.h>

#define IL __inline__ __attribute__((always_inline))

#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)

typedef long long LL;

template <class T>
IL bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}

template <class T>
IL bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}

template <class T>
IL T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}

template <class T>
IL T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}

template <class T>
IL T myabs(const T &a) {
  return a > 0 ? a : -a;
}

const int INF = 0X3F3F3F3F;
const double EPS = 1E-10, PI = acos(-1.0);

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((x).size())

namespace Math {
const int MOD = 998244353;

IL int add(int a, int b) {
  a += b;
  return a >= MOD ? a - MOD : a;
}

template <class ...Args>
IL int add(int a, const Args &...args) {
  a += add(args...);
  return a >= MOD ? a - MOD : a;
}

IL int sub(int a, int b) {
  a -= b;
  return a < 0 ? a + MOD : a;
}

IL int mul(int a, int b) {
  return (LL)a * b % MOD;
}

template <class ...Args>
IL int mul(int a, const Args &...args) {
  return (LL)a * mul(args...) % MOD;
}

IL int quickPow(int a, int p) {
  int ret = 1;
  for (; p; p >>= 1, a = mul(a, a)) {
    if (p & 1) {
      ret = mul(ret, a);
    }
  }
  return ret;
}
}

using namespace Math;

const int MAXN = 100000 + 5, LOG = 19, G = 3, G_inv = 332748118, INV_2 = 499122177;

namespace Poly {
int pos[1 << LOG], root[1 << LOG], root_inv[1 << LOG], len;

IL void init(int n) {
  for (; 1 << len < n; ++ len);
  FOR(i, 0, 1 << len) {
    pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (len - 1));
  }
  int w = quickPow(G, (MOD - 1) >> len);
  root[0] = 1;
  FOR(i, 1, 1 << len) {
    root[i] = mul(root[i - 1], w);
  }
  w = quickPow(G_inv, (MOD - 1) >> len);
  root_inv[0] = 1;
  FOR(i, 1, 1 << len) {
    root_inv[i] = mul(root_inv[i - 1], w);
  }
}

IL void NTT(int *a, int n, int *root) {
  int shift = __builtin_ctz((1 << len) / n);
  FOR(i, 0, n) {
    if (i > pos[i] >> shift) {
      std::swap(a[i], a[pos[i] >> shift]);
    }
  }
  for (int i = 2; i <= n; i <<= 1) {
    int k = i >> 1;
    shift = __builtin_ctz((1 << len) / i);
    for (int *p = a; p != a + n; p += i) {
      FOR(j, 0, k) {
        int temp = mul(p[j + k], root[j << shift]);
        p[j + k] = sub(p[j], temp);
        p[j] = add(p[j], temp);
      }
    }
  }
}

IL void DFT(int *a, int n) {
  NTT(a, n, root);
}

IL void IDFT(int *a, int n) {
  NTT(a, n, root_inv);
  int inv_n = quickPow(n, MOD - 2);
  FOR(i, 0, n) {
    a[i] = mul(a[i], inv_n);
  }
}

IL void multiply(int *a, int n, int *b, int m, int *ret) {
  int len = 0;
  for (; 1 << len < n + m; ++ len);
  static int x[1 << LOG], y[1 << LOG];
  std::copy(a, a + n, x);
  memset(x + n, 0, ((1 << len) - n) * sizeof (int));
  std::copy(b, b + m, y);
  memset(y + m, 0, ((1 << len) - m) * sizeof (int));
  memset(ret, 0, (1 << len) * sizeof (int));
  DFT(x, 1 << len);
  DFT(y, 1 << len);
  FOR(i, 0, 1 << len) {
    ret[i] = mul(x[i], y[i]);
  }
  IDFT(ret, 1 << len);
  memset(ret + n + m - 1, 0, ((1 << len) - n - m + 1) * sizeof (int));
}

void inverse(int *f, int *g, int t) {
  if (t == 1) {
    g[0] = quickPow(f[0], MOD - 2);
    return;
  }
  inverse(f, g, (t + 1) >> 1);
  int len = 0;
  for (; 1 << len < t << 1; ++ len);
  static int temp[1 << LOG];
  std::copy(f, f + t, temp);
  memset(temp + t, 0, ((1 << len) - t) * sizeof (int));
  DFT(temp, 1 << len);
  DFT(g, 1 << len);
  FOR(i, 0, 1 << len) {
    g[i] = mul(g[i], sub(2, mul(temp[i], g[i])));
  }
  IDFT(g, 1 << len);
  memset(g + t, 0, ((1 << len) - t) * sizeof (int));
}

IL void reverse(int *f, int n) {
  std::reverse(f, f + n);
}

IL void inc(int *f, int *g, int n, int *ret) {
  FOR(i, 0, n) {
    ret[i] = add(f[i], g[i]);
  }
}

IL void dec(int *f, int *g, int n, int *ret) {
  FOR(i, 0, n) {
    ret[i] = sub(f[i], g[i]);
  }
}

IL void divide(int *f, int n, int *g, int m, int *q, int *r) {
  if (n < m) {
    std::copy(f, f + n, r);
    return;
  }
  reverse(f, n), reverse(g, m);
  int len = 0;
  for (; 1 << len < mymax((n - m + 1) << 1, n + 1); ++ len);
  static int temp1[1 << LOG], temp2[1 << LOG];
  memset(temp1, 0, (1 << len) * sizeof (int));
  memset(temp2, 0, (1 << len) * sizeof (int));
  std::copy(g, g + m, temp1);
  inverse(temp1, temp2, n - m + 1);
  multiply(f, n - m + 1, temp2, n - m + 1, q);
  reverse(q, n - m + 1);
  reverse(f, n), reverse(g, m);
  multiply(g, m, q, n - m + 1, temp2);
  dec(f, temp2, m - 1, r);
}

int pre_work[LOG][MAXN * 8];

void decoNTT(int *a, int level, int l, int r) {
  if (l + 1 >= r) {
    pre_work[level][l << 1] = sub(0, a[l]);
    pre_work[level][l << 1 | 1] = 1;
    return;
  }
  int mid = (l + r) >> 1;
  decoNTT(a, level + 1, l, mid);
  decoNTT(a, level + 1, mid, r);
  static int temp[1 << LOG];
  multiply(pre_work[level + 1] + (l << 1), mid - l + 1, pre_work[level + 1] + (mid << 1), r - mid + 1, temp);
  std::copy(temp, temp + r - l + 1, pre_work[level] + (l << 1));
}

int ret_eval[LOG][1 << LOG];

void getEvaluation(int *f, int *g, int level, int l, int r, int len, int n) {
  static int temp[1 << LOG];
  int p = r - l;
  divide(f, len, pre_work[level] + (l << 1), p + 1, temp, ret_eval[level] + l);
  if (l + 1 >= r) {
    g[l] = ret_eval[level][l];
    return;
  }
  int mid = (l + r) >> 1;
  getEvaluation(ret_eval[level] + l, g, level + 1, l, mid, mymin(p, n), n);
  getEvaluation(ret_eval[level] + l, g, level + 1, mid, r, mymin(p, n), n);
}

IL void evaluate(int *a, int *f, int n, int m, int *g) {
  decoNTT(a, 0, 0, m);
  getEvaluation(f, g, 0, 0, m, n, n);
}

int ans[LOG][MAXN * 8];

void solve1(int *a, int level, int l, int r) {
  if (l + 1 >= r) {
    ans[level][l << 1] = a[l];
    ans[level][l << 1 | 1] = 1;
    return;
  }
  int mid = (l + r) >> 1;
  solve1(a, level + 1, l, mid);
  solve1(a, level + 1, mid, r);
  static int temp[1 << LOG];
  multiply(ans[level + 1] + (l << 1), mid - l + 1, ans[level + 1] + (mid << 1), r - mid + 1, temp);
  std::copy(temp, temp + r - l + 1, ans[level] + (l << 1));
}

int ret[MAXN * 4];

void solve2(int level, int l, int r) {
  if (l + 1 >= r) {
    ret[l] = 1;
    return;
  }
  int mid = (l + r) >> 1;
  solve2(level + 1, l, mid);
  solve2(level + 1, mid, r);
  static int temp1[1 << LOG], temp2[1 << LOG];
  multiply(ret + l, mid - l, ans[level + 1] + (mid << 1), r - mid + 1, temp1);
  multiply(ans[level + 1] + (l << 1), mid - l + 1, ret + mid, r - mid, temp2);
  inc(temp1, temp2, r - l, ret + l);
}
}

int a[MAXN * 4], x[MAXN * 4], y[MAXN * 4], z[MAXN * 4], f[MAXN * 4], g[MAXN * 4], to[MAXN], ans[MAXN];

int main() {
#ifndef ONLINE_JUDGE
  freopen("p.in", "r", stdin);
  freopen("p.out", "w", stdout);
#endif
  int n, m;
  scanf("%d%d", &n, &m);
  Poly::init(n * 3 + 5);
  int sum = 0;
  FOR(i, 0, n) {
    scanf("%d", &a[i]);
    sum = add(sum, a[i]);
  }
  Poly::solve1(a, 0, 0, n);
  Poly::solve2(0, 0, n);
  int a = 1, b = 0, c = 0, d = 1, cnt = 0;
  FOR(i, 0, m) {
    int opt;
    scanf("%d", &opt);
    if (opt == 1) {
      int x;
      scanf("%d", &x);
      a = add(a, mul(c, x)), b = add(b, mul(d, x));
    } else {
      std::swap(a, c), std::swap(b, d);
    }
    if (!c) {
      ans[i] = mul(add(mul(sum, a), mul(b, n)), quickPow(d, MOD - 2));
      continue;
    }
    int inv = quickPow(c, MOD - 2);
    x[cnt] = mul(a, inv), y[cnt] = mul(sub(b, mul(d, x[cnt])), inv), z[cnt] = mul(d, inv);
    to[cnt ++] = i;
  }
  Poly::evaluate(z, Poly::ans[0], n + 1, cnt, f);
  Poly::evaluate(z, Poly::ret, n, cnt, g);
  FOR(i, 0, cnt) {
    ans[to[i]] = add(mul(x[i], n), mul(y[i], g[i], quickPow(f[i], MOD - 2)));
  }
  FOR(i, 0, m) {
    printf("%d\n", ans[i]);
  }
  return 0;
}
上一篇:【UOJ#495】新年的促销


下一篇:UOJ Round #19 简要题解