CodeForces Gym 101623 간략한 문제 해결

46578 단어

Ascending Photo


먼저 이산화하고 인접한 동일한 수를 하나로 만든다.값 영역을 작은 DP에서 큰 DP로 고려하면 i와 i+1i+1 사이가 절개되지 않으면 i+1i+1과 i+2i+2 사이가 절개되어야 하기 때문에 DP 값과 지난번 결정 지점만 유지하면 됩니다.최대치와 차대치만 유지하면 이동할 수 있다는 것을 발견하기 어렵지 않다.
#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n;
  scanf("%d", &n);
  vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", &a[i]);
  }
  vector<int> disc = a;
  sort(disc.begin(), disc.end());
  disc.erase(unique(disc.begin(), disc.end()), disc.end());
  vector<vector<int>> all(disc.size() + 1);
  vector<int> b;
  for (int i = 0; i < n; ++i) {
    a[i] = lower_bound(disc.begin(), disc.end(), a[i]) - disc.begin();
    if (!b.empty() && a[i] == b.back()) {
      continue;
    }
    all[a[i]].push_back(b.size());
    b.push_back(a[i]);
  }
  n = b.size();
  pair<int, int> u = make_pair(0, n), v = make_pair(0, n);
  for (int i = 0; i < disc.size(); ++i) {
    pair<int, int> x = make_pair(u.first, n), y = make_pair(v.first, n);
    for (auto p : all[i]) {
      if (p != n - 1 && b[p] + 1 == b[p + 1]) {
        pair<int, int> value(1 + (u.second + 1 != p ? u.first : v.first), all[i + 1].size() == 1 ? n : p);
        y = max(y, value);
        if (x < y) {
          swap(x, y);
        }
      }
    }
    u = x;
    v = y;
  }
  printf("%d
"
, n - 1 - u.first); return 0; }

Boss Battle


특판 n≤3 n≤3의 경우, 그렇지 않으면 매번 boss의 가능한 위치를 1 1로 줄일 수 있으며, 답은 n-3 n-3이다.
#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n;
  scanf("%d", &n);
  printf("%d
"
, max(n - 2, 1)); return 0; }

Connect the Dots


욕심은 현재의 합법적인 각도를 지키면 된다.
#include 

using namespace std;

struct angle_t {
  int x, y, turn;

  angle_t(int x = 0, int y = 0, int turn = 0):x(x), y(y), turn(turn) {
  }

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

  int where() const {
    if (y < 0) {
      if (x >= 0) {
        return 3;
      } else {
        return 2;
      }
    } else if (y > 0) {
      if (x <= 0) {
        return 1;
      } else {
        return 0;
      }
    } else {
      if (x <= 0) {
        return 2;
      } else {
        return 0;
      }
    }
  }

  angle_t rotate() {
    return angle_t(-x, -y, turn + (where() >= 2));
  }

  bool operator < (const angle_t &b) const {
    if (turn != b.turn) {
      return turn < b.turn;
    } else if (where() != b.where()) {
      return where() < b.where();
    } else {
      return x * b.y > y * b.x;
    }
  }

  bool operator <= (const angle_t &b) const {
    return !(b < *this);
  }

  bool operator > (const angle_t &b) const {
    return b < *this;
  }

  bool operator >= (const angle_t &b) const {
    return !(*this < b);
  }
};

struct range_t {
  angle_t l, r;
  bool tl, tr;

  range_t() {
  }

  range_t(angle_t angle) {
    l = r = angle;
    tl = tr = true;
  }

  bool in(angle_t angle) {
    while (!(tl ? l <= angle : l < angle)) {
      ++angle.turn;
    }
    return tr ? angle <= r : angle < r;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n = 4, answer = 1;
  vector a(n * n);
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      int x;
      scanf("%d", &x);
      a[x - 1] = angle_t(i, j, 0);
    }
  }
  range_t current(a[1] - a[0]);
  for (int i = 2; i < n * n; ++i) {
    angle_t delta = a[i] - a[i - 1];
    if (current.in(delta)) {
      current = range_t(delta);
    } else {
      ++answer;
      angle_t l = current.l.rotate(), r = current.r.rotate();
      while (r > delta.rotate()) {
        --r.turn;
      }
      while (r.rotate() <= delta) {
        ++r.turn;
      }
      while (l >= delta.rotate()) {
        --l.turn;
      }
      while (l.rotate() < delta) {
        ++l.turn;
      }
      current = range_t(delta);
      if (r > delta) {
        current.r = r;
        current.tr = false;
      }
      if (l < delta) {
        current.l = l;
        current.tl = false;
      }
      int diff = -current.l.turn;
      current.l.turn += diff;
      current.r.turn += diff;
    }
  }
  printf("%d
"
, answer); return 0; }

Dunglish


모방하다.
#include 

using namespace std;

typedef long long ll;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(0);
  cin.tie(0);
  int n;
  cin >> n;
  vector<string> a(n);
  for (int i = 0; i < n; ++i) {
    cin >> a[i];
  }
  int m;
  cin >> m;
  map<string, int> correct, incorrect;
  map<string, string> translation;
  while (m--) {
    string from, to, state;
    cin >> from >> to >> state;
    if (state == "correct") {
      ++correct[from];
    } else {
      ++incorrect[from];
    }
    translation[from] = to;
  }
  ll ways = 1, ok = 1;
  for (int i = 0; i < n; ++i) {
    ways *= (correct[a[i]] + incorrect[a[i]]);
    ok *= correct[a[i]];
  }
  if (ways == 1) {
    for (int i = 0; i < n; ++i) {
      cout << translation[a[i]] << (i == n - 1 ? '
'
: ' '); } cout << (ok ? "correct" : "incorrect") << endl; } else { cout << ok << " correct" << endl; cout << ways - ok << " incorrect" << endl; } return 0; }

English Restaurant


탁자를 용량에 따라 정렬하고 마지막에 tt의 용량이 ∞∞인 탁자를 추가합니다.마지막 사람은 몇 개의 구간을 꽉 채웠을 것이다. 먼저 f[l][r]f[l][r][r]는 구간[l,r][l,r]만 앉은 테이블의 방안 수와 답안을 총화하고 마지막에 앉은 테이블의mid m i d를 매거한다. 양쪽은 하위 문제이고 마지막에 온 사람이 구간(al-1,amid](al-3-1,am i d)에 매거하면 옮길 수 있다.
뒤에서 앞으로 DP를 외우고 g[i][j]g[i][j]는 ii를 고려한 후의 시간을 나타낸다. 현재 구간의 가장 왼쪽 단점은 jj의 방안수와 답안을 합친 것이다. 옮길 때 지난번에 옮긴 시간과 지난번 구간의 시작 위치를 일일이 열거하고 접두사와 최적화를 사용하면 된다.
#include 

using namespace std;

typedef long double ld;

pair operator + (pair a, pair b) {
  return make_pair(a.first + b.first, a.second + b.second);
}

pair operator * (pair a, pair b) {
  return make_pair(a.first * b.second + a.second * b.first, a.second * b.second);
}

int sum(int x) {
  return x * (x + 1) >> 1;
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n, group, hours;
  scanf("%d %d %d", &n, &group, &hours);
  vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", &a[i]);
    a[i] = min(a[i], group);
  }
  sort(a.begin(), a.end());
  for (int i = 0; i < hours; ++i) {
    a.push_back(group + 1);
    ++n;
  }
  vector<vector> binom(n + 1);
  for (int i = 0; i <= n; ++i) {
    binom[i].push_back(1);
    for (int j = 1; j <= i; ++j) {
      binom[i].push_back((j != i ? binom[i - 1][j] : 0) + binom[i - 1][j - 1]);
    }
  }
  vector<vector>> dp(n, vector> (n));
  for (int j = 0; j < n; ++j) {
    for (int i = j; ~i; --i) {
      for (int k = i; k <= j; ++k) {
        pair value = make_pair(0, binom[j - i][k - i]);
        value = value * make_pair(a[k] == group + 1 ? 0 : sum(a[k]) - sum(i ? a[i - 1] : 0), min(a[k], group) - (i ? min(a[i - 1], group) : 0));
        if (k != i) {
          value = value * dp[i][k - 1];
        }
        if (k != j) {
          value = value * dp[k + 1][j];
        }
        dp[i][j] = dp[i][j] + value;
      }
    }
  }
  vector<vector>> f(hours, vector> (n)), sum(hours, vector> (n));
  for (int i = 0; i < hours; ++i) {
    for (int j = 0; j <= n + i - hours; ++j) {
      f[i][j] = dp[j][j + hours - i - 1];
    }
  }
  for (int i = hours - 1; ~i; --i) {
    for (int j = n - 1; ~j; --j) {
      for (int k = i + 1; k < hours; ++k) {
        if (j + k - i + 1 < n) {
          pair value = make_pair(0, binom[hours - i][hours - k]);
          value = value * dp[j][j + k - i - 1] * sum[k][j + k - i + 1];
          f[i][j] = f[i][j] + value;
        }
      }
      sum[i][j] = f[i][j];
      if (j + 1 < n) {
        sum[i][j] = sum[i][j] + sum[i][j + 1];
      }
    }
  }
  pair answer;
  for (int i = 0; i < n; ++i) {
    answer = answer + f[0][i];
  }
  printf("%.8lf
"
, (double)(answer.first / answer.second)); return 0; }

Factor-Free Tree


분해질 인수는 왼쪽에서 오른쪽으로 가장 먼 곳까지 모든 것과 호환성을 구하고 중간 순서에 따라 전체 서열을 두루 고려한다. 한 창고는 이전의 가장 오른쪽 체인을 표시하고 새로운 점이 생길 때마다 먼저 아래로 걸어서 아버지의 rr가 자신의 rr보다 크거나 그의 ll가 왼쪽의 자수를 덮을 수 없을 때까지 위로 올라가려고 한다.
#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n;
  scanf("%d", &n);
  vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", &a[i]);
  }
  int m = *max_element(a.begin(), a.end());
  vector<int> min_prime(m + 1), primes;
  for (int i = 2; i <= m; ++i) {
    if (!min_prime[i]) {
      min_prime[i] = i;
      primes.push_back(i);
    }
    for (auto p : primes) {
      if (i * p > m) {
        break;
      }
      min_prime[i * p] = p;
      if (i % p == 0) {
        break;
      }
    }
  }
  vector<int> l(n), r(n), last(m + 1, -1);
  for (int i = 0; i < n; ++i) {
    l[i] = -1;
    int x = a[i];
    while (x != 1) {
      int p = min_prime[x];
      l[i] = max(l[i], last[p]);
      last[p] = i;
      while (x % p == 0) {
        x /= p;
      }
    }
    ++l[i];
  }
  for (int i = 0; i <= m; ++i) {
    last[i] = n;
  }
  for (int i = n - 1; ~i; --i) {
    r[i] = n;
    int x = a[i];
    while (x != 1) {
      int p = min_prime[x];
      r[i] = min(r[i], last[p]);
      last[p] = i;
      while (x % p == 0) {
        x /= p;
      }
    }
    --r[i];
  }
  vector<int> answer(n);
  vectorint, int>, int>> stack(n + 1);
  stack[0].first.second = -1;
  int top = 0;
  for (int i = 0; i < n; ++i) {
    stack[top + 1].first.second = -1;
    int temp = i;
    while (top && l[i] <= stack[top].first.first && r[i] >= stack[top].second) {
      temp = min(temp, stack[top].first.first);
      --top;
    }
    if (~stack[top + 1].first.second) {
      answer[stack[top + 1].first.second] = i;
    }
    answer[i] = stack[top].first.second;
    int right = top ? stack[top].second : n;
    if (right < i) {
      puts("impossible");
      return 0;
    }
    stack[++top] = make_pair(make_pair(temp, i), min(r[i], right));
  }
  for (int i = 0; i < n; ++i) {
    printf("%d%c", answer[i] + 1, i == n - 1 ? '
'
: ' '); } return 0; }

Glyph Recognition


매거 변수는 공식적으로 두 개의 bound를 계산해 낼 수 있고 직접 계산하면 된다.
#include 

using namespace std;

typedef long long ll;
typedef long double ld;

const ld pi = acosl(-1);
const ld inf = 1e9;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n;
  scanf("%d", &n);
  vector<int> x(n), y(n);
  for (int i = 0; i < n; ++i) {
    scanf("%d %d", &x[i], &y[i]);
  }
  ld answer = 0;
  int best = -1;
  for (int i = 3; i <= 8; ++i) {
    ld inner = inf, outer = 0;
    for (int j = 0; j < n; ++j) {
      ld angle = atan2(y[j], x[j]);
      while (angle < 0) {
        angle += 2 * pi / i;
      }
      while (angle >= 2 * pi / i) {
        angle -= 2 * pi / i;
      }
      ld dist = sqrtl((ll)x[j] * x[j] + (ll)y[j] * y[j]) * cosl(angle - pi / i);
      inner = min(inner, dist);
      outer = max(outer, dist);
    }
    ld ratio = inner / outer;
    ratio *= ratio;
    if (ratio > answer) {
      answer = ratio;
      best = i;
    }
  }
  printf("%d %.8lf
"
, best, (double)answer); return 0; }

High Score


제곱의 성장이 비교적 빠르기 때문에 작은 두 개가 얼마나 증가했는지 매거할 수 있다. 이 값은 크지 않고 폭력이면 된다.
#include 

using namespace std;

typedef long long ll;

ll calc(int a, int b, int c) {
  return (ll)a * a + (ll)b * b + (ll)c * c + 7ll * min(a, min(b, c));
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int T;
  scanf("%d", &T);
  while (T--) {
    int a, b, c, d;
    scanf("%d %d %d %d", &a, &b, &c, &d);
    ll answer = 0;
    for (int i = 0; i <= d && i <= 100; ++i) {
      for (int j = 0; i + j <= d && j <= 100; ++j) {
        int k = d - i - j;
        answer = max(answer, calc(a + i, b + j, c + k));
        answer = max(answer, calc(a + i, b + k, c + j));
        answer = max(answer, calc(a + k, b + i, c + j));
      }
    }
    printf("%lld
"
, answer); } return 0; }

Installing Apps


만약에 모든 것을 선택한다면 가장 좋은 순서는 반드시 max(d,s) - d max(d,s) - - d에 따라 큰 것부터 작은 것까지 순서를 정하고 f(i,j) f(i,j)를 외우는 것이 전 ii의 물품을 고려하고 j개를 선택했는데 최소한 얼마의 공간을 차지했는지 나타낸다.
#include 

using namespace std;

struct info_t {
  int need, get, id;

  info_t(int need = 0, int get = 0, int id = 0):need(need), get(get), id(id) {
  }

  bool operator < (const info_t &b) const {
    return get > b.get;
  }
};

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n, size;
  scanf("%d %d", &n, &size);
  vector apps(n);
  for (int i = 0; i < n; ++i) {
    int disk, storage;
    scanf("%d %d", &disk, &storage);
    apps[i] = info_t(max(disk, storage), max(disk, storage) - storage, i);
  }
  sort(apps.begin(), apps.end());
  vector<vector<int>> f(n + 1, vector<int> (n + 1, size + 1));
  vector<vector<bool>> g(n + 1, vector<bool> (n + 1, false));
  f[0][0] = 0;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j <= i; ++j) {
      f[i + 1][j] = f[i][j];
    }
    for (int j = 0; j <= i; ++j) {
      if (f[i][j] + apps[i].need <= size && f[i + 1][j + 1] > f[i][j] + apps[i].need - apps[i].get) {
        f[i + 1][j + 1] = f[i][j] + apps[i].need - apps[i].get;
        g[i + 1][j + 1] = true;
      }
    }
  }
  for (int i = n; ~i; --i) {
    if (f[n][i] <= size) {
      printf("%d
"
, i); if (i) { vector<int> answer; for (int j = n, current = i; j; --j) { if (g[j][current]) { --current; answer.push_back(apps[j - 1].id); } } reverse(answer.begin(), answer.end()); for (int j = 0; j < answer.size(); ++j) { printf("%d%c", answer[j] + 1, j == answer.size() - 1 ? '
'
: ' '); } } return 0; } } return 0; }

Juggling Troupe


22마다 단독으로 고려하여 ii라고 가정하고 그 좌우의 000의 위치 l,rl,r를 구하면 l,rl,r를 1로 부여하고 l+r-3-i l+r-3을 0으로 부여한다.set로 유지보수하면 됩니다.
#include 

using namespace std;

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(0);
  cin.tie(0);
  string str;
  cin >> str;
  int n = str.length();
  set<int> s;
  s.insert(-1);
  s.insert(n);
  for (int i = 0; i < n; ++i) {
    if (str[i] == '0') {
      s.insert(i);
    }
  }
  for (int i = 0; i < n; ++i) {
    if (str[i] == '2') {
      auto l = s.lower_bound(i), r = l;
      --l;
      int x = *l + *r - i;
      if (~*l) {
        s.erase(l);
      }
      if (*r < n) {
        s.erase(r);
      }
      s.insert(x);
    }
  }
  string answer(n, '1');
  for (auto p : s) {
    if (p >= 0 && p < n) {
      answer[p] = '0';
    }
  }
  cout << answer << endl;
  return 0;
}

Knockout Tournament


a1a1을 0 0으로 보고 aa에 따라 작은 순서에서 큰 순서로 인접한 매칭이 가장 좋다.그리고 트리 DP를 만들면 됩니다.
#include 

using namespace std;

typedef long double ld;

void dfs(int x, int m, int &index, vector<vectorint, ld>>> &f) {
  if ((x << 1 | 1) >= m) {
    f[x].push_back(make_pair(--index, 1));
  } else {
    dfs(x << 1 | 1, m, index, f);
    dfs(x + 1 << 1, m, index, f);
  }
}

int main() {
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  int n;
  scanf("%d", &n);
  vector<int> a(n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", &a[i]);
  }
  int first = a[0];
  a[0] = 0;
  sort(a.begin(), a.end());
  a[0] = first;
  int m = (n << 1) - 1, binary = 1;
  while ((binary << 1 | 1) <= m) {
    binary = binary << 1 | 1;
  }
  vector<vectorint, ld>>> f(m);
  int index = n;
  dfs(0, m, index, f);
  for (int i = m - n - 1, j = 0; ~i; --i) {
    int l = i << 1 | 1, r = i + 1 << 1;
    for (int rotate = 0; rotate < 2; ++rotate) {
      for (auto p : f[l]) {
        int index = p.first;
        ld prob = 0;
        for (auto q : f[r]) {
          prob += q.second * a[index] / (a[index] + a[q.first]);
        }
        f[i].push_back(make_pair(index, prob * p.second));
      }
      swap(l, r);
    }
  }
  for (auto p : f[0]) {
    if (!p.first) {
      printf("%.8lf
"
, (double)p.second); } } return 0; }

좋은 웹페이지 즐겨찾기