CodeForces Gym 102156 简要题解

Takeover

每次贪心选增量最小的。

#include <bits/stdc++.h>

using namespace std;

int main() {
   
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin >> n;
  vector<int> x(n), y(n);
  for (int i = 0; i < n; ++i) {
   
    cin >> x[i] >> y[i];
  }
  vector<int> by_x(n), by_y(n), by_z(n);
  for (int i = 0; i < n; ++i) {
   
    by_x[i] = by_y[i] = by_z[i] = i;
  }
  sort(by_x.begin(), by_x.end(), [&](int a, int b) {
   
    return x[a] < x[b];
  });
  sort(by_y.begin(), by_y.end(), [&](int a, int b) {
   
    return y[a] < y[b];
  });
  sort(by_z.begin(), by_z.end(), [&](int a, int b) {
   
    return x[a] + y[a] < x[b] + y[b];
  });
  int ptr_x = 0, ptr_y = 0, ptr_z = 0;
  int cur_x = 1, cur_y = 1;
  priority_queue<pair<int, int>> q_x, q_y;
  vector<bool> done(n);
  for (int rep = 0; rep < n; ++rep) {
   
    while (ptr_x < n && x[by_x[ptr_x]] <= cur_x) {
   
      q_y.emplace(-y[by_x[ptr_x]], by_x[ptr_x]);
      ++ptr_x;
    }
    while (ptr_y < n && y[by_y[ptr_y]] <= cur_y) {
   
      q_x.emplace(-x[by_y[ptr_y]], by_y[ptr_y]);
      ++ptr_y;
    }
    while (ptr_z < n && (done[by_z[ptr_z]] || x[by_z[ptr_z]] <= cur_x || y[by_z[ptr_z]] <= cur_y)) {
   
      ++ptr_z;
    }
    while (!q_x.empty() && done[q_x.top().second]) {
   
      q_x.pop();
    }
    while (!q_y.empty() && done[q_y.top().second]) {
   
      q_y.pop();
    }
    pair<int, int> choice = make_pair(INT_MAX, -1);
    if (!q_x.empty()) {
   
      choice = min(choice, make_pair(max(0, -(q_x.top().first + cur_x)), q_x.top().second));
    }
    if (!q_y.empty()) {
   
      choice = min(choice, make_pair(max(0, -(q_y.top().first + cur_y)), q_y.top().second));
    }
    if (ptr_z < n) {
   
      choice = min(choice, make_pair(x[by_z[ptr_z]] + y[by_z[ptr_z]] - cur_x - cur_y, by_z[ptr_z]));
    }
    int id = choice.second;
    done[id] = true;
    cur_x = max(cur_x, x[id]);
    cur_y = max(cur_y, y[id]);
    if (rep) {
   
      cout << " ";
    }
    cout << id + 1;
  }
  cout << "\n";
  return 0;
}

Unfair Card Deck

f ( i , j ) f(i,j) f(i,j) 表示 i i i j j j 前出现次数,则 f ( i , j ) / f ( j , i ) f(i,j)/f(j,i) f(i,j)/f(j,i) 可以近似得到 w i w_i wi w j w_j wj 的比值。考虑每次选出 w w w 最大的,用所有已有的卡片来计算平均值。需要注意的是,如果 f ( i , j ) / f ( j , i ) &lt; 1 0 − 3 f(i,j)/f(j,i)&lt;10^{-3} f(i,j)/f(j,i)<103 ,这个卡片是相对没有代表性的,它不能很好反映概率,应该丢掉。如果所有已经确定卡片都在当前卡片前面出现,则它们都没有代表性,需要用之前最小的 w w w 乘上 1 0 − 7 10^{-7} 107 (极大概率出现在他们后面,同时也能区分后面的卡片)。

#include <bits/stdc++.h>

using namespace std;

typedef long double ld;

int main() {
   
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cout.setf(ios::fixed);
  cout.precision(290);
  int m, n;
  cin >> m >> n;
  int cards = 0;
  for (int i = 0; i < n; ++i) {
   
    int x;
    cin >> x;
    cards += x;
  }
  vector<vector<int>> before(n, vector<int>(n));
  for (int i = 0; i < m; ++i) {
   
    vector<int> log(cards);
    for (int j = 0; j < cards; ++j) {
   
      cin >> log[j];
      --log[j];
    }
    for (int j = 0; j < cards; ++j) {
   
      for (int k = j + 1; k < cards; ++k) {
   
        if (log[j] != log[k]) {
   
          ++before[log[j]][log[k]];
        }
      }
    }
  }
  vector<bool> used(n);
  vector<ld> ans(n);
  int first = 0;
  for (int i = 1; i < n; ++i) {
   
    if (before[i][first] > before[first][i]) {
   
      first = i;
    }
  }
  used[first] = true;
  ans[first] = 1;
  for (int rep = 1; rep < n; ++rep) {
   
    vector<ld> prob(n);
    for (int i = 0; i < n; ++i) {
   
      if (!used[i]) {
   
        vector<int> all;
        for (int j = 0; j < n; ++j) {
   
          if (used[j]) {
   
            all.push_back(j);
          }
        }
        sort(all.begin(), all.end(), [&](int a, int b) {
   
          return ans[a] < ans[b];
        });
        while ((int) all.size() > 1 && before[i][all.back()] < before[all.back()][i] * 1e-3) {
   
          all.pop_back();
        }
        ld ave = 0;
        for (auto j : all) {
   
          ave += before[i][j] * ans[j] / before[j][i];
        }
        ave /= all.size();
        if (ave < 1e-300) {
   
          prob[i] = 1;
          for (int j = 0; j < n; ++j) {
   
            if (used[j]) {
   
              prob[i] = min(prob[i], ans[j]);
            }
          }
          prob[i] *= 1e-7;
        } else {
   
          prob[i] = ave;
        }
      }
    }
    int p = -1;
    for (int i = 0; i < n; ++i) {
   
      if (!used[i] && (p == -1 || prob[i] > prob[p] || (prob[i] == prob[p] && before[i][p] > before[p][i]))) {
   
        p = i;
      }
    }
    ans[p] = prob[p];
    used[p] = true;
  }
  for (int i = 0; i < n; ++i) {
   
    if (ans[i] < 1e-233) {
   
      ans[i] = 1e-233;
    }
    if (ans[i] > 1) {
   
      ans[i] = 1;
    }
    cout << ans[i] << "\n";
  }
  return 0;
}

Diverse Singing

对于每个点每种颜色限流,跑上下界网络流即可。

#include <bits/stdc++.h>

using namespace std;

using cap_t = int;

const int cap_inf = 0x3f3f3f3f;

namespace flow {
   
struct edge {
   
  int to, rev;
  cap_t cap;
  
  edge(int t, cap_t c, int r) {
   
    to = t;
    cap = c;
    rev = r;
  }
};

vector<vector<edge>> adj;
vector<int> cur, dist;
int n, source, sink;
cap_t ans;

void init(int v, int s, int t) {
   
  n = v;
  ans = 0;
  source = s;
  sink = t;
  adj.clear();
  adj.resize(n);
  cur.resize(n);
  dist.resize(n);
}

void add(int x, int y, cap_t c) {
   
  adj[x].emplace_back(y, c, adj[y].size());
  adj[y].emplace_back(x, 0, adj[x].size() - 1);
}

bool bfs() {
   
  queue<int> q;
  for (int i = 0; i < n; ++i) {
   
    dist[i] = -1;
  }
  dist[source] = 0;
  q.push(source);
  while (!q.empty()) {
   
    int x = q.front();
    q.pop();
    for (auto e : adj[x]) {
   
      if (e.cap && !~dist[e.to]) {
   
        dist[e.to] = dist[x] + 1;
        if (e.to == sink) {
   
          return true;
        }
        q.push(e.to);
      }
    }
  }
  return false;
}

cap_t dfs(int x, cap_t f) {
   
  if (x == sink) {
   
    return f;
  }
  for (int &i = cur[x]; ~i; --i) {
   
    edge &e = adj[x][i];
    if (e.cap && dist[e.to] == dist[x] + 1) {
   
      cap_t w = dfs(e.to, min(e.cap, f));
      if (w) {
   
        e.cap -= w;
        adj[e.to][e.rev].cap += w;
        return w;
      }
    }
  }
  return 0;
}

cap_t max_flow() {
   
  while (bfs()) {
   
    for (int i = 0; i < n; ++i) {
   
      cur[i] = adj[i].size() - 1;
    }
    while (true) {
   
      cap_t flow = dfs(source, cap_inf);
      if (!flow) {
   
        break;
      }
      ans += flow;
    }
  }
  return ans;
}
}

using flow::init;
using flow::add;
using flow::max_flow;

int main() {
   
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n, m, e;
  cin >> n >> m >> e;
  vector<int> from(e), to(e), color(e);
  vector<map<int, int>> left_id(n);
  vector<map<int, int>> right_id(m);
  int cnt = n + m;
  for (int i = 0; i < e; ++i) {
   
    cin >> from[i] >> to[i] >> color[i];
    --from[i];
    --to[i];
    if (!left_id[from[i]].count(color[i])) {
   
      left_id[from[i]][color[i]] = cnt++;
    }
    if (!right_id[to[i]].count(color[i])) {
   
      right_id[to[i]][color[i]] = cnt++;
    }
  }
  init(cnt + 4, cnt + 2, cnt + 3);
  for (int i = 0; i < e; ++i) {
   
    add(left_id[from[i]][color[i]], right_id[to[i]][color[i]], 1);
  }
  for (int i = 0; i < n; ++i) {
   
    add(cnt + 0, i, cap_inf);
    add(cnt + 2, i, 1);
    for (auto p : left_id[i]) {
   
      add(i, p.second, 1);
    }
  }
  for (int i = 0; i < m; ++i) {
   
    add(i + n, cnt + 1, cap_inf);
    add(i + n, cnt + 3, 1);
    for (auto p : right_id[i]) {
   
      add(p.second, i + n, 1);
    }
  }
  add(cnt + 0, cnt + 3, n);
  add(cnt + 2, cnt + 1, m);
  add(cnt + 1, cnt + 0, cap_inf);
  if (max_flow() != n + m) {
   
    cout << -1 << "\n";
    return 0;
  }
  set<pair<int, int>> st;
  for (int i = 0; i < n; ++i) {
   
    for (auto p : left_id[i]) {
   
      for (auto e : flow::adj[p.second]) {
   
        if (e.to >= n + m && !e.cap) {
   
          st.insert(make_pair(p.second, e.to));
        }
      }
    }
  }
  vector<int> ans;
  for (int i = 0; i < e; ++i) {
   
    if (st.count(make_pair(left_id[from[i]][color[i]], right_id[to[i]][color[i]]))) {
   
      ans.push_back(i);
      st.erase(make_pair(left_id[from[i]][color[i]], right_id[to[i]][color[i]]));
    }
  }
  cout << ans.size() << "\n";
  for (int i = 0; i < (int) ans.size(); ++i) {
   
    if (i) {
   
      cout << " ";
    }
    cout << ans[i] + 1;
  }
  cout << "\n";
  return 0;
}

Pick Your Own Nim

拟阵交。第一个拟阵是要求线性无关,第二个拟阵是每堆最多选一个。

#include <bits/stdc++.h>

using namespace std;

const int LOG = 60;

struct base {
   
  vector<long long> b;

  base() {
   
    b.assign(LOG, 0);
  }

  void clear() {
   
    for (int i = 0; i < LOG; ++i) {
   
      b[i] = 0;
    }
  }

  void append(long long x) {
   
    for (int i = 0; i < LOG; ++i) {
   
      if (x >> i & 1) {
   
        if (b[i]) {
   
          x ^= b[i];
        } else {
   
          b[i] = x;
          return;
        }
      }
    }
  }

  bool check(long long x) {
   
    for (int i = 0; i < LOG; ++i) {
   
      if (x >> i & 1) {
   
        if (b[i]) {
   
          x ^= b[i];
        } else {
   
          return true;
        }
      }
    }
    return false;
  }
};

int main() {
   
#ifdef wxh010910
  freopen("input.txt", "r", stdin);
#endif
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int n;
  cin >> n;
  vector<long long> values;
  vector<int> colors;
  for (int i = 0; i < n; ++i) {
   
    long long x;
    cin >> x;
    values.push_back(x);
    colors.push_back(i);
  }
  int m;
  cin >> m;
  for (int i = 0; i < m; ++i) {
   
    int sz;
    cin >> sz;
    while (sz--) {
   
      long long x;
      cin >> x;
      values.push_back(x);
      colors.push_back(i + n);
    }
  }
  int s = values.size();
  vector<base> without(s);
  base everything;
  set<int> st;
  auto solve = [&]() {
   
    vector<bool> used(n + m);
    everything.clear();
    for (auto x : st) {
   
      used[colors[x]] = true;
      everything.append(values[x]);
      without[x].clear();
      for (auto y : st) {
   
        if (y != x) {
   
          without[x].append(values[y]);
        }
      }
    }
    vector<int> pre(s, -1);
    queue<int> q;
    for (int i = 0; i < s; ++i) {
   
      if <
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值