CodeForces Gym 101773 简要题解

Remainder Game:

n n 按照二进制拆位,不难发现相邻的两个 1 会对答案产生 1 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;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  int n;
  Read(n);
  printf("%d\n", __builtin_popcount(n) >> 1);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Double Trouble:

显然贪心就行了,需要注意的是不能存下每个数,但是存每个数被乘了几次就行了。

#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, a[N], f[N];
LL ans;

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n);
  for (int i = 0; i < n; ++i) {
    Read(a[i]);
  }
  for (int i = 1; i < n; ++i) {
    if (!a[i] && a[i - 1]) {
      puts("-1");
      return 0;
    }
    if (a[i] > a[i - 1]) {
      if (a[i - 1]) {
        for (; a[i - 1] << 1 <= a[i]; a[i - 1] <<= 1, --f[i]);
      }
    } else {
      for (int t = a[i]; t < a[i - 1]; t <<= 1, ++f[i]);
    }
    ans += f[i] = max(0, f[i] + f[i - 1]);
  }
  printf("%lld\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Stripe Bishops:

因为任意两个主教不能攻击,所以一个格子最多被两个主教覆盖,用 n(2h2) 减去被两个主教都覆盖的格子数就是答案,二维数点即可。

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

vector <LL> a[2], b[2];
int n, m;
LL ans;

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m), ans = 1LL * ((m << 1) - 1) * n;
  for (int i = 1, x, y; i <= n; ++i) {
    Read(x), Read(y);
    a[x + y & 1].pb(x - y);
    b[x + y & 1].pb(x + y);
  }
  for (int i = 0; i < 2; ++i) {
    sort(b[i].begin(), b[i].end());
  }
  for (int i = 0; i < 2; ++i) {
    for (auto x : a[i]) {
      ans -= upper_bound(b[i].begin(), b[i].end(), x + 2LL * (m - 1) + 1) - lower_bound(b[i].begin(), b[i].end(), x);
    }
  }
  printf("%lld\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Unsmooth Tree:

二分答案之后树形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 = 100005;
const double eps = 1e-7;

double mid, l[N], r[N];
vector <int> adj[N];
bool e[N], f[N];
char opt[10];
int n, v[N];

inline bool DFS(int x, int p) {
  if (e[x]) {
    f[x] = true;
  } else {
    f[x] = false, l[x] = r[x] = v[x];
  }
  for (auto y : adj[x]) {
    if (y != p) {
      if (!DFS(y, x)) {
        return false;
      }
      if (!f[y]) {
        if (f[x]) {
          f[x] = false, l[x] = l[y] - mid, r[x] = r[y] + mid;
        } else {
          CheckMax(l[x], l[y] - mid), CheckMin(r[x], r[y] + mid);
        }
      }
    }
  }
  return f[x] || l[x] <= r[x] + eps;
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n);
  for (int i = 1; i <= n; ++i) {
    scanf("%s", opt);
    if (opt[0] == '*') {
      e[i] = true;
    } else {
      sscanf(opt, "%d", &v[i]);
    }
  }
  for (int i = 1, x, y; i < n; ++i) {
    Read(x), Read(y);
    adj[x].pb(y), adj[y].pb(x);
  }
  double l = 0, r = 2e6;
  while (r - l > eps) {
    mid = (l + r) / 2;
    if (DFS(1, 0)) {
      r = mid;
    } else {
      l = mid;
    }
  }
  printf("%lf\n", l);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Max B B -Matching

一个结论是,记 fi f i 表示权值是 2i 2 i 的匹配个数,一定存在一个最优解,满足 f19,f18, f 19 , f 18 , ⋯ 字典序最大。

证明可以用调整法,假设某个匹配在 fi f i 处小于最优解的 fi f i ,那么至少有一条边 (u,v) ( u , v ) 满足其权值为 2i 2 i 而没有被匹配,将它们匹配,至多减少 2 2 条权值为 2i1 的边,不会变劣。

剩下就是构建一个网络流图,建立 20 20 个二进制位点记为 biti b i t i ,如果 ai a i j j 位为 1 那么 i i bitj 连边,然后按位贪心即可,这个过程可以用Hall定理优化。

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

int n, m, a[N], b[N], ret[N];
LL ans;

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 0, x; i < n; ++i) {
    Read(x), ++a[(1 << 20) - 1 ^ x];
  }
  for (int i = 0, x; i < m; ++i) {
    Read(x), ++b[(1 << 20) - 1 ^ x];
  }
  for (int i = 1; i < 1 << 20; i <<= 1) {
    for (int j = 0; j < 1 << 20; j += i << 1) {
      for (int k = 0; k < i; ++k) {
        a[j + k] += a[j + k + i], b[j + k] += b[j + k + i];
      }
    }
  }
  for (int i = 0; i < 1 << 20; ++i) {
    a[i] = n - a[i], b[i] = m - b[i];
  }
  for (int i = 19; ~i; --i) {
    int lim = 1 << 30;
    for (int j = 1 << i; j < 1 << i + 1; ++j) {
      CheckMin(lim, min(a[j], b[j]));
    }
    ans += (LL)lim << i;
    for (int j = 1 << i; j < 1 << i + 1; ++j) {
      CheckMin(a[j - (1 << i)], a[j] - lim);
      CheckMin(b[j - (1 << i)], b[j] - lim);
    }
  }
  printf("%lld\n", ans);
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}

Toroidal Picture

首先将第一行补到最后一行,然后就不用管首尾行的影响了。

f(i,j) f ( i , j ) 表示考虑前 i i 行, i 这一行移动 j j 格是否可行,g(i,j) 表示第 i1 i − 1 行不动,第 i i 行移动 j 格是否不与第 i1 i − 1 行矛盾,转移可以用FFT,输出方案直接暴力就行了。

#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 = 2097155;
const double pi = acos(-1);

struct E {
  double x, y;

  E(double x = 0, double y = 0):x(x), y(y) {}

  E operator + (const E &b) const {
    return E(x + b.x, y + b.y);
  }

  E operator - (const E &b) const {
    return E(x - b.x, y - b.y);
  }

  E operator * (const E &b) const {
    return E(x * b.x - y * b.y, x * b.y + y * b.x);
  }
} w[N], x[N], y[N], z[N];

int n, m, D, L, p[N], q[N], r[N], R[N], ans[N];
bool ff[N], gg[N], *f[N], *g[N];
char ss[N], *s[N];

inline void DFT(E *x, E *w) {
  for (int i = 0; i < D; ++i) {
    if (i < R[i]) {
      swap(x[i], x[R[i]]);
    }
  }
  for (int i = 1, l = L - 1; i < D; i <<= 1, --l) {
    for (int j = 0; j < D; j += i << 1) {
      for (int k = 0; k < i; ++k) {
        E u = x[j + k], v = x[j + k + i] * w[k * (1 << l)];
        x[j + k] = u + v, x[j + k + i] = u - v;
      }
    }
  }
}

inline void Mul(int *a, int n, int *b, int m, int *c) {
  for (D = 1, L = 0; D < n + m - 1; D <<= 1, ++L);
  for (int i = 1; i < D; ++i) {
    R[i] = (R[i >> 1] >> 1) | ((i & 1) << L - 1);
  }
  for (int i = 0; i < D; ++i) {
    z[i] = w[i] = E(cos(2 * pi * i / D), sin(2 * pi * i / D)), w[i].y = -w[i].y;
    x[i] = i < n ? E(a[i], 0) : E(0, 0), y[i] = i < m ? E(b[i], 0) : E(0, 0);
  }
  DFT(x, z), DFT(y, z);
  for (int i = 0; i < D; ++i) {
    x[i] = x[i] * y[i];
  }
  DFT(x, w);
  for (int i = 0; i < n + m - 1; ++i) {
    c[i] = x[i].x / D + 0.5;
  }
}

inline int Get(int i, int j) {
  return (s[i][j] == 'X') << 1 | (s[i][(j + 1) % m] == 'X');
}

int main() {
#ifdef wxh010910
  freopen("d.in", "r", stdin);
#endif
  Read(n), Read(m);
  for (int i = 0; i <= n; ++i) {
    s[i] = ss + i * (m + 1);
    f[i] = ff + i * (m + 1);
    g[i] = gg + i * (m + 1);
  }
  for (int i = 0; i < n; ++i) {
    scanf("%s", s[i]);
  }
  for (int i = 0; i < m; ++i) {
    s[n][i] = s[0][i];
  }
  f[0][0] = 1;
  for (int i = 1; i <= n; ++i) {
    for (int t = 1; t <= 3; ++t) {
      for (int j = 0; j < m; ++j) {
        p[j] = Get(i - 1, m - 1 - j) == t, q[j] = q[j + m] = Get(i, j) && Get(i, j) != t;
      }
      Mul(p, m, q, m << 1, r);
      for (int j = 0; j < m; ++j) {
        g[i][j] |= r[m - 1 + j];
      }
    }
    for (int j = 0; j < m; ++j) {
      g[i][j] = !g[i][j];
    }
    for (int j = 0; j < m; ++j) {
      p[j] = f[i - 1][j], q[j] = q[j + m] = g[i][j];
    }
    Mul(p, m, q, m << 1, r);
    for (int j = 0; j < m; ++j) {
      f[i][j] = r[j + m];
    }
  }
  for (int i = n, cur = 0; i; --i) {
    for (int j = 0; j < m; ++j) {
      if (f[i - 1][j] && g[i][(cur - j + m) % m]) {
        ans[i - 1] = cur = j;
        break;
      }
    }
  }
  for (int i = 0; i < n; ++i) {
    for (int j = ans[i]; j < m; ++j) {
      putchar(s[i][j]);
    }
    for (int j = 0; j < ans[i]; ++j) {
      putchar(s[i][j]);
    }
    putchar(10);
  }
#ifdef wxh010910
  Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值