Day 1
examination
直接上三维数点就能过,也可以容斥一下变成二维数点。
#include <bits/stdc++.h>
using namespace std;
template<typename T>
class fenwick {
public:
vector<T> fenw;
int n;
fenwick(int n): n(n) {
fenw.resize(n);
}
void modify(int x, T v) {
while (x < n) {
fenw[x] += v;
x |= x + 1;
}
}
T query(int x) {
T res{
};
while (x >= 0) {
res += fenw[x];
x = (x & (x + 1)) - 1;
}
return res;
}
};
struct event {
int x, y, z, id;
event(int x, int y, int z, int id): x(x), y(y), z(z), id(id) {
}
bool operator < (const event &other) {
return make_tuple(x, y, z, id) < make_tuple(other.x, other.y, other.z, other.id);
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<event> events;
vector<int> disc_x, disc_y, disc_z;
for (int i = 0; i < n; ++i) {
int x, y, z;
cin >> x >> y;
z = x + y;
x = -x;
y = -y;
z = -z;
disc_x.push_back(x);
disc_y.push_back(y);
disc_z.push_back(z);
events.emplace_back(x, y, z, -1);
}
for (int i = 0; i < m; ++i) {
int x, y, z;
cin >> x >> y >> z;
x = -x;
y = -y;
z = -z;
disc_x.push_back(x);
disc_y.push_back(y);
disc_z.push_back(z);
events.emplace_back(x, y, z, i);
}
sort(disc_x.begin(), disc_x.end());
disc_x.erase(unique(disc_x.begin(), disc_x.end()), disc_x.end());
sort(disc_y.begin(), disc_y.end());
disc_y.erase(unique(disc_y.begin(), disc_y.end()), disc_y.end());
sort(disc_z.begin(), disc_z.end());
disc_z.erase(unique(disc_z.begin(), disc_z.end()), disc_z.end());
for (auto &p : events) {
p.x = lower_bound(disc_x.begin(), disc_x.end(), p.x) - disc_x.begin();
p.y = lower_bound(disc_y.begin(), disc_y.end(), p.y) - disc_y.begin();
p.z = lower_bound(disc_z.begin(), disc_z.end(), p.z) - disc_z.begin();
}
sort(events.begin(), events.end());
fenwick<int> fenw(disc_z.size());
vector<int> ans(m);
function<void(vector<event>)> solve = [&](vector<event> events) {
if ((int) events.size() == 1) {
return;
}
int n = events.size();
solve(vector<event>(events.begin(), events.begin() + (n / 2)));
solve(vector<event>(events.begin() + (n / 2), events.end()));
vector<event> new_events;
for (int i = 0; i < (n / 2); ++i) {
if (events[i].id == -1) {
new_events.emplace_back(0, events[i].y, events[i].z, events[i].id);
}
}
for (int i = (n / 2); i < n; ++i) {
if (events[i].id != -1) {
new_events.emplace_back(0, events[i].y, events[i].z, events[i].id);
}
}
sort(new_events.begin(), new_events.end());
for (auto &p : new_events) {
if (p.id == -1) {
fenw.modify(p.z, 1);
} else {
ans[p.id] += fenw.query(p.z);
}
}
for (auto &p : new_events) {
if (p.id == -1) {
fenw.modify(p.z, -1);
}
}
};
solve(events);
for (int i = 0; i < m; ++i) {
cout << ans[i] << "\n";
}
return 0;
}
naan
不难证明每次贪心选右端点增加最少的是对的,但这样无法输出分数。考虑将 v i , j v_{i,j} vi,j 乘上 n n n ,然后只能在每段的整数位置切割(即在第 j j j 段如果分给 i i i 那么分母是 1 v i , j \frac{1}{v_{i,j}} vi,j1 ),可以证明这样也满足条件。
#include <bits/stdc++.h>
using namespace std;
struct frac {
int pos, num, den;
frac(int pos = 0, int num = 0, int den = 1): pos(pos), num(num), den(den) {
}
bool operator < (const frac &other) const {
if (pos != other.pos) {
return pos < other.pos;
} else {
return (long long) num * other.den < (long long) den * other.num;
}
}
};
int main() {
#ifdef wxh010910
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n, m;
cin >> n >> m;
vector<vector<int>> a(n, vector<int>(m + 1));
vector<vector<long long>> sum(n, vector<long long>(m + 1));
vector<int> need(n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cin >> a[i][j];
need[i] += a[i][j];
a[i][j] *= n;
sum[i][j + 1] = sum[i][j] + a[i][j];
}
a[i][m] = 1;
}
vector<bool> used(n);
vector<int> ptr(n);
vector<int> p(n);
frac cur(0, 0, 1);
auto get_pos = [&](int i, frac l) {
return ((long long) l.num * a[i][l.pos] + l.den - 1) / l.den;
};
auto get_sum = [&](int i, frac l, int r) {
return sum[i][r] - sum[i][l.pos] - get_pos(i, l);
};
for (int i = 0; i < n; ++i) {
frac min_right(m + 1, 0, 1);
int min_pos = -1;
for (int j = 0; j < n; ++j) {
if (!used[j]) {
ptr[j] = max(ptr[j], cur.pos);
while (ptr[j] < m && get_sum(j, cur, ptr[j] + 1) <= need[j]) {
++ptr[j];
}
int cut = 0;
if (ptr[j] == cur.pos) {
cut = get_pos(j, cur) + need[j];
} else {
cut = need[j] - get_sum(j, cur, ptr[j]);
}
if (cut == a[j][ptr[j]]) {
++ptr[j];
cut = 0;
}
if (frac(ptr[j], cut, a[j][ptr[j]]) < min_right) {
min_right = frac(ptr[j], cut, a[j][ptr[j]]);
min_pos = j;
}
}
}
used[min_pos] = true;
cur = min_right;
p[i] = min_pos;
if (i != n - 1) {
cout << (long long) min_right.pos * min_right.den + min_right.num << " " << min_right.den << "\n";
}
}
for (int i = 0; i < n; ++i) {
if (i) {
cout << " ";
}
cout << p[i] + 1;
}
cout << "\n";
return 0;
}
meetings
贴一下代码?(做法就随机点分)
#include <bits/stdc++.h>
#include "meetings.h"
using namespace std;
void add(int x, int y) {
if (x > y) {
swap(x, y);
}
Bridge(x, y);
}
void solve(int x, int y, vector<int> all) {
if (all.empty()) {
add(x, y);
return;
}
if ((int) all.size() == 1) {
add(x, *all.begin());
add(y, *all.begin());
return;
}
int z = all[rand() % all.size()];
vector<int> l, r;
for (auto w : all) {
if (w != z) {
if (Query(x, z, w) == w) {
l.push_back(w);
} else {
r.push_back(w);
}
}
}
solve(x, z, l);
solve(y, z, r);
}
void solve(int x, vector<int> all) {
if (all.empty()) {
return;
}
if ((int) all.size() == 1) {
add(x, *all.begin());
return;
}
int y = all[rand() % all.size()];
map<int, vector<int>> f;
for (auto z : all) {
if (z != y) {
int res = Query(x, y, z);
if (res == z) {
f[res];
} else {
f[res].push_back(z);
}
}
}
vector<int> chain;