Goodbye Yiwei

A

贪心的取,后缀 \(\min\) 比栈顶和栈底小就一直取到后缀 \(\min\),否则取栈顶和栈底中最小的。

#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;

std::deque<int> dq;
int a[MAXN], suf[MAXN];

int main() {
  int T;
  scanf("%d", &T);
  while (T --) {
    dq.clear();
    int n;
    scanf("%d", &n);
    For(i, 1, n) {
      scanf("%d", &a[i]);
    }
    suf[n + 1] = INF;
    Rep(i, n, 1) {
      suf[i] = mymin(suf[i + 1], a[i]);
    }
    int cur = 1, cnt = 0;
    while (cnt < n) {
      while (dq.empty() || mymin(dq.front(), dq.back()) > suf[cur]) {
        dq.push_back(a[cur ++]);
      }
      while (!dq.empty() && mymin(dq.front(), dq.back()) < suf[cur]) {
        if (dq.front() < dq.back()) {
          printf("%d ", dq.front());
          dq.pop_front();
        } else {
          printf("%d ", dq.back());
          dq.pop_back();
        }
        ++ cnt;
      }
    }
    puts("");
  }
  return 0;
}

B

一个点是安全的当且仅当:

1.它的度数为 \(1\)
2.它和一个度数为 \(1\) 的点相连;
3.存在一个点,忽略它和这个点的连边后这两个点相邻的点相同。

前两个条件很好判断,第三个条件如果两个点不相邻排个序就行了,相邻的话直接枚举每条边然后暴力判断即可。

这个暴力复杂度是对的,因为它等价于这个式子:

\[\sum^m[deg_u = deg_v]deg_u \]

每个点至多贡献 \(O(\sqrt{m})\) 次,而所有点的度数和为 \(O(m)\),所以复杂度是 \(O(m\sqrt{m})\)

#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())

struct Input {
  char buf[1 << 25], *s;

  Input() {
#ifndef ONLINE_JUDGE
    freopen("police.in", "r", stdin);
#endif
    fread(s = buf, 1, 1 << 25, stdin);
  }

  friend Input &operator>>(Input &io, int &x) {
    x = 0;
    while (!isdigit(*io.s)) {
      ++ io.s;
    }
    while (isdigit(*io.s)) {
      x =  x * 10 + *io.s ++ - '0';
    }
    return io;
  }
} cin;

const int MAXN = 100000 + 5, MAXM = 200000 + 5;

struct Edge {
  int u, v;
} edge[MAXM];

std::vector<int> adj[MAXN];
std::pair<std::vector<int>, int> tp[MAXN];
int deg[MAXN];
bool ok[MAXN];

int main() {
  int T;
  cin >> T;
  while (T --) {
    int n, m;
    cin >> n >> m;
    memset(deg, 0, sizeof deg);
    memset(ok, 0, sizeof ok);
    For(i, 1, n) {
      adj[i].clear();
    }
    For(i, 1, m) {
      cin >> edge[i].u >> edge[i].v;
      ++ deg[edge[i].u], ++ deg[edge[i].v];
      adj[edge[i].u].push_back(edge[i].v);
      adj[edge[i].v].push_back(edge[i].u);
    }
    For(i, 1, n) {
      std::sort(adj[i].begin(), adj[i].end());
      tp[i] = {adj[i], i};
    }
    std::sort(tp + 1, tp + n + 1);
    FOR(i, 1, n) {
      if (tp[i].first == tp[i + 1].first) {
        ok[tp[i].second] = ok[tp[i + 1].second] = 1;
      }
    }
    For(i, 1, m) {
      if (deg[edge[i].u] == 1 || deg[edge[i].v] == 1) {
        ok[edge[i].u] = ok[edge[i].v] = 1;
      }
    }
    For(i, 1, m) {
      if ((!ok[edge[i].u] || !ok[edge[i].v]) && deg[edge[i].u] == deg[edge[i].v]) {
        int u = edge[i].u, v = edge[i].v;
        bool yes = 1;
        for (int x = 0, y = 0; x < SZ(adj[u]) && y < SZ(adj[v]); ++ x, ++ y) {
          if (adj[u][x] == v) {
            ++ x;
          }
          if (adj[v][y] == u) {
            ++ y;
          }
          if (x >= SZ(adj[u]) || y >= SZ(adj[v])) {
            break;
          }
          if (adj[u][x] != adj[v][y]) {
            yes = 0;
            break;
          }
        }
        if (yes) {
          ok[u] = ok[v] = 1;
        }
      }
    }
    int cnt = 0;
    For(i, 1, n) {
      cnt += ok[i];
    }
    printf("%d\n", cnt);
    For(i, 1, n) {
      if (ok[i]) {
        printf("%d ", i);
      }
    }
    puts("");
  } 
  return 0;
}

C

考虑 Boruvka 算法,每轮给每个连通块赋一个颜色,然后逐位确定最大连边的权值,可以发现你实际上要求的是某个集合的超集的最大值和次大值(为了判断是否只有一种颜色),高维前缀和即可。

#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, MASK = 1 << 18;

struct DisjointSet {
  int fa[MAXN];

  void init(int n) {
    For(i, 1, n) {
      fa[i] = i;
    }
  }

  int find(int u) {
    return fa[u] == u ? u : fa[u] = find(fa[u]);
  }

  bool same(int u, int v) {
    return find(u) == find(v);
  }

  void merge(int u, int v) {
    if (!same(u, v)) {
      fa[fa[v]] = fa[u];
    }
  }
} dsu;

int a[MAXN], col[MAXN], tp[MAXN], to[MAXN], val[MAXN], col_sec[MASK], col_max[MASK], num_sec[MASK], num_max[MASK];

int main() {
#ifndef ONLINE_JUDGE
  freopen("andmst.in", "r", stdin);
#endif
  int n, m;
  scanf("%d%d", &n, &m);
  For(i, 1, n) {
    scanf("%d", &a[i]);
  }
  int cnt = 0, cur = n;
  For(i, 1, n) {
    col[i] = i;
  }
  LL ans = 0;
  while (cnt < n - 1) {
    dsu.init(cur);
    memset(col_sec, 0, sizeof col_sec);
    memset(col_max, 0, sizeof col_max);
    memset(num_sec, 0, sizeof num_sec);
    memset(num_max, 0, sizeof num_max);
    For(i, 1, n) {
      if (col_max[a[i]] < col[i]) {
        col_sec[a[i]] = col_max[a[i]];
        col_max[a[i]] = col[i];
        num_sec[a[i]] = num_max[a[i]];
        num_max[a[i]] = i;
      } else if (col_max[a[i]] != col[i] && col_sec[a[i]] < col[i]) {
        col_sec[a[i]] = col[i];
        num_sec[a[i]] = i;
      }
    }
    FOR(i, 0, m) {
      REP(S, 1 << m, 0) {
        if ((~S >> i) & 1) {
          if (col_max[S] < col_max[S | (1 << i)]) {
            col_sec[S] = col_max[S];
            col_max[S] = col_max[S | (1 << i)];
            num_sec[S] = num_max[S];
            num_max[S] = num_max[S | (1 << i)];
            if (col_sec[S] < col_sec[S | (1 << i)]) {
              col_sec[S] = col_sec[S | (1 << i)];
              num_sec[S] = num_sec[S | (1 << i)];
            }
          } else if (col_max[S] != col_max[S | (1 << i)] && col_sec[S] < col_max[S | (1 << i)]) {
            col_sec[S] = col_max[S | (1 << i)];
            num_sec[S] = num_max[S | (1 << i)];
          } else if (col_max[S] == col_max[S | (1 << i)] && col_sec[S] < col_sec[S | (1 << i)]) {
            col_sec[S] = col_sec[S | (1 << i)];
            num_sec[S] = num_sec[S | (1 << i)];
          }
        }
      }
    }
    For(i, 1, cur) {
      to[i] = 0, val[i] = -1;
    }
    For(i, 1, n) {
      int s = 0;
      REP(j, m, 0) {
        if ((a[i] >> j) & 1) {
          int t = s << 1 | 1, p = t << j;
          if (col_max[p] && (col_max[p] != col[i] || (col_sec[p] && col_sec[p] != col[i]))) {
            s = t;
          } else {
            s = t - 1;
          }
        } else {
          s <<= 1;
        }
      }
      int v = col_max[s] == col[i] ? num_sec[s] : num_max[s], w = a[i] & a[v];
      if (chkmax(val[col[i]], w)) {
        to[col[i]] = col[v];
      }
    }
    For(i, 1, cur) {
      if (!dsu.same(i, to[i])) {
        dsu.merge(i, to[i]);
        ++ cnt;
        ans += val[i];
      }
    }
    int fn = 0;
    For(i, 1, cur) {
      if (dsu.find(i) == i) {
        tp[i] = ++ fn;
      }
    }
    For(i, 1, cur) {
      tp[i] = tp[dsu.find(i)];
    }
    For(i, 1, n) {
      col[i] = tp[col[i]];
    }
    cur = fn;
  }
  printf("%lld\n", ans);
  return 0;
}

D

先二分答案,然后考虑倒着做,把合并变成划分,然后就变成了你初始有一个雷,每次你可以把一个威力为 \(k\) 的雷变成 \(m\) 个威力为 \(\{k - b_1, k - b_2, \cdots, k - b_m\}\) 的雷,最后要让排序后每个雷的威力都大于等于对应位置的 \(a_i\)

我们称雷的集合 \(S\) 可以匹配集合 \(T\),当且仅当 \(S\) 可以通过一系列拆分操作使得 \(|S| = |T|\),且排序后 \(S\) 中对应位置的雷的威力都大于 \(T\) 中的。

每次考虑 \(S\) 中最大的雷能否拆出能匹配 \(T\) 中最大的雷的雷,否则就把 \(T\) 中最大的雷匹配掉,用 multiset 维护即可。

#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 = 50000 + 5;

int a[MAXN], b[MAXN];

IL bool check(int n, int m, LL k) {
  std::multiset<LL> s({k}), t(a + 1, a + n + 1);
  while (SZ(s) < SZ(t)) {
    if (s.empty()) {
      return 0;
    }
    LL x = *s.rbegin(), y = *t.rbegin();
    if (x - b[1] >= y) {
      For(i, 1, m) {
        s.insert(x - b[i]);
      }
      s.erase(s.find(x));
    } else {
      auto it = s.lower_bound(y);
      if (it == s.end()) {
        return 0;
      }
      s.erase(it), t.erase(t.find(y));
    }
  }
  for (auto x = s.begin(), y = t.begin(); x != s.end() && y != t.end(); ++ x, ++ y) {
    if (*x < *y) {
      return 0;
    }
  }
  return 1;
}

int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  For(i, 1, n) {
    scanf("%d", &a[i]);
  }
  For(i, 1, m) {
    scanf("%d", &b[i]);
  }
  std::sort(a + 1, a + n + 1);
  std::sort(b + 1, b + m + 1);
  LL l = a[n], r = a[n] + (LL)(n - 1) / (m - 1) * b[m], ans = 0;
  while (l <= r) {
    LL mid = (l + r) >> 1;
    if (check(n, m, mid)) {
      ans = mid, r = mid - 1;
    } else {
      l = mid + 1;
    }
  }
  printf("%lld\n", ans);
  return 0;
}

E

发现如果值域是 \([0,1024]\) 的话可以用长为 \(10240\) 的串传送,于是考虑一个 hash 函数把这 \(1024\) 个坐标映射到这个范围上去。

问题在于随机这个函数的话需要的次数太多了,考虑转换一下方法,每次把这些坐标分成两半,这样随机次数就可以接受了。

但这样需要传送的次数太多了,于是可以考虑小范围用开始的方法暴力随。

有一个问题是如果你用定长编码传送次数,那么这个定长会比较大,所以可以使用不定长编码,具体实现可以参见代码。

#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 = 1024, MAXM = 20000 + 5;

IL unsigned xorShift() {
  static unsigned x = 20030102;
  x ^= x << 13;
  x ^= x >> 17;
  x ^= x << 5;
  return x;
}

struct Hash {
  static const int MOD = 998244353;

  int a, b;

  Hash() : a(114514), b(1919810) {}

  void next() {
    a = xorShift() % MOD, b = xorShift() % MOD;
  }

  int get(unsigned x) {
    return ((LL)a * x + b) % MOD;
  }
} h;

namespace Encode {
unsigned key[MAXN];
int val[MAXN], to[MAXN], cur;
bool ret[MAXM];

IL void print(int x, int digit, bool mode) {
  if (mode) {
    int real = x ? std::__lg(x) + 1 : 0;
    For(i, 1, real - digit) {
      ret[cur ++] = 1;
    }
    ret[cur ++] = 0;
  }
  for (; x; x >>= 1, -- digit) {
    ret[cur ++] = x & 1;
  }
  for (; digit > 0; -- digit) {
    ret[cur ++] = 0;
  }
}

void solve(const std::vector<int> &v, int high) {
  static int tp[MAXN];
  int times = 0;
  if (SZ(v) <= 8) {
    while (1) {
      FOR(i, 0, 8) {
        tp[i] = -1;
      }
      FOR(i, 0, 8) {
        tp[h.get(key[v[i]]) % 8] = v[i];
      }
      bool ok = 1;
      FOR(i, 0, 8) {
        if (!~tp[i]) {
          ok = 0;
          break;
        }
      }
      if (ok) {
        break;
      }
      ++ times;
      h.next();
    }
    FOR(i, 0, 8) {
      to[high << 3 | i] = tp[i];
    }
    print(times, 9, 1);
    return;
  }
  int n = SZ(v);
  while (1) {
    FOR(i, 0, n) {
      tp[i] = h.get(key[v[i]]) % 2;
    }
    int cnt = 0;
    FOR(i, 0, n) {
      cnt += tp[i];
    }
    if (cnt == n / 2) {
      break;
    }
    ++ times;
    h.next();
  }
  print(times, 4, 1);
  std::vector<int> x, y;
  FOR(i, 0, n) {
    if (tp[i]) {
      y.push_back(v[i]);
    } else {
      x.push_back(v[i]);
    }
  }
  solve(x, high << 1), solve(y, high << 1 | 1);
}

IL void main() {
  FOR(i, 0, MAXN) {
    scanf("%u%d", &key[i], &val[i]);
  }
  std::vector<int> v(MAXN);
  FOR(i, 0, MAXN) {
    v[i] = i;
  }
  solve(v, 0);
  FOR(i, 0, MAXN) {
    print(val[to[i]], 10, 0);
  }
  FOR(i, 0, cur) {
    putchar('0' + ret[i]);
  }
  puts("");
}
}

namespace Decode {
unsigned val[MAXN];
int to[MAXN], ans[MAXN], cur;
int len;
char str[MAXM];

IL int read(int digit, bool mode) {
  int more = 0;
  if (mode) {
    while (str[cur ++] == '1') {
      ++ more;
    }
  }
  int ans = 0;
  FOR(i, 0, digit + more) {
    ans += (str[cur ++] - '0') << i;
  }
  return ans;
}

void solve(const std::vector<int> &v, int cur, int high) {
  if (cur <= 8) {
    int times = read(9, 1);
    For(i, 1, times) {
      h.next();
    }
    for (auto &x : v) {
      to[high << 3 | (h.get(val[x]) % 8)] = x;
    }
    return;
  }
  int times = read(4, 1);
  For(i, 1, times) {
    h.next();
  }
  std::vector<int> x, y;
  for (auto &a : v) {
    if (h.get(val[a]) % 2) {
      y.push_back(a);
    } else {
      x.push_back(a);
    }
  }
  solve(x, cur >> 1, high << 1), solve(y, cur >> 1, high << 1 | 1);
}

IL void main() {
  memset(to, -1, sizeof to);
  scanf("%s", str);
  len = strlen(str);
  int q;
  scanf("%d", &q);
  std::vector<int> v(q);
  FOR(i, 0, q) {
    scanf("%u", &val[i]);
    v[i] = i;
  }
  solve(v, MAXN, 0);
  FOR(i, 0, MAXN) {
    int x = read(10, 0);
    if (to[i] != -1) {
      ans[to[i]] = x;
    }
  }
  FOR(i, 0, q) {
    printf("%d\n", ans[i]);
  }
}
}
int main() {
#ifndef ONLINE_JUDGE
  freopen("decode.in", "r", stdin);
  freopen("decode.out", "w", stdout);
#endif
  char str[10];
  scanf("%s", str);
  if (str[0] == 'e') {
    Encode::main();
  } else {
    Decode::main();
  }
  return 0;
}
posted @ 2020-01-15 15:45  sjkmost  阅读(130)  评论(0编辑  收藏  举报