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 ) < 1 0 − 3 f(i,j)/f(j,i)<10^{-3} f(i,j)/f(j,i)<10−3 ,这个卡片是相对没有代表性的,它不能很好反映概率,应该丢掉。如果所有已经确定卡片都在当前卡片前面出现,则它们都没有代表性,需要用之前最小的 w w w 乘上 1 0 − 7 10^{-7} 10−7 (极大概率出现在他们后面,同时也能区分后面的卡片)。
#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 <