CodeForces Gym 101635 简要题解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wxh010910/article/details/81017099

Cakey McCakeFace

模拟。

#include <bits/stdc++.h>

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n, m;
  scanf("%d %d", &n, &m);
  vector<int> a(n), b(m);
  for (int i = 0; i < n; ++i) {
    scanf("%d", &a[i]);
  }
  for (int i = 0; i < m; ++i) {
    scanf("%d", &b[i]);
  }
  map<int, int> number;
  for (auto x : a) {
    for (auto y : b) {
      if (x <= y) {
        ++number[y - x];
      }
    }
  }
  int best = 0, answer = -1;
  for (auto p : number) {
    if (answer < p.second) {
      answer = p.second;
      best = p.first;
    }
  }
  printf("%d\n", best);
  return 0;
}

Table

枚举下边界,维护上边界的单调栈,考虑每个元素退栈的时候带来的影响,对 y 差分一次,对 x 差分两次之后影响的位置只有 O ( 1 ) 个,直接打标记就行了。

#include <bits/stdc++.h>

using namespace std;

const int N = 2005;

int n, m, k, q, top, s[N], up[N], a[N][N], answer[N][N];

int add(int l, int r, int x, int y) {
  ++answer[y][x - r + 1];
  ++answer[y][r - l];
  --answer[y][x - l + 1];
  --answer[y][1];
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  scanf("%d %d %d %d", &n, &m, &k, &q);
  while (k--) {
    int xl, xr, yl, yr;
    scanf("%d %d %d %d", &xl, &xr, &yl, &yr);
    ++a[xr][yr];
    ++a[xl][yl];
    --a[xl][yr];
    --a[xr][yl];
  }
  for (int i = n; i; --i) {
    for (int j = m; j; --j) {
      a[i][j] += a[i + 1][j] + a[i][j + 1] - a[i + 1][j + 1];
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m; ++j) {
      if (a[i][j]) {
        up[j] = 0;
      } else {
        ++up[j];
      }
    }
    top = 0;
    for (int j = 1; j <= m; ++j) {
      while (top && up[s[top]] > up[j]) {
        add(s[top - 1], s[top], j - 1, up[s[top]]);
        top--;
      }
      s[++top] = j;
    }
    while (top) {
      add(s[top - 1], s[top], m, up[s[top]]);
      top--;
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= m + 1; ++j) {
      answer[i][j] += answer[i][j - 1];
    }
  }
  for (int i = n; i; --i) {
    for (int j = m; j; --j) {
      answer[i][j] += answer[i + 1][j] + answer[i][j + 1] - answer[i + 1][j + 1];
    }
  }
  while (q--) {
    int x, y;
    scanf("%d %d", &x, &y);
    printf("%d\n", answer[x][y]);
  }
  return 0;
}

Macarons

状压,矩阵快速幂。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 260;
const int mod = 1e9;

int n, f[N], g[N];
ll m;

int add(int x, int y) {
  x += y;
  if (x >= mod) {
    x -= mod;
  }
  return x;
}

int mul(int x, int y) {
  return (ll)x * y % mod;
}

struct matrix_t {
  int a[N][N];

  matrix_t() {
    for (int i = 0; i < 1 << n; ++i) {
      for (int j = 0; j < 1 << n; ++j) {
        a[i][j] = 0;
      }
    }
  }

  matrix_t operator * (const matrix_t &b) const {
    matrix_t c;
    for (int k = 0; k < 1 << n; ++k) {
      for (int i = 0; i < 1 << n; ++i) {
        if (a[i][k]) {
          for (int j = 0; j < 1 << n; ++j) {
            if (b.a[k][j]) {
              c.a[i][j] = add(c.a[i][j], mul(a[i][k], b.a[k][j]));
            }
          }
        }
      }
    }
    return c;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  scanf("%d %lld", &n, &m);
  matrix_t base, answer;
  for (int i = 0; i < 1 << n; ++i) {
    answer.a[i][i] = 1;
  }
  for (int s = 0; s < 1 << n; ++s) {
    f[s] = 1;
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < 1 << n; ++j) {
        if (!(j >> i & 1)) {
          g[j | 1 << i] = add(g[j | 1 << i], f[j]);
        } else {
          g[j ^ 1 << i] = add(g[j ^ 1 << i], f[j]);
          g[j] = add(g[j], f[j]);
          if (i && !(j >> i - 1 & 1)) {
            g[j | 1 << i - 1] = add(g[j | 1 << i - 1], f[j]);
          }
        }
      }
      for (int j = 0; j < 1 << n; ++j) {
        f[j] = g[j];
        g[j] = 0;
      }
    }
    for (int i = 0; i < 1 << n; ++i) {
      base.a[s][i] = f[i];
      f[i] = 0;
    }
  }
  for (; m; m >>= 1, base = base * base) {
    if (m & 1) {
      answer = answer * base;
    }
  }
  printf("%d\n", answer.a[(1 << n) - 1][(1 << n) - 1]);
  return 0;
}

Candy Chain

f ( i , j ) 表示消去区间 [ i , j ] 的最大收益, g ( i , j , k ) 表示考虑区间 [ i , j ] ,当前在trie树上 k 节点的最大收益,转移要么跳过一段被消掉的区间,要么往下走,要么将这一段卖掉走到根。合法状态并不多,直接转移就可以。

#include <bits/stdc++.h>

using namespace std;

const int N = 55;
const int M = 20005;

int n, m, root, total, answer[N], value[M], f[N][N], trans[M][26], g[N][M];
char s[N], t[N];

int new_node() {
  ++total;
  value[total] = -1;
  return total;
}

void insert(int v) {
  int x = root;
  for (int i = 0; t[i]; ++i) {
    if (!trans[x][t[i] - 'a']) {
      trans[x][t[i] - 'a'] = new_node();
    }
    x = trans[x][t[i] - 'a'];
  }
  value[x] = max(value[x], v);
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  scanf("%s", s + 1);
  n = strlen(s + 1);
  root = new_node();
  scanf("%d", &m);
  while (m--) {
    int v;
    scanf("%s %d", t, &v);
    insert(v);
    reverse(t, t + strlen(t));
    insert(v);
  }
  memset(f, -1, sizeof f);
  for (int i = n; i; --i) {
    for (int j = i - 1; j <= n; ++j) {
      for (int k = 1; k <= total; ++k) {
        g[j][k] = -1;
      }
    }
    g[i - 1][root] = 0;
    for (int j = i - 1; j <= n; ++j) {
      for (int k = 1; k <= total; ++k) {
        if (~g[j][k]) {
          for (int l = j + 1; l <= n; ++l) {
            if (~f[j + 1][l]) {
              g[l][k] = max(g[l][k], g[j][k] + f[j + 1][l]);
            }
          }
          if (j < n) {
            if (trans[k][s[j + 1] - 'a']) {
              g[j + 1][trans[k][s[j + 1] - 'a']] = max(g[j + 1][trans[k][s[j + 1] - 'a']], g[j][k]);
              if (~value[trans[k][s[j + 1] - 'a']]) {
                g[j + 1][root] = max(g[j + 1][root], g[j][k] + value[trans[k][s[j + 1] - 'a']]);
              }
            }
          }
          if (k == root) {
            f[i][j] = max(f[i][j], g[j][k]);
          }
        }
      }
    }
  }
  for (int i = 1; i <= n; ++i) {
    answer[i] = answer[i - 1];
    for (int j = 1; j <= i; ++j) {
      if (~f[j][i]) {
        answer[i] = max(answer[i], answer[j - 1] + f[j][i]);
      }
    }
  }
  printf("%d\n", answer[n]);
  return 0;
}

Ingredients

模拟。

#include <bits/stdc++.h>

using namespace std;

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

int n, m, total, f[N], cost[N], value[N];
vector<pair<int, pair<int, int>>> adj[N];
map<string, int> id;
bool visit[N];

void dfs(int x) {
  visit[x] = true;
  if (adj[x].empty()) {
    return;
  }
  cost[x] = inf;
  value[x] = -inf;
  for (auto e : adj[x]) {
    int y = e.first, u = e.second.first, v = e.second.second;
    if (!visit[y]) {
      dfs(y);
    }
    if (cost[x] > cost[y] + u || (cost[x] == cost[y] + u && value[x] < value[y] + v)) {
      cost[x] = cost[y] + u;
      value[x] = value[y] + v;
    }
  }
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(0);
  cin.tie(0);
  cin >> m >> n;
  while (n--) {
    string from, to, temp;
    int cost, value;
    cin >> to >> from >> temp >> cost >> value;
    if (id.find(to) == id.end()) {
      id[to] = ++total;
    }
    if (id.find(from) == id.end()) {
      id[from] = ++total;
    }
    adj[id[to]].push_back(make_pair(id[from], make_pair(cost, value)));
  }
  for (int i = 1; i <= total; ++i) {
    if (!visit[i]) {
      dfs(i);
    }
  }
  for (int i = 1; i <= m; ++i) {
    f[i] = -inf;
  }
  for (int i = 1; i <= total; ++i) {
    for (int j = m; j >= cost[i]; --j) {
      f[j] = max(f[j], f[j - cost[i]] + value[i]);
    }
  }
  int answer = 0, best = 0;
  for (int i = 1; i <= m; ++i) {
    if (f[i] > answer) {
      answer = f[i];
      best = i;
    }
  }
  cout << answer << endl << best << endl;
  return 0;
}

Shattered Cake

答案是总面积除以宽。

#include <bits/stdc++.h>

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int w, n;
  scanf("%d %d", &w, &n);
  int sum = 0;
  while (n--) {
    int x, y;
    scanf("%d %d", &x, &y);
    sum += x * y;
  }
  printf("%d\n", sum / w);
  return 0;
}

Cordon Bleu

在餐馆新建 n 1 个点表示从餐馆出发的人,然后跑KM。

#include <bits/stdc++.h>

using namespace std;

const int N = 2005;

int n, m, answer, visit_t, l[N], r[N], lx[N], ly[N], dist[N], visit[N], parent[N], a[N][N];
pair<int, int> restaurant, bottle[N], courier[N];

void km(int n) {
  for (int i = 1; i <= n; ++i) {
    lx[i] = a[i][1];
    for (int j = 2; j <= n; ++j) {
      lx[i] = min(lx[i], a[i][j]);
    }
  }
  for (int i = 1; i <= n; ++i) {
    ly[i] = a[1][i] - lx[1];
    for (int j = 2; j <= n; ++j) {
      ly[i] = min(ly[i], a[j][i] - lx[j]);
    }
  }
  int t = 0;
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n; ++j) {
      if (!r[j] && lx[i] + ly[j] == a[i][j]) {
        l[i] = j;
        r[j] = i;
        ++t;
        break;
      }
    }
  }
  for (; t <= n; ++t) {
    int source = 0, sink;
    for (int i = 1; i <= n; ++i) {
      if (!l[i]) {
        source = i;
        break;
      }
    }
    for (int i = 1; i <= n; ++i) {
      dist[i] = a[source][i] - lx[source] - ly[i];
      parent[i] = 0;
    }
    ++visit_t;
    while (true) {
      sink = 0;
      for (int j = 1; j <= n; ++j) {
        if (visit[j] != visit_t && (!sink || dist[j] < dist[sink])) {
          sink = j;
        }
      }
      visit[sink] = visit_t;
      if (!r[sink]) {
        break;
      }
      int from = r[sink];
      for (int j = 1; j <= n; ++j) {
        if (visit[j] != visit_t) {
          int diff = dist[sink] + (a[from][j] - lx[from] - ly[j]);
          if (dist[j] > diff) {
            dist[j] = diff;
            parent[j] = sink;
          }
        }
      }
    }
    for (int j = 1; j <= n; ++j) {
      if (visit[j] == visit_t && j != sink) {
        lx[r[j]] += dist[sink] - dist[j];
        ly[j] -= dist[sink] - dist[j];
      }
    }
    lx[source] += dist[sink];
    while (parent[sink]) {
      l[r[parent[sink]]] = sink;
      r[sink] = r[parent[sink]];
      sink = parent[sink];
    }
    l[source] = sink;
    r[sink] = source;
  }
  for (int i = 1; i <= n; ++i) {
    answer += a[i][l[i]];
  }
}

int calc(pair<int, int> a, pair<int, int> b) {
  return abs(a.first - b.first) + abs(a.second - b.second);
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; ++i) {
    scanf("%d %d", &bottle[i].first, &bottle[i].second);
  }
  for (int i = 1; i <= m; ++i) {
    scanf("%d %d", &courier[i].first, &courier[i].second);
  }
  scanf("%d %d", &restaurant.first, &restaurant.second);
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= n + m - 1; ++j) {
      a[j][i] = calc(bottle[i], j <= m ? courier[j] : restaurant);
    }
  }
  km(n + m - 1);
  for (int i = 1; i <= n; ++i) {
    answer += calc(bottle[i], restaurant);
  }
  printf("%d\n", answer);
  return 0;
}

Kabobs

建出自动机,暴力搜出所有可能的在自动机上的位置集合,合法的状态并不多,暴力DP就行了。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N = 3000005;
const int mod = 1e7;

struct rule_t {
  int mid, size;
  string s;

  rule_t(string from, string to) {
    s = from + to;
    mid = from.length();
    size = s.length();
  }

  int go(int x, char c) {
    if (s[x] == c) {
      return (x + 1) % size;
    } else if (x < mid) {
      return c == s[0];
    } else {
      return (c == s[mid]) + mid;
    }
  }
};

int n, total, f[N], g[N];
vector<rule_t> limit;
string sigma, rules;
vector<int> adj[N];
map<ll, int> id;
ll realate[N];

int add(int x, int y) {
  x += y;
  if (x >= mod) {
    x -= mod;
  }
  return x;
}

ll encode(vector<int> a) {
  ll result = 0;
  for (int i = 0; i < limit.size(); ++i) {
    result = result * limit[i].size + a[i];
  }
  return result;
}

vector<int> decode(ll a) {
  vector<int> result(limit.size());
  for (int i = limit.size() - 1; ~i; --i) {
    result[i] = a % limit[i].size;
    a /= limit[i].size;
  }
  return result;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> sigma >> rules;
  for (int i = 0; i < rules.length(); ++i) {
    string from, to;
    while (rules[i] != '>') {
      from += rules[i++];
    }
    i++;
    while (i < rules.length() && rules[i] != '|') {
      to += rules[i++];
    }
    limit.push_back(rule_t(from, to));
  }
  id[0] = ++total;
  realate[total] = 0;
  for (int i = 1; i <= total; ++i) {
    vector<int> current = decode(realate[i]);
    for (auto c : sigma) {
      vector<int> next = current;
      for (int i = 0; i < limit.size(); ++i) {
        next[i] = limit[i].go(next[i], c);
      }
      ll code = encode(next);
      if (id.find(code) == id.end()) {
        id[code] = ++total;
        realate[total] = code;
      }
      adj[i].push_back(id[code]);
    }
  }
  f[1] = 1;
  for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= total; ++j) {
      if (f[j]) {
        for (auto k : adj[j]) {
          g[k] = add(g[k], f[j]);
        }
      }
    }
    for (int j = 1; j <= total; ++j) {
      f[j] = g[j];
      g[j] = 0;
    }
  }
  int answer = 0;
  for (int i = 1; i <= total; ++i) {
    vector<int> current = decode(realate[i]);
    bool flag = true;
    for (int j = 0; j < limit.size(); ++j) {
      if (current[j] >= limit[j].mid) {
        flag = false;
        break;
      }
    }
    if (flag) {
      answer = add(answer, f[i]);
    }
  }
  printf("%d\n", answer);
  return 0;
}

Burglary

f ( i , j , k ) 表示考虑第 i 层以下的,当前在楼梯 j , k ,暴力转移。

#include <bits/stdc++.h>

using namespace std;

const int N = 1005;
const int M = 5005;

int n, m, l[M], r[M], sum[M], number[N], ladder[N][15], f[N][15][15];
char board[N][M];

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; ++i) {
    scanf("%s %s", board[i] + 1, board[i + 1] + 1);
    for (int j = 1; j <= m; ++j) {
      if (board[i + 1][j] == '|') {
        ladder[i][++number[i]] = j;
      }
    }
  }
  for (int i = n + 1; i > 1; --i) {
    l[0] = 1;
    for (int j = 1; j <= m; ++j) {
      l[j] = l[j - 1];
      sum[j] = sum[j - 1];
      if (isdigit(board[i][j])) {
        l[j] = j;
        sum[j] += board[i][j] - '0';
      }
    }
    r[m + 1] = m;
    for (int j = m; j; --j) {
      r[j] = r[j + 1];
      if (isdigit(board[i][j])) {
        r[j] = j;
      }
    }
    for (int j = 1; j <= number[i - 1]; ++j) {
      for (int k = j; k <= number[i - 1]; ++k) {
        int sl = ladder[i - 1][j], sr = ladder[i - 1][k];
        f[i][j][k] = sum[r[sr]] - sum[l[sl] - 1];
        if (i != n + 1 && (sl != sr || sum[sr] == sum[sr - 1])) {
          for (int a = 1; a <= number[i]; ++a) {
            for (int b = a; b <= number[i]; ++b) {
              int tl = ladder[i][a], tr = ladder[i][b];
              if (tl != tr || sum[tr] == sum[tr - 1]) {
                if (sr <= tl) {
                  if (sum[tl] == sum[sr - 1]) {
                    f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[tr]] - sum[l[sl] - 1]);
                  }
                } else if (sl >= tr) {
                  if (sum[sl] == sum[tr - 1]) {
                    f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[sr]] - sum[l[tl] - 1]);
                  }
                } else if (l[min(sr, tr)] <= r[max(sl, tl)]) {
                  f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[max(sr, tr)]] - sum[l[min(sl, tl)] - 1]);
                } else {
                  f[i][j][k] = max(f[i][j][k], f[i + 1][a][b] + sum[r[max(sr, tr)]] - sum[l[min(sr, tr)] - 1] + sum[r[max(sl, tl)]] - sum[l[min(sl, tl)] - 1]);
                }
              }
            }
          }
        }
      }
    }
  }
  int answer = 0;
  for (int i = 1; i <= number[1]; ++i) {
    for (int j = i; j <= number[1]; ++j) {
      answer = max(answer, f[2][i][j]);
    }
  }
  printf("%d\n", answer);
  return 0;
}

Frosting on the Cake

模拟。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  vector<int> a(3, 0), b(3, 0);
  int n;
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    int x;
    scanf("%d", &x);
    a[i % 3] += x;
  }
  for (int i = 1; i <= n; ++i) {
    int x;
    scanf("%d", &x);
    b[i % 3] += x;
  }
  for (int i = 0; i < 3; ++i) {
    ll answer = 0;
    for (int j = 0; j < 3; ++j) {
      for (int k = 0; k < 3; ++k) {
        if ((j + k) % 3 == i) {
          answer += (ll)a[j] * b[k];
        }
      }
    }
    printf("%lld%c", answer, i == 2 ? '\n' : ' ');
  }
  return 0;
}

Blowing Candles

旋转卡壳。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;

const int N = 200005;
const ld inf = 1e9;

struct point_t {
  int x, y;

  point_t(int x = 0, int y = 0):x(x), y(y) {
  }

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

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

  bool operator < (const point_t &b) const {
    return x < b.x || (x == b.x && y < b.y);
  }

  ll operator * (const point_t &b) const {
    return (ll)x * b.y - (ll)y * b.x;
  }
} p[N], lower[N], upper[N], convex[N];

int n, m, upper_m, lower_m;

ld dist(point_t p, point_t q) {
  return sqrtl((ll)(p.x - q.x) * (p.x - q.x) + (ll)(p.y - q.y) * (p.y - q.y));
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n; ++i) {
    scanf("%d %d", &p[i].x, &p[i].y);
  }
  sort(p + 1, p + n + 1);
  for (int i = 1; i <= n; ++i) {
    while (lower_m > 1 && (p[i] - lower[lower_m - 1]) * (lower[lower_m] - lower[lower_m - 1]) >= 0) {
      --lower_m;
    }
    lower[++lower_m] = p[i];
  }
  for (int i = 1; i <= n; ++i) {
    while (upper_m > 1 && (p[i] - upper[upper_m - 1]) * (upper[upper_m] - upper[upper_m - 1]) <= 0) {
      --upper_m;
    }
    upper[++upper_m] = p[i];
  }
  m = 0;
  for (int i = 1; i <= lower_m; ++i) {
    convex[++m] = lower[i];
  }
  for (int i = upper_m - 1; i > 1; --i) {
    convex[++m] = upper[i];
  }
  if (m == 2) {
    puts("0");
  } else {
    convex[m + 1] = convex[1];
    ld answer = inf;
    for (int i = 1, j = 2; i <= m; ++i) {
      while ((convex[i + 1] - convex[i]) * (convex[j + 1] - convex[i]) > (convex[i + 1] - convex[i]) * (convex[j] - convex[i])) {
        j = j % m + 1;
      }
      answer = min(answer, (convex[i + 1] - convex[i]) * (convex[j] - convex[i]) / dist(convex[i], convex[i + 1]));
    }
    printf("%.8lf\n", (double)answer);
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/wxh010910/article/details/81017099